• Advertisement
Sign in to follow this  

Odd problem with my lighting shader

This topic is 3878 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi! I've been working on getting my old Lighting shader I made in Render Monkey to work in my DirectX application, and after some hours of error seeking and coding I finaly got it to work. I am calculating ambient, diffuse and specular components (ambient and diffuse in the vertex shader and specular per-pixel in the pixel shader). First I got it to work, but when I rotated the objects, it was as if the light rotated around them... I later figured that I was calculating the lightning on the objects in Object Space, forgot to transform them to world space where the light is, so I translated the position and normals of the objects to world space and now the light is positioned where it should on the objects... but, to the problem. I thought it work for sometime, but later I noticed that there is always one of the models I render that is getting totally broken =( . It looks like when you put the matrix and the vertex position in the wrong order in the matrix multiplication, something I've done plenty of times since in Render monkey it's the other way around. But since the shader works fine, visualy for all objects except one, I feel completely lost to what it can be. And the creation of these objects are all done the same way. I use the D3DXCreateTeapot(), Box, Cylinder, Torus and Sphere. For some reason it is the cylinder, the sphere and the teapot that gets wronly rendered. When I just draw 3 torus'es and a box it works as it should. But as soon as I add these others, one of them gets wrong. But at the same time, but sometimes they work, but it's always one that doesn. E.g. if I draw 3 toruses, a cylinder, sphere, box and a teapot in that order, the cylinder gets broken. But everything else looks correct and nice. If I comment the cylinder creation away, then the sphere gets broken instead. I've starred at the shader for a long time and tried changing things back and I can't get it to work. I am not sure if the problem is in the shader anymore, but since I used different shaders before on the same objects and I experienced no such "broken" models then, I presumed it was in the shader. I'm still quite wet behind the ears when it comes to Direct3D and HLSL, so I am not sure. I think that either the problem is in the shader or in my converting from the FVF to my own vertex declaration. Anyone that has a clue of what kind of errors can cause problems like the one I described? Here's the code where I clone the default meshes to my own format:
void c_3DModel::ChangeToCustomVertexDeclaration(IDirect3DDevice9 *p_Device)
{	
	D3DVERTEXELEMENT9 Elements[] = 
	{
		{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
		{0, sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
		{0, 2 * sizeof(D3DXVECTOR3), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
		D3DDECL_END()
	};

	// Clones the DX generated model and sets our custom vertex declaration to it.
	p_Model->CloneMesh(p_Model->GetOptions(), Elements, p_Device, &p_Model);
	
}
and here is the Lighting shader:
// Texture.
uniform extern texture TextureSurface;

// The matrices needed.
extern float4x4 matViewProjection;
extern float4x4 matView;
extern float4x4 matViewInverse;
extern float4x4 matWorld;

// Ambient Light variable.
extern float4 AmbientLight;

// The models position.
extern float4 CameraPos;

// Diffuse Light1 variables.
extern float4 Light1Position;
extern float4 Light1Attenuation;
extern float4 Light1Color;

// Sampling the texture.
sampler TextureSampler = sampler_state
{
	Texture = <TextureSurface>;
	// Filters.
	MinFilter = LINEAR;//Anisotropic;
	MagFilter = LINEAR;//Anisotropic;	
};

struct VS_Output
{
   float4 Position: POSITION0;
   float2 TextureCoordinates: TEXCOORD0;
   float4 Color: COLOR0;
   float4 Pos: TEXCOORD1; // NOTE: Is of type texcoord because the pixel shader can't handle positons.
   float3 Normal: TEXCOORD2; // Same but with normals.
};

struct VS_Input
{
   float4 Position: POSITION0;
   float3 Normal: NORMAL0;
   float2 TextureCoordinates: TEXCOORD0;   
};

// *** FUNCTION PROTOTYPES ***

// Diffuse lightning function.
float4 LightPointDiffuse( float3 VertexPosition,
                          float3 VertexNormal,
                          float3 LightSourcePosition,
                          float4 LightColor,
                          float4 LightAttenuation  );
                          
float4 LightPointSpecular( float3 VertexPosition,
                           float3 VertexNormal,
                           float3 LightSourcePosition,
                           float4 LightColor,
                           float4 LightAttenuation,
                           float4 EyeDirection );
                          
//////////////////////////////////////////////////////////////////
// VERTEX SHADER
//////////////////////////////////////////////////////////////////


VS_Output vs_main(VS_Input Input)
{
   VS_Output Output;
   
   Output.Position = mul(Input.Position, matWorld);
   Output.Normal = mul(float4(Input.Normal, 0.0f), matWorld);
   
   // Calculate the eye vector from the camera to the vertex.
   //float4 EyeVector = mul(CameraPos, matViewInverse); 
   //EyeVector = -normalize(EyeVector + Output.Position);
   
   // Calls the function that calculates the final colors for the diffuse lightning component. Gouraud-shading.
   // NOTE: If this function is called and done per-pixel in the pixel shader instead it is called Phong-shading.
   float4 Diffuse = LightPointDiffuse(  Output.Position,
                                        Output.Normal,
                                        Light1Position,
                                        Light1Color,
                                        Light1Attenuation);
      
    //Calculating specular lightning per vertex.
   //float4 Specular = LightPointSpecular( Output.Position,
   //                                     Output.Normal,
   //                                     Light1Position,
   //                                     Light1Color,
   //                                     Light1Attenuation,
   //                                     EyeVector ); 
   
   // Calculates the final color. NOTE: the vector (1.0, 1.0, 1.0, 1.0) is used since no texture is used.                                      
   float4 FinalColor = (1.0, 1.0, 1.0, 1.0)*(AmbientLight+Diffuse);//+Specular;
   
   Output.Color = FinalColor;
   Output.TextureCoordinates = Input.TextureCoordinates;   
   Output.Pos = Output.Position;      
   Output.Position = mul(Output.Position, matViewProjection);
     
   return (Output);
}

///////////////////////////////////////////////////////////////////////////

float4 LightPointDiffuse( float3 VertexPosition,
                          float3 VertexNormal,
                          float3 LightSourcePosition,
                          float4 LightColor,
                          float4 LightAttenuation  )
{
   // Calculates the direction vector. NOTE: Waits to normalize it since we need the vectors length first.
   float3 LightDirectionVector = LightSourcePosition - VertexPosition;   
   float DistanceToLight = length(LightDirectionVector);
   
   // Finishes the Directional vector calculation here.
   LightDirectionVector = normalize(LightDirectionVector);
   
   // Calculates the distance attenuation using given formula.
   float DistanceAttenuation = 1/(LightAttenuation.x
                                  + LightAttenuation.y * DistanceToLight
                                  + LightAttenuation.z * pow(DistanceToLight, 2));
                                  
   // Makes sure the value stays between 0 and 1.
   DistanceAttenuation = clamp(0, 1, DistanceAttenuation);
   
   // Calculates the angle attentuation between the vertex and the light vector.
   float AngleAttenuation = clamp(0, 1, dot(VertexNormal, LightDirectionVector));
   
   // Finalizes the Light calculation.
   return (LightColor * AngleAttenuation * DistanceAttenuation);
}


float4 LightPointSpecular( float3 VertexPosition,
                           float3 VertexNormal,
                           float3 LightSourcePosition,
                           float4 LightColor,
                           float4 LightAttenuation,
                           float4 EyeDirection)
{
   // Calculates the direction vector. NOTE: Waits to normalize it since we need the vectors length first.
   float3 LightDirectionVector = LightSourcePosition - VertexPosition;   
   float DistanceToLight = length(LightDirectionVector);
   
   // Finishes the Directional vector calculation here.
   LightDirectionVector = normalize(LightDirectionVector);
   
   // Calculates the Half Vector.
   float3 HalfVector = normalize(LightDirectionVector - EyeDirection);
   
   // Calculates the distance attenuation using given formula.
   float DistanceAttenuation = 1/(LightAttenuation.x
                                  + LightAttenuation.y * DistanceToLight
                                  + LightAttenuation.z * pow(DistanceToLight, 2));
   
   // Makes sure the value stays between 0 and 1.
   DistanceAttenuation = clamp(0, 1, DistanceAttenuation);   
   
   // Calculates the specular attenuation.                               
   float SpecularAttenuation = pow(clamp(0, 1, dot(VertexNormal, HalfVector)), 32);
                                  
   return (LightColor * DistanceAttenuation * SpecularAttenuation);
}

/////////////////////////////////////////////////////////////////////////////////
// PIXEL SHADER
/////////////////////////////////////////////////////////////////////////////////

struct PS_Input
{
   float2 TextureCoordinates : TEXCOORD0;
   float4 Color : COLOR0;
   float4 Pos: TEXCOORD1; // Is of the type TEXCOORD1 because Pixel shaders can't take positions in the Input.
   float3 Normal: TEXCOORD2; // Same but with normals.
};

float4 ps_main(PS_Input Input) : COLOR0
{
   // Calculate the eye vector from the camera to the vertex.
   float4 EyeVector = mul(CameraPos, matViewInverse); 
   EyeVector = -normalize(EyeVector + Input.Pos);

   // Calculates the Specular lightning per pixel.
   float4 Spec = Input.Color + LightPointSpecular (Input.Pos,
                                                    Input.Normal,
                                                    Light1Position,
                                                    Light1Color,
                                                    Light1Attenuation,
                                                    EyeVector );
   
   //return ((tex2D(TextureSampler, Input.TextureCoordinates)) * Input.Color);
   return ((tex2D(TextureSampler, Input.TextureCoordinates)) * Spec);
}

technique LightningTechnique
{
	pass TexturePass0
	{
		FillMode = Solid;
		CullMode = NONE;
		
		VertexShader = compile vs_2_0 vs_main();
		PixelShader = compile ps_2_0 ps_main();
	}
}
I'd apreciate any help I can get, and thank you for reading this all. Sorry about the messy code with lots of code commented away. It's what usualy happens to my code when I have problems I can't find and go to the brute force method of solving it by trying all possible combinations. =P PS. Sorry for the long post. How do you make those scroll boxes for posting code with keyword highlights? (am obviously brand ner here on gamedev.net) ;) / Bertil [Edited by - jollyjeffers on July 12, 2007 12:53:49 PM]

Share this post


Link to post
Share on other sites
Advertisement
to be honest, it sounds like your problem is 'outside' the shader. It's more likely that you're leaking state between draw operations. Your pipeline configuration isn't being correctly (re)set before the draw calls - what is valid for one object is no longer valid for the next etc..etc..

If I were you, look into using D3DPERF_BeginEvent() and D3DPERF_EndEvent() calls to surround your drawing code, then position D3DPERF_SetMarker() calls immediately before the rendering code.

Then use PIX with a single frame capture you can look at the device state (including VS/PS constants) to determine how the pipeline is configured. It's a bit tedious, but you should be able to see what is being configured incorrectly.

Quote:
How do you make those scroll boxes for posting code with keyword highlights?
Use [source] ... [/source] tags. I added them for you this time [smile]

hth
Jack

Share this post


Link to post
Share on other sites
ah thank you! :) Much easier to get an overview of the post now, will use the source commands next time I post. Thanks for adding it to me :) I will try PIX, have seen it being recommended in many posts. Am unfamiliar with how it works though, is it something that I should download first? Or any headers I need to include for those D3DPERF_BeginEvent() and the others? Or it's just to use right away?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement