Sign in to follow this  
Paul7

Shader problems

Recommended Posts

I`m new to using vertex and pixel shaders but have created a fully working specular lighting shader in ATI`s RenderMonkey. See image below: I then tried to add this shader into my DirectX program. I initialised the shader using:
if (FAILED(hr=D3DXCreateEffectFromFile(gDevice,"specular_lighting.fx",NULL,NULL,0,NULL,&m_pEffect,NULL)))
{
	return hr;
}

and then when rendering each frame:
gDevice->GetTransform(D3DTS_VIEW,&matView);
gDevice->GetTransform(D3DTS_PROJECTION,&matProjection);

D3DXMatrixMultiply(&matWVP,&matWorld,&matView);
D3DXMatrixMultiply(&matWVP,&matWVP,&matProjection);
	
D3DXMatrixTranspose(&matWVP, &matWVP);
D3DXMatrixTranspose(&matWorld, &matWorld);

D3DXVECTOR4 View;
View.x = matView._13;
View.y = matView._23;
View.z = matView._33;
View.w = 1.0;

m_pEffect->SetMatrix("matWorldViewProjection", &matWVP);
m_pEffect->SetMatrix("matWorld", &matWorld);
m_pEffect->SetVector("vecEye", &View);
	
m_pEffect->SetTechnique( m_pEffect->GetTechniqueByName("Effect1"));

UINT iPass, cPasses;
m_pEffect->Begin(&cPasses, 0);
for (iPass = 0; iPass < cPasses; iPass++)
{
	m_pEffect->BeginPass(iPass);
		
	gDevice->SetStreamSource( 0, gVB, 0,  sizeof(Vertex_pos_norm));
	gDevice->SetFVF(D3DFVF_VERTEX_POS_NORM);
	gDevice->SetIndices( gIB);
	gDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,0,0,num_vert,0, num_tris);

	m_pEffect->EndPass();
}
m_pEffect->End();

The resulting image is shown below. This obvioulsy isnt correct. As I rotate the camera upwards the specular highlight increases. Is there anything wrong with the initialisation code or rendering code? I thought it could be to do with the matrices or vectors that are passed to the vertex shader? Any help would be much appreciated. Thanks

Share this post


Link to post
Share on other sites
you shouldn't be transposing the matrices, the fact that the view matrix is naturally inversed is how it's supposed to be; WorldViewProjection puts geometry onto the screen, exactly where it should be. Put the set stream source and set indices outside the loop, it's not needed each iteration - I'm not sure if it could cause a slow down because I have never received a D3D warning message on setting the same stream source more than once, unlike repetitive renderstates. I don't know what your .fx file looks like, but rendermonkey's matrix with vector multiplication is backwards, it should be mul(matrix, vector) if I remember correctly. It'll produce a torn image in the program, but it is correct. A way around this is to manually patch the .fx file by parsing the text, prior to loading it in.

I believe that...

View.x = matView._13;
View.y = matView._23;
View.z = matView._33;

should be:

View.x = matView._31;
View.y = matView._32;
View.z = matView._33;

I'm also pretty sure that you're not supposed to be setting the FVF at all, the vertex/pixel shader takes it over and your vertex structure should be the same as your vertex shader's entry function.

The fact that the mesh is positioned to where you want it to be is weird, unless there's something to transposing that I don't know of. I'm no expert on shaders, but I hope this helped anyways [smile]

Share this post


Link to post
Share on other sites
In RenderMonkey, the transformations are carried out from right to left because the matrix inputs to the vertex shader are transposed :-

Out.vPosition = mul(mWorldViewProj, inPos);

Whereas, DirectX needs you to carry out transformations from a left to right order if you don't transpose your matrices :-

Out.vPosition = mul(inPos, mWorldViewProj);

The same holds good for all matrix transformations. If you've changed the transformations in "specular_lighting.fx" and instead supplying transposed matrices, then the "error" in that screenshot would occur.

Try using un-transposed matrices everywhere (in the app and the vertex shader) and see if you get correct results.

Share this post


Link to post
Share on other sites
Thanks for the help.

Ive switched the view vector around and it works a bit better. The highlights intensity now increases as I rotate the camera towards the plane. Its still not right tho:



Here the light is a directional light pointing straight down on the plane.

If I dont transpose the world matrix it works as in the screenshot it works a bit better. Not transposing the worldviewprojection matrix messes everything up so cant see the plane hardly at all.

my shader is as follows:


float4x4 matWorldViewProjection : WorldViewProjection;
float4x4 matWorld : World;
float4 vecLightDir
<
string UIName = "vecLightDir";
string UIWidget = "Direction";
float4 UIMin = ( -1.00, -1.00, -1.00, -1.00 );
float4 UIMax = ( 1.00, 1.00, 1.00, 1.00 );
bool Normalize = false;
> = ( 0.0, -1.0, 0.0, 1.00 );

float4 vecEye : ViewPosition;

struct VS_OUTPUT
{
float4 Pos: POSITION;
float3 Light : TEXCOORD0;
float3 Norm : TEXCOORD1;
float3 View : TEXCOORD2;
};

VS_OUTPUT Effect_Group_1_Effect1_Pass_0_Vertex_Shader_VS( float4 inPos: POSITION, float3 Normal : NORMAL)
{
VS_OUTPUT Out = (VS_OUTPUT)0;

Out.Pos = mul(matWorldViewProjection, inPos);
Out.Light = vecLightDir;
float3 PosWorld = normalize(mul(inPos, matWorld));
Out.View = vecEye - PosWorld; // V
Out.Norm = mul(Normal, matWorld); // N

return Out;
}


