I'm trying to achieve a simple diffuse light effect through HLSL vertex and pixel shader.
My shader code is pretty much taken from a
Gamasutra article, just slightly modified, take a look at this .fx file:
float4x4 matWorldViewProj;
float4x4 matWorld;
float4 vecLightDir;
struct VS_OUTPUT
{
float4 Pos : POSITION;
float2 UV : TEXCOORD0;
float3 Light : TEXCOORD1;
float3 Norm : TEXCOORD2;
};
VS_OUTPUT VS(float4 Pos : POSITION, float2 UV : TEXCOORD0, float3 Normal : NORMAL)
{
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Pos = mul(Pos, matWorldViewProj); // transform Position
Out.UV = UV; // pass UV coordinates on
Out.Light = normalize(vecLightDir); // output light vector
Out.Norm = normalize(mul(Normal, matWorld)); // transform Normal and normalize it
return Out;
}
float4 PS(float2 UV : TEXCOORD0, float3 Light : TEXCOORD1, float3 Norm : TEXCOORD2, sampler2D tex0) : COLOR
{
float4 diffuse = tex2D ( tex0, UV );
float4 ambient = {0.05, 0.05, 0.075, 1.0};
return ambient + diffuse * saturate(dot(Light, Norm));
}
technique EntryPoint
{
pass SinglePass
{
VertexShader = compile vs_2_0 VS ( );
PixelShader = compile ps_2_0 PS ( );
}
}
As you can see, I pretty much only added texture mapping (btw. this didn't make a difference, the results with the original code from the article and my modified version yield the same lighting results/problems).
My drawing code in the application looks like this:
void Render ( )
{
unsigned int num_passes;
// clear the back- and z-buffer
device->Clear ( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB ( clear_color.r, clear_color.g, clear_color.b ), 1.0f, 0 );
effect->Begin ( &num_passes, 0 );
for ( unsigned int pass = 0; pass < num_passes; pass++ )
// loop through all passes
{
effect->BeginPass ( pass );
DWORD old_fvf = NULL;
// get current flexible vertex format
device->GetFVF ( &old_fvf );
// set format for our models
device->SetFVF ( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2 );
std::vector<Model*>::iterator i;
for ( i = model.begin ( ); i < model.end ( ); i++ )
// loop through all models
{
// apply the matrix transformations for the model
(*i)->ApplyMatrixTransformations ( device );
// now get combined matrix (ie. the world-view-projection matrix)
D3DXMATRIX combined_matrix = GetCombinedMatrix ( );
effect->SetMatrix ( "matWorldViewProj", &combined_matrix );
D3DXMATRIX world_matrix;
// get world matrix
device->GetTransform ( D3DTS_WORLD, &world_matrix );
effect->SetMatrix ( "matWorld", &world_matrix );
D3DXVECTOR4 light_vector ( 0.0f, 0.0f, 1.0f, 0.0f );
effect->SetVector ( "vecLightDir", &light_vector );
// make sure all values send to the shader are updated
effect->CommitChanges ( );
// render model
(*i)->Render ( device );
}
// reset to old format
device->SetFVF ( old_fvf );
effect->EndPass ( );
}
effect->End ( );
}
As you can see, at the moment, I just hardcode the light vector so I should get a simple direction light.
What I get, however, is relatively weird:
These are two shots of my 3-test-cubes model.
If nothing is wrong with the shader (I'd need some confirmation there), then it has to be the normals, I guess. I calculate them using the lib3ds functionality, like this:
for ( int i = 0; i < file->nmeshes; i++ )
// loop through all meshes+
{
float ( *normals )[3] = ( float (*)[3] ) malloc ( 3 * 3 * sizeof ( float ) * file->meshes->nfaces );
// calculate the normals for all vertices in the mesh
lib3ds_mesh_calculate_vertex_normals ( file->meshes, normals );
}
Then, when I create my vertex buffer, I retrieve the proper normals from the "normals" array and add them to the vertex buffer. I also debug display the normals from that array when I'm loading the model and they look very correct, check out this output for one of the cubes (ie. one submesh):
Mesh 0 includes 26 vertices...
Format:
i: x, y, z / u, v / nx, ny, nz
0: -9.999, -9.999, 0.001 / 1, 1 / 0, 0, -1
1: 10.001, -9.999, 0.001 / 0, 1 / 0, 0, -1
2: -9.999, 10.001, 0.001 / 1, 0 / 0, 0, -1
3: 10.001, 10.001, 0.001 / 0, 0 / 0, 0, -1
4: -9.999, -9.999, 20.001 / 0, 1 / 0, 0, -1
5: 10.001, -9.999, 20.001 / 1, 1 / 0, 0, -1
6: -9.999, 10.001, 20.001 / 0, 0 / 0, 0, 1
7: 10.001, 10.001, 20.001 / 1, 0 / 0, 0, 1
8: -9.999, -9.999, 0.001 / 0, 1 / 0, 0, 1
9: 10.001, -9.999, 0.001 / 1, 1 / 0, 0, 1
10: 10.001, -9.999, 20.001 / 1, 0 / 0, 0, 1
11: 10.001, -9.999, 20.001 / 1, 0 / 0, 0, 1
12: -9.999, -9.999, 20.001 / 0, 0 / 0, -1, 0
13: -9.999, -9.999, 0.001 / 0, 1 / 0, -1, 0
14: 10.001, 10.001, 0.001 / 1, 1 / 0, -1, 0
15: 10.001, -9.999, 20.001 / 0, 0 / 0, -1, 0
16: 10.001, 10.001, 0.001 / 0, 1 / 0, -1, 0
17: -9.999, 10.001, 0.001 / 1, 1 / 0, -1, 0
18: -9.999, 10.001, 20.001 / 1, 0 / 1, 0, 0
19: -9.999, 10.001, 20.001 / 1, 0 / 1, 0, 0
20: 10.001, 10.001, 20.001 / 0, 0 / 1, 0, 0
21: 10.001, 10.001, 0.001 / 0, 1 / 1, 0, 0
22: -9.999, 10.001, 0.001 / 0, 1 / 1, 0, 0
23: -9.999, -9.999, 20.001 / 1, 0 / 1, 0, 0
24: -9.999, -9.999, 20.001 / 1, 0 / 0, 1, 0
25: -9.999, 10.001, 0.001 / 0, 1 / 0, 1, 0
As I said, looks fine to me. So what could be wrong?
Any help is appreciated, as always and thanks for your time.