4 light normalmapping for animated meshes [C++/GLSL]

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
xirtamatrix
Posts: 219
Joined: Fri Feb 19, 2010 4:03 pm
Location: Estonia

Post by xirtamatrix »

hi there,

Great work! Unfortunately I'm using DX but I'm terribly in need of this. Any chance you (or someone else) could write a DX (hlsl) version of this?

Many thanks in advance!
to live, is natural; to die, is not!
wing64
Competition winner
Posts: 242
Joined: Wed Jul 23, 2008 2:35 am
Location: Thailand
Contact:

Post by wing64 »

Try this. :D

vertex program

Code: Select all

float4x4 matWorldInverse; 
float4x4 ModelViewMatrix;
float4x4 ModelViewProjectionMatrix;

float3 fvLightPosition1; 
float3 fvLightPosition2; 
float3 fvLightPosition3; 
float3 fvLightPosition4; 
 
float fLightStrength1; 
float fLightStrength2; 
float fLightStrength3; 
float fLightStrength4; 
 
struct VS_OUTPUT
{
	float4 Position				: POSITION0;
	float2 Texcoord				: TEXCOORD0;
	float3 ViewDirection		: TEXCOORD1; 
	float3 LightDirection1		: TEXCOORD2; 
	float3 LightDirection2		: TEXCOORD3; 
	float3 LightDirection3		: TEXCOORD4; 
	float3 LightDirection4		: TEXCOORD5; 
	float4 LightDistMultiplier  : TEXCOORD6;
};
    
float getLengthSQR (float3 vec) 
{ 
	return(vec.x*vec.x+vec.y*vec.y+vec.z*vec.z); 
}  

struct VS_INPUT
{
	float3 Position         : POSITION0;
	float3 Normal           : NORMAL;
	float2 Texcoord         : TEXCOORD0;
};

VS_OUTPUT vertexMain( in VS_INPUT IN ) 
{    
	VS_OUTPUT OUT = (VS_OUTPUT)0;

	// common output
	OUT.Position = mul(float4(IN.Position,1.0), ModelViewProjectionMatrix);
	OUT.Texcoord = IN.Texcoord;

	float4x4 LightTransform= ModelViewMatrix; 
	LightTransform= mul(matWorldInverse, LightTransform);

	float4 fvObjectPosition = mul(float4(IN.Position,1.0), ModelViewProjectionMatrix);
	float4 fvLightPos1 = mul(float4(fvLightPosition1,1.0), LightTransform); 
	float4 fvLightPos2 = mul(float4(fvLightPosition2,1.0), LightTransform); 
	float4 fvLightPos3 = mul(float4(fvLightPosition3,1.0), LightTransform); 
	float4 fvLightPos4 = mul(float4(fvLightPosition4,1.0), LightTransform); 

	float3 fvViewDirection  =  - fvObjectPosition.xyz; 

	float3 fvLightDirection1 = (fvLightPos1.xyz - fvObjectPosition.xyz); 
	float3 fvLightDirection2 = (fvLightPos2.xyz - fvObjectPosition.xyz); 
	float3 fvLightDirection3 = (fvLightPos3.xyz - fvObjectPosition.xyz); 
	float3 fvLightDirection4 = (fvLightPos4.xyz - fvObjectPosition.xyz); 

	OUT.LightDistMultiplier[0]=1.0/(getLengthSQR (fvLightDirection1)/(fLightStrength1*10000.0)); 
	OUT.LightDistMultiplier[1]=1.0/(getLengthSQR (fvLightDirection2)/(fLightStrength2*10000.0)); 
	OUT.LightDistMultiplier[2]=1.0/(getLengthSQR (fvLightDirection3)/(fLightStrength3*10000.0)); 
	OUT.LightDistMultiplier[3]=1.0/(getLengthSQR (fvLightDirection4)/(fLightStrength4*10000.0)); 

	float3 fvTangent	= -float3(abs(IN.Normal.y) + abs(IN.Normal.z), abs(IN.Normal.x), 0); 
	float3 fvBinormal	= cross(fvTangent,IN.Normal);
	float3 fvNormal     = mul(IN.Normal, ModelViewMatrix); 

	fvTangent			= mul( cross(fvBinormal, IN.Normal), ModelViewMatrix ); 
	fvBinormal			= mul( fvBinormal, ModelViewMatrix ); 

	OUT.ViewDirection.x  = dot( fvTangent, fvViewDirection ); 
	OUT.ViewDirection.y  = dot( fvBinormal, fvViewDirection ); 
	OUT.ViewDirection.z  = dot( fvNormal, fvViewDirection ); 

	OUT.LightDirection1.x  = dot( fvTangent, fvLightDirection1.xyz ); 
	OUT.LightDirection1.y  = dot( fvBinormal, fvLightDirection1.xyz ); 
	OUT.LightDirection1.z  = dot( fvNormal, fvLightDirection1.xyz ); 

	OUT.LightDirection2.x  = dot( fvTangent, fvLightDirection2.xyz ); 
	OUT.LightDirection2.y  = dot( fvBinormal, fvLightDirection2.xyz ); 
	OUT.LightDirection2.z  = dot( fvNormal, fvLightDirection2.xyz ); 

	OUT.LightDirection3.x  = dot( fvTangent, fvLightDirection3.xyz ); 
	OUT.LightDirection3.y  = dot( fvBinormal, fvLightDirection3.xyz ); 
	OUT.LightDirection3.z  = dot( fvNormal, fvLightDirection3.xyz ); 

	OUT.LightDirection4.x  = dot( fvTangent, fvLightDirection4.xyz ); 
	OUT.LightDirection4.y  = dot( fvBinormal, fvLightDirection4.xyz ); 
	OUT.LightDirection4.z  = dot( fvNormal, fvLightDirection4.xyz ); 

	return OUT;
}
pixel program

Code: Select all

float4 fvAmbient;
float4 fvLight1Color; 
float4 fvLight2Color; 
float4 fvLight3Color; 
float4 fvLight4Color; 

float fSpecularPower; 
float fSpecularStrength; 
float fBumpStrength; 

sampler2D baseMap		: register(s0); 
sampler2D bumpMap		: register(s1); 

struct PS_INPUT
{	
	float2 Texcoord				: TEXCOORD0;
	float3 ViewDirection		: TEXCOORD1; 
	float3 LightDirection1		: TEXCOORD2; 
	float3 LightDirection2		: TEXCOORD3;
	float3 LightDirection3		: TEXCOORD4; 
	float3 LightDirection4		: TEXCOORD5; 
	float4 LightDistMultiplier  : TEXCOORD6;

};

float4 pixelMain( in PS_INPUT IN ) : COLOR
{
	float4 color = float4(0,0,0,0);

	float3  fvLightDirection1 = normalize( IN.LightDirection1 ); 
	float3  fvLightDirection2 = normalize( IN.LightDirection2 ); 
	float3  fvLightDirection3 = normalize( IN.LightDirection3 ); 
	float3  fvLightDirection4 = normalize( IN.LightDirection4 ); 

	float3  fvNormal         = tex2D( bumpMap, IN.Texcoord ).yxz; 
	fvNormal.xy*=2.0; 
	fvNormal.xy-=1.0; 

	fvNormal=(float3(0.0,0.0,1.0)-fvNormal)*fBumpStrength+fvNormal; 

	fvNormal=normalize(fvNormal); 

	float fNDotL1           = max(dot(fvNormal, fvLightDirection1),0.0)-0.1;  
	float fNDotL2           = max(dot(fvNormal, fvLightDirection2),0.0)-0.1;  
	float fNDotL3           = max(dot(fvNormal, fvLightDirection3),0.0)-0.1;  
	float fNDotL4           = max(dot(fvNormal, fvLightDirection4),0.0)-0.1;  

	float3  fvReflection1     = normalize( ( ( 2.0 * fvNormal )  ) - fvLightDirection1 );  
	float3  fvReflection2     = normalize( ( ( 2.0 * fvNormal )  ) - fvLightDirection2 );  
	float3  fvReflection3     = normalize( ( ( 2.0 * fvNormal )  ) - fvLightDirection3 );  
	float3  fvReflection4     = normalize( ( ( 2.0 * fvNormal )  ) - fvLightDirection4 );  

	float3  fvViewDirection  = normalize( IN.ViewDirection ); 

	float fRDotV1          = max( 0.0, dot( fvReflection1, fvViewDirection ) ); 
	float fRDotV2          = max( 0.0, dot( fvReflection2, fvViewDirection ) ); 
	float fRDotV3          = max( 0.0, dot( fvReflection3, fvViewDirection ) ); 
	float fRDotV4          = max( 0.0, dot( fvReflection4, fvViewDirection ) ); 

	float4  fvBaseColor      = tex2D( baseMap, IN.Texcoord ); 

	float4  fvTotalAmbient   = fvAmbient * fvBaseColor;  

	float4  fvTotalDiffuse   = fvLight1Color * fNDotL1* fvBaseColor*IN.LightDistMultiplier[0];  
	float4  fvTotalSpecular  = fNDotL1*fvLight1Color * ( pow( fRDotV1, fSpecularPower ) )*IN.LightDistMultiplier[0]; 

	fvTotalDiffuse   += fvLight2Color * fNDotL2* fvBaseColor*IN.LightDistMultiplier[1];  
	fvTotalSpecular  += fNDotL2*fvLight2Color * ( pow( fRDotV2, fSpecularPower ) )*IN.LightDistMultiplier[1];   

	fvTotalDiffuse   += fvLight3Color * fNDotL3* fvBaseColor*IN.LightDistMultiplier[2];  
	fvTotalSpecular  += fNDotL3*fvLight3Color * ( pow( fRDotV3, fSpecularPower ) )*IN.LightDistMultiplier[2];   

	fvTotalDiffuse   += fvLight4Color * fNDotL4* fvBaseColor*IN.LightDistMultiplier[3];  
	fvTotalSpecular  += fNDotL4*fvLight4Color * ( pow( fRDotV4, fSpecularPower ) )*IN.LightDistMultiplier[3];   

	color=( fvTotalAmbient + fvTotalDiffuse+ (fvTotalSpecular*fSpecularStrength)); 
	if(color.r>1.0){color.gb+=color.r-1.0;} 
	if(color.g>1.0){color.rb+=color.g-1.0;} 
	if(color.b>1.0){color.rg+=color.b-1.0;} 

	return color;
} 
kaliber
Posts: 117
Joined: Sat Jan 17, 2009 12:51 pm

Post by kaliber »

hello, please help me with the directx version callback

here is my code :

Code: Select all

virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
  {
	//int var0=0;
 //   services->setPixelShaderConstant("baseMap", (float*)(&var0), 1); //the colormap
 //   int var1=1;
 //   services->setPixelShaderConstant("bumpMap", (float*)(&var1), 1); //the normalmap
   
    core::matrix4 invWorld = services->getVideoDriver()->getTransform(video::ETS_WORLD);
    invWorld.makeInverse();
    services->setVertexShaderConstant("matWorldInverse", (float*)(&invWorld), 16);

	core::matrix4 ModelViewMatrix = services->getVideoDriver()->getTransform(video::ETS_VIEW);
    ModelViewMatrix.makeInverse();
    services->setVertexShaderConstant("ModelViewMatrix", (float*)(&ModelViewMatrix), 16);

	core::matrix4 worldViewProj;
	worldViewProj = services->getVideoDriver()->getTransform(video::ETS_PROJECTION);
	worldViewProj *= services->getVideoDriver()->getTransform(video::ETS_VIEW);
	worldViewProj *= services->getVideoDriver()->getTransform(video::ETS_WORLD);
	
    services->setVertexShaderConstant("ModelViewProjectionMatrix", (float*)(&worldViewProj), 16);
   
    services->setVertexShaderConstant("fLightStrength1", (float*)(&fLightStrength[0]), 1);
    services->setVertexShaderConstant("fLightStrength2", (float*)(&fLightStrength[1]), 1);
    services->setVertexShaderConstant("fLightStrength3", (float*)(&fLightStrength[2]), 1);
    services->setVertexShaderConstant("fLightStrength4", (float*)(&fLightStrength[3]), 1);
   
    services->setVertexShaderConstant("fvLightPosition1", (float*)(&fvLightPosition[0]), 3);
    services->setVertexShaderConstant("fvLightPosition2", (float*)(&fvLightPosition[1]), 3);
    services->setVertexShaderConstant("fvLightPosition3", (float*)(&fvLightPosition[2]), 3);
    services->setVertexShaderConstant("fvLightPosition4", (float*)(&fvLightPosition[3]), 3);
   
    services->setPixelShaderConstant("fvAmbient", (float*)(&fvAmbient), 4);
    services->setPixelShaderConstant("fvLight1Color", (float*)(&fvLightColor[0]), 4);
    services->setPixelShaderConstant("fvLight2Color", (float*)(&fvLightColor[1]), 4);
    services->setPixelShaderConstant("fvLight3Color", (float*)(&fvLightColor[2]), 4);
    services->setPixelShaderConstant("fvLight4Color", (float*)(&fvLightColor[3]), 4);

    services->setPixelShaderConstant("fSpecularPower", (float*)(&fSpecularPower), 1);
    services->setPixelShaderConstant("fSpecularStrength", (float*)(&fSpecularStrength), 1);
    services->setPixelShaderConstant("fBumpStrength", (float*)(&fBumpStrength), 1);
		
   }

}; 
i dont know how to set the "ModelViewMatrix" and the "ModelViewProjectionMatrix" variable.
wing64
Competition winner
Posts: 242
Joined: Wed Jul 23, 2008 2:35 am
Location: Thailand
Contact:

Post by wing64 »

Code: Select all

		matrix4 ModelViewProjectionMatrix;
		ModelViewProjectionMatrix = driver->getTransform(ETS_PROJECTION);
		ModelViewProjectionMatrix *= driver->getTransform(ETS_VIEW);
		ModelViewProjectionMatrix *= driver->getTransform(ETS_WORLD);
		services->setVertexShaderConstant("ModelViewProjectionMatrix", ModelViewProjectionMatrix.pointer(), 16);

		matrix4 ModelViewMatrix;
		ModelViewMatrix = driver->getTransform(ETS_VIEW);
		ModelViewMatrix *= driver->getTransform(ETS_WORLD);
		services->setVertexShaderConstant("ModelViewMatrix", ModelViewMatrix.pointer(), 16);
kaliber
Posts: 117
Joined: Sat Jan 17, 2009 12:51 pm

Post by kaliber »

yay yay thx a lot :D :lol:
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Post by Mel »

The shader in the first page should be marked as "deprecated"

The tangents and binormals are currently passed to the shaders, even in the animated meshes, and they are correctly calculated inside the engine.

They are passed in TEXCOORD1 (the tangent) and TEXCOORD2 (the binormal), instead of the expected semantics TANGENT0 and BINORMAL0, and they are also passed to animated meshes (though their processing isn't correct ATM, the tangents and binormals should be animated too, and they aren't)

IN HLSL, in the vertex definition the tangents and binormals are there:

Code: Select all

...
float3 tangent   :TEXCOORD1;
float3 binormal :TEXCOORD2;
...
So, this 4 lights shader would look like this in the vertex shader:

Code: Select all

float4x4 matWorldInverse;
float4x4 ModelViewMatrix;
float4x4 ModelViewProjectionMatrix;

float3 fvLightPosition1;
float3 fvLightPosition2;
float3 fvLightPosition3;
float3 fvLightPosition4;
 
float fLightStrength1;
float fLightStrength2;
float fLightStrength3;
float fLightStrength4;
 
struct VS_OUTPUT
{
   float4 Position            : POSITION0;
   float2 Texcoord            : TEXCOORD0;
   float3 ViewDirection      : TEXCOORD1;
   float3 LightDirection1      : TEXCOORD2;
   float3 LightDirection2      : TEXCOORD3;
   float3 LightDirection3      : TEXCOORD4;
   float3 LightDirection4      : TEXCOORD5;
   float4 LightDistMultiplier  : TEXCOORD6;
};
   
float getLengthSQR (float3 vec)
{
   return(vec.x*vec.x+vec.y*vec.y+vec.z*vec.z);
} 

struct VS_INPUT
{
   float3 Position         : POSITION0;
   float3 Normal           : NORMAL;
   float2 Texcoord         : TEXCOORD0;
   float3 Tangent          :TEXCOORD1;
   float3 Binormal         :TEXCOORD2;
};