float4 Effect_Group_1_Effect1_Pass_0_Pixel_Shader_PS(float3 Light: TEXCOORD0, float3 Norm : TEXCOORD1,
float3 View : TEXCOORD2) : COLOR
{
float4 diffuse = { 0.0f, 0.8f, 0.0f, 1.0f};
float4 ambient = {0.2, 0.02, 0.02, 1.0};

float3 Normal = normalize(Norm);
float3 LightDir = normalize(Light);
float3 ViewDir = normalize(View);
float4 diff = saturate(dot(Normal, LightDir)); // diffuse component
// compute self-shadowing term
float shadow = saturate(4* diff);

float3 Reflect = normalize(2 * diff * Normal - LightDir); // R
float4 specular = pow(saturate(dot(Reflect, ViewDir)), 4); // R.V^n )
return ambient + shadow * (diffuse * diff + specular);

}

technique Effect1
{
pass Pass_0
{
VertexShader = compile vs_2_0 Effect_Group_1_Effect1_Pass_0_Vertex_Shader_VS();
PixelShader = compile ps_2_0 Effect_Group_1_Effect1_Pass_0_Pixel_Shader_PS();
}
}





[Edited by - Paul7 on October 3, 2004 10:51:48 AM]

Share this post


Link to post
Share on other sites
I think you need to change this line:
Out.Pos = mul(matWorldViewProjection, inPos);
to
Out.Pos = mul(inPos, matWorldViewProjection);

and then remove your transpose on matWorldViewProjection; That should do it - according to what poly-gone said :).

Share this post


Link to post
Share on other sites
Doing that makes it work without the transpose but still gives me the strange shaped specular highlight as in the previous screen shot.

Any other suggestions would be much appreciated. thanks.

Share this post


Link to post
Share on other sites
Ive now switched a few bits round and have got it working fine in NVIDIA effects composer also.



So i`m pretty sure that it must be something wrong with my vectors and matrices that am passing to the shader but cant figure out which?

my latest directx code is as follows:


gDevice->GetTransform(D3DTS_WORLD,&matWorld);
gDevice->GetTransform(D3DTS_VIEW,&matView);
gDevice->GetTransform(D3DTS_PROJECTION,&matProjection);

D3DXVECTOR4 View;
View.x = matView._31;
View.y = matView._32;
View.z = matView._33;
View.w = 1.0;

D3DXMatrixMultiply(&matWVP,&matWorld,&matView);
D3DXMatrixMultiply(&matWVP,&matWVP,&matProjection);

D3DXVECTOR4 Lightvec;
Lightvec.x = 0.0; Lightvec.y = 1.0; Lightvec.z = 0.0; Lightvec.w = 1.0;

m_pEffect->SetMatrix("matWorldViewProjection", &matWVP);
m_pEffect->SetMatrix("matWorld", &matWorld);
m_pEffect->SetVector("vecLightDir", &Lightvec);
m_pEffect->SetVector("vecEye", &View);

m_pEffect->SetTechnique( m_pEffect->GetTechniqueByName("Effect1"));

gDevice->SetStreamSource( 0, gVB, 0, sizeof(Vertex_pos_norm));
gDevice->SetFVF(D3DFVF_VERTEX_POS_NORM);
gDevice->SetIndices( gIB);

UINT iPass, cPasses;
m_pEffect->Begin(&cPasses, 0);
for (iPass = 0; iPass < cPasses; iPass++)
{
m_pEffect->BeginPass(iPass);

gDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,0,0,num_vert,0, num_tris);

m_pEffect->EndPass();
}
m_pEffect->End();



and my latest shader code is:


float4x4 matWorldViewProjection : WorldViewProjection;
float4x4 matWorld : World;
float4 vecLightDir;
float4 vecEye;

struct VS_OUTPUT
{
float4 Pos: POSITION;
float3 Light : TEXCOORD0;
float3 Norm : TEXCOORD1;
float3 View : TEXCOORD2;
};

VS_OUTPUT Effect_Group_1_Effect1_Pass_0_Vertex_Shader_VS( float4 inPos: POSITION, float3 Normal : NORMAL)
{
VS_OUTPUT Out = (VS_OUTPUT)0;

//Out.Pos = mul(matWorldViewProjection, inPos);
Out.Pos = mul(inPos, matWorldViewProjection);
Out.Light = vecLightDir;
float3 PosWorld = normalize(mul(inPos, matWorld));
Out.View = vecEye - PosWorld; // V
Out.Norm = mul(Normal, matWorld); // N

return Out;
}

float4 Effect_Group_1_Effect1_Pass_0_Pixel_Shader_PS(float3 Light: TEXCOORD0, float3 Norm : TEXCOORD1,
float3 View : TEXCOORD2) : COLOR
{
float4 diffuse = { 0.0f, 0.8f, 0.0f, 1.0f};
float4 ambient = {0.2, 0.02, 0.02, 1.0};

float3 Normal = normalize(Norm);
float3 LightDir = normalize(Light);
float3 ViewDir = normalize(View);
float4 diff = saturate(dot(Normal, LightDir)); // diffuse component

// compute self-shadowing term
float shadow = saturate(4* diff);

float3 Reflect = normalize(2 * diff * Normal - LightDir); // R
float4 specular = pow(saturate(dot(Reflect, ViewDir)), 20); // R.V^n
// I = ambient + shadow * (Dcolor * N.L + (R.V)n)
return ambient + shadow * (diffuse * diff + specular);

}

technique Effect1
{
pass Pass_0
{
VertexShader = compile vs_2_0 Effect_Group_1_Effect1_Pass_0_Vertex_Shader_VS();
PixelShader = compile ps_2_0 Effect_Group_1_Effect1_Pass_0_Pixel_Shader_PS();
}

}



Thanks.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this