Dot3 Shader

Started by
11 comments, last by noaktree 19 years ago
I usually can't think of any good forum topics to start, so you can imagine how delighted I am to be posting this now. I have been using this shader for objects that are at (0,0,0). The objects are usually just rotated with an arcball and all works fine. Today I translated the object -50 along X and well... just have a look: Here is the FX file that I am using:
// DELighting structs 
// ************************************************************
struct DELight_s
{
	int	Type;	
	bool	Active;	
	bool	LightingActive;	
	float4	Position;	
	float4	Diffuse;
	float4	Specular;	
	float4	Direction;	
	float	Attenuation;	
	float	Range;	
	float	Theta;	
	float	Phi;
	float	Falloff;
};

struct DEAmbient_s
{
	bool 	Active;	
	float4 	Color;
};

// Variables
// ************************************************************
DELight_s		DE1NALight 		: DENALIGHT1;
DEAmbient_s		DEAmbient 		: DEAMBIENTLIGHT;	
float4x4		DEWorld			: DEWORLD;
float4x4		DEWorldViewProj	 	: DEWORLDVIEWPERSPECTIVE;
float4x4 		DEViewInverse 		: DEVIEW_INVERSE;

texture NormalTexture : DETEXTURE 
<
	string name="Dwarf_Normal.tga";
>;

texture ColorTexture : DEBASIC_MATERIAL_TEXTURE; 

// The sample state for the basic texture
sampler2D NormalMap = sampler_state
{
	Texture 		= (NormalTexture);
	MinFilter 		= Linear;	
	MagFilter		= Linear;	
	AddressU		= Wrap;	
	AddressV		= Wrap;
};

// The sample state for the basic texture
sampler2D ColorMap = sampler_state
{
	Texture 		= (ColorTexture);
	MinFilter 		= Linear;	
	MagFilter		= Linear;
	AddressU		= Wrap;	
	AddressV		= Wrap;
};

// Shader I/O structs 
// ************************************************************
struct sVSIN
{	
	float4 Position 	: POSITION;    
	float4 Normal   	: NORMAL;
	float2 UV		: TEXCOORD0;    
	float4 Tangent  	: TANGENT;   
};



struct sPSIN
{				
	float4 Position 	: POSITION;
	float4 Normal		: COLOR0;
	float4 LightVector	: TEXCOORD0;
	float2 TexCoord0	: TEXCOORD1;
	float2 TexCoord1	: TEXCOORD2; 
};

// Vertex Shader 
// ************************************************************
sPSIN VertexShader(sVSIN VIN)
{	
	// Create struct to send to pixel shader   
	sPSIN OUT = (sPSIN)0;
	
	// Get the Eye Position
	float3 World_Eye_Position = DEViewInverse[3].xyz;

	// Calculate the transformed world vertex position
	float3 World_Vertex_Position = mul(VIN.Position, DEWorld).xyz;

	// Calculate light direction from the Nearest Active Light
	float3 Light_Direction = World_Vertex_Position - DE1NALight.Position;
			
	// Tangent
	float3 T = mul(VIN.Tangent, DEWorld);		
	// Normal vector
	float4 N = mul(VIN.Normal, DEWorld);
	// Eye vector
	float3 E = normalize(World_Eye_Position - World_Vertex_Position); 
	// Light vector
	float3 L = normalize(-Light_Direction.xyz);				
	// Compute the tangent rotation matrix
	float3 B = cross(T, N);	

	// Compute the 3x3 tranform from tangent space to object space
   	float3x3 Object_To_Tangent_Space;
   	Object_To_Tangent_Space[0] = T;
   	Object_To_Tangent_Space[1] = B;
	Object_To_Tangent_Space[2] = N;

	// Transform normal from object space to tangent space
	OUT.Normal.xyz = 0.5 * 
		mul(Object_To_Tangent_Space, N) + 0.5.xxx;

	// Transform light vector from object space to tangent space
	OUT.LightVector.xyz = 0.5 * 
		mul(Object_To_Tangent_Space, L.xyz) + 0.5.xxx;

	// Pass the calculated vertex position	
	OUT.Position = mul(VIN.Position, DEWorldViewProj);

	// Pass texture coordinates
	OUT.TexCoord0 = VIN.UV;
	OUT.TexCoord1 = VIN.UV;
	
	return OUT;
}

// Pixel Shader 
// ************************************************************
float4 PixelShader(sPSIN PIN) : COLOR

{
	// Get the bump normal
	float4 Bump_Normal = 2 * (tex2D(NormalMap, PIN.TexCoord0) - 0.5);

	// Get the color map color 
	float4 Texture_Color = tex2D(ColorMap, PIN.TexCoord1);

	// Expand iterated normal to [-1,1]
	float4 Normal = 2 * (PIN.Normal - 0.5);

	// Expand iterated light vector to [-1,1]
	float4 Light_Vector = 2 * (PIN.LightVector - 0.5);
	
	// Compute self-shadowing term
   	float Shadow = saturate(4 * dot(Normal.xyz, Light_Vector.xyz));
		
	// Calculate Annenuation
	float Attenuation = 1/DE1NALight.Attenuation;

	// Computer diffuse term
	float4 Diffuse_Term = Attenuation * 
		saturate(dot(Bump_Normal.xyz, Light_Vector.xyz)-0.2);   	
		
	return Texture_Color * (Diffuse_Term * Shadow  + DEAmbient.Color);
}

// Technique
// ************************************************************
technique DETechnique
<float vs=1.1; float ps=2.0;>
{   
	pass Pass0    
	{				
		VertexShader 	= compile vs_1_1 VertexShader();		
		PixelShader  	= compile ps_2_0 PixelShader();   
	}  	
}




I messed around with it a bit and was unable to correct the problem. I'm almost certain that all of the data coming into the shader is good. So I guess this is where you guys tell me what I did wrong. [smile] ...Please! [Edited by - noaktree on March 30, 2005 4:11:56 PM]
game development is liek a state of mind man.. it's liek when you liek... think... and then you liek make it fun++

- Yes I'm drunk.
Advertisement
From a quick glance over the code (it's late here & I'm tired), I'd say the following is where the problem lies:

// Tangentfloat3 T = mul(VIN.Tangent, DEWorld);		// Normal vectorfloat4 N = mul(VIN.Normal, DEWorld);


DEWorld is a full 4x4 matrix; i.e. one which includes translation.


So your tangent space basis vectors (T and N) are also being translated when you translate your object...

...for tangent space, the light vector should only be rotated (because it's just a direction vector rather than a position). It shouldn't be translated.

Multiplying the tangent and normal by the top left 3x3 of the matrix (rather than the full 4x4) should do the trick.

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

That makes sense. Thanks for taking the time! [smile]
I'll have to try it out a little later...it's dinner time.
game development is liek a state of mind man.. it's liek when you liek... think... and then you liek make it fun++

- Yes I'm drunk.
Quote:Original post by S1CA
...for tangent space, the light vector should only be rotated (because it's just a direction vector rather than a position). It shouldn't be translated.


Ah, tiredness strikes... I'll just correct my maths: the matrix that will result from translating the basis vectors (N, T, B) will shear and/or scale (as well as rotate) the light vector rather than translate it.

A shear/scale of L is as bad as a translation though: L dot N = cos theta*|L|*|N|, if L or N aren't unit, your lighting goes overly dark or light depending on the magnitude of the vectors. Additionally, negative translation of the basis vectors (e.g. -50,0,0) will also cause the light vector (and basis vectors) to point the wrong way. Generally "wrong" looking [wink]

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

Your solution was successful. Thanks.

I will send the rotation data as a 3x3 matrix parameter to speed things along.
I've never sent a 3x3 but according to the docs:

"If the destination matrix is smaller than the source matrix, the additional components of the source matrix will be ignored."

So it should be fairly straight forward.

Thanks again,
Neil
game development is liek a state of mind man.. it's liek when you liek... think... and then you liek make it fun++

- Yes I'm drunk.
As a small side question, looking at your code you use structures to group stuff. Does this help the compiler produce better code, ie less constants/regs used? Also when you set the values in your code do you just set one param with a block of memory the size of the structure or do you need to set each member?

Just planning my first attempts at shaders and wondered what the best approach is.

Thanks
Just a question do you reckon you could post your updated HLSL code as i'm having the exact same problem as you in my normal mapping shader and a little bit of code may save me hours of frustration.

Thanks in advance
Quote:As a small side question, looking at your code you use structures to group stuff. Does this help the compiler produce better code, ie less constants/regs used? Also when you set the values in your code do you just set one param with a block of memory the size of the structure or do you need to set each member?
I'm not sure if sending a struct improves performance in any way. I am sending the whole thing with one call (SetValue()).

Quote:Just a question do you reckon you could post your updated HLSL code as i'm having the exact same problem as you in my normal mapping shader and a little bit of code may save me hours of frustration.
The only changes that I've made to the existing code are in these two calls where

// Tangent
float3 T = mul(VIN.Tangent, DEWorld_Rotation33);
// Normal
float3 N = mul(VIN.Normal, DEWorld_Rotation33);

where DEWorld_Rotation33 is a 3x3 matrix containing the world rotation data. As Simon said it's just the world 4x4 matrix without translation and scaling. Hope this helps.
game development is liek a state of mind man.. it's liek when you liek... think... and then you liek make it fun++

- Yes I'm drunk.
Thanks for the quick reply, So basically your just supplying the rotation section of the matrix to your shaders. so if below is a standard 4x4 Matrix

r00 r01 r02 t0
r10 r11 r12 t1
r20 r21 r22 t2
0 0 0 1

you would chop off the t0 (translation) and 0 rows and columns to leave

r00 r01 r02
r10 r11 r12
r20 r21 r22

just making sure i'm understanding correctly :)

Thanks
Quote:Thanks for the quick reply, So basically your just supplying the rotation section of the matrix to your shaders.
Not to my "shaders" exactly - It's one of many that I'm passing as parameters. I'm using that matrix to calculate the tangents and normals so I can use them to create my tangent rotation matrix. I pass a full version of the world matrix also as well as others to calculate other parts.

[Edited by - noaktree on March 30, 2005 11:03:00 PM]
game development is liek a state of mind man.. it's liek when you liek... think... and then you liek make it fun++

- Yes I'm drunk.

This topic is closed to new replies.

Advertisement