VS_OUTPUT vertexMain( in VS_INPUT IN )
{   
   VS_OUTPUT OUT = (VS_OUTPUT)0;

   // common output
   OUT.Position = mul(float4(IN.Position,1.0), ModelViewProjectionMatrix);
   OUT.Texcoord = IN.Texcoord;

   float4x4 LightTransform= ModelViewMatrix;
   LightTransform= mul(matWorldInverse, LightTransform);

   float4 fvObjectPosition = mul(float4(IN.Position,1.0), ModelViewProjectionMatrix);
   float4 fvLightPos1 = mul(float4(fvLightPosition1,1.0), LightTransform);
   float4 fvLightPos2 = mul(float4(fvLightPosition2,1.0), LightTransform);
   float4 fvLightPos3 = mul(float4(fvLightPosition3,1.0), LightTransform);
   float4 fvLightPos4 = mul(float4(fvLightPosition4,1.0), LightTransform);

   float3 fvViewDirection  =  - fvObjectPosition.xyz;

   float3 fvLightDirection1 = (fvLightPos1.xyz - fvObjectPosition.xyz);
   float3 fvLightDirection2 = (fvLightPos2.xyz - fvObjectPosition.xyz);
   float3 fvLightDirection3 = (fvLightPos3.xyz - fvObjectPosition.xyz);
   float3 fvLightDirection4 = (fvLightPos4.xyz - fvObjectPosition.xyz);

   OUT.LightDistMultiplier[0]=1.0/(getLengthSQR (fvLightDirection1)/(fLightStrength1*10000.0));
   OUT.LightDistMultiplier[1]=1.0/(getLengthSQR (fvLightDirection2)/(fLightStrength2*10000.0));
   OUT.LightDistMultiplier[2]=1.0/(getLengthSQR (fvLightDirection3)/(fLightStrength3*10000.0));
   OUT.LightDistMultiplier[3]=1.0/(getLengthSQR (fvLightDirection4)/(fLightStrength4*10000.0));

   float3 fvTangent   = mul(IN.tangent,ModelViewMatrix);
   float3 fvBinormal   = mul(IN.binormal,ModelViewMatrix);
   float3 fvNormal     = mul(IN.Normal, ModelViewMatrix);

   OUT.ViewDirection.x  = dot( fvTangent, fvViewDirection );
   OUT.ViewDirection.y  = dot( fvBinormal, fvViewDirection );
   OUT.ViewDirection.z  = dot( fvNormal, fvViewDirection );

   OUT.LightDirection1.x  = dot( fvTangent, fvLightDirection1.xyz );
   OUT.LightDirection1.y  = dot( fvBinormal, fvLightDirection1.xyz );
   OUT.LightDirection1.z  = dot( fvNormal, fvLightDirection1.xyz );

   OUT.LightDirection2.x  = dot( fvTangent, fvLightDirection2.xyz );
   OUT.LightDirection2.y  = dot( fvBinormal, fvLightDirection2.xyz );
   OUT.LightDirection2.z  = dot( fvNormal, fvLightDirection2.xyz );

   OUT.LightDirection3.x  = dot( fvTangent, fvLightDirection3.xyz );
   OUT.LightDirection3.y  = dot( fvBinormal, fvLightDirection3.xyz );
   OUT.LightDirection3.z  = dot( fvNormal, fvLightDirection3.xyz );

   OUT.LightDirection4.x  = dot( fvTangent, fvLightDirection4.xyz );
   OUT.LightDirection4.y  = dot( fvBinormal, fvLightDirection4.xyz );
   OUT.LightDirection4.z  = dot( fvNormal, fvLightDirection4.xyz );

   return OUT;
}
And the pixel shader remains the same.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

Cool stuff. Does it look much different from the current shader when two lights are used? If not, we should probably use this in the engine by default if the user supports HLSL/GLSL.
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

Since you have:

Code: Select all

struct VS_INPUT
{
   (...)
   float3 Tangent          :TEXCOORD1;
   float3 Binormal         :TEXCOORD2;
};

Code: Select all

float3 fvTangent   = mul(IN.tangent,ModelViewMatrix);
float3 fvBinormal   = mul(IN.binormal,ModelViewMatrix); 
should be:

Code: Select all

float3 fvTangent   = mul(IN.Tangent,ModelViewMatrix);
float3 fvBinormal   = mul(IN.Binormal,ModelViewMatrix); 
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Post by Mel »

You know what i mean, right? ;)
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

Sure. Just wanted to tell you to fix it if you wish, `cause some peeps are used to copy/paste without reading a thing, then they`d post here the errors they get etc. :D
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Post by Mel »

Then some people should be ready also to correct minor errors due to fast coding :lol: But yeah, you are right.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
Luben
Posts: 568
Joined: Sun Oct 09, 2005 10:12 am
Location: #irrlicht @freenode

Post by Luben »

Why do people still say binormal? It really ought to be bitangent, right?
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Post by Mel »

Either name is correct :) at any case, it is a complementary vector to the tangent and the normal vectors to create the tangent space, so, it really doesn't matter how you name it. In spanish, for instance, the name is binormal, not bitangent.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
Luben
Posts: 568
Joined: Sun Oct 09, 2005 10:12 am
Location: #irrlicht @freenode

Post by Luben »

Is it really correct? Consider a plane; It consists of one normal and two tangents. Two normals for a plane just doesn't make any sense.
If we were to consider a line instead, there's one tangent and two normals. The name binormal makes sense then, but a bitangent would make no sense at all.
(I suppose there might be more normals for a surface in higher dimensions, don't know anything about that)
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Post by Mel »

According to wikipedia, this is a "bitangent"

http://en.wikipedia.org/wiki/Bitangent

But then, you find things like this:

http://mathworld.wolfram.com/BitangentVector.html

So i am really confused now... :lol:
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
Post Reply