Next i render other Meshes without textures but with lighting using a different Shader. I begin a pass, and render them.
Now this causes a bug where the meshes rendered with the second shader wiggle whenever i rotate/move the camera. A lot. After spending ages debugging, the problem somehow disappeared. I had a huge WTF moment. A day later, the problem re-appeared. Only some meshes wiggled while others didn't. Another WTF moment. The next day, this bug started to affect all the meshes.
I finally found out that when i omit the CommitChanges() calls when rendering with the first shader, the problem disappears. But since i need those, i added one CommitChanges() call to the second Shader before rendering any meshes.. and the problem was solved.
Now would someone tell me WTF is going on?
Here's any relevent code that i can think of:
The render function:
void CFramework::Render()
{
m_d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(50, 50, 80), 1.0f, 0);
m_d3ddev->BeginScene();
D3DXMATRIX World, View, Projection;
D3DXMatrixPerspectiveFovLH(&Projection,
D3DXToRadian(45),
(float)m_ScreenSize.cx / m_ScreenSize.cy,
1.0f,
100.0f);
D3DXMatrixIdentity(&World);
Cam.GetViewMatrix(&View);
D3DXMATRIX WVP = World * View * Projection;
// draw w/o texture
m_d3ddev->SetVertexDeclaration(_VertexDecl::PositionNormal::Decl);
Effect->Begin(NULL, 0);
Effect->BeginPass(0);
Effect->SetMatrix("WorldViewProj", &WVP);
Effect->SetFloatArray("MatAmbient", (float*)(&Mesh[3].m_Mats[0].Ambient), 3);
D3DXMATRIX WIT;
D3DXMatrixInverse(&WIT, 0, &World);
D3DXMatrixTranspose(&WIT, &WIT);
Effect->SetInt("nLights", 1);
Effect->SetMatrix("World", &World);
Effect->SetFloatArray("CamPosition", (float*)(&Cam.Position), 3);
Effect->SetFloatArray("MatDiffuse", (float*)(&Mesh[3].m_Mats[0].Diffuse), 4);
Effect->SetFloatArray("MatSpecular", (float*)(&Mesh[3].m_Mats[0].Specular), 3);
Effect->SetFloat("MatPower", 40.0f);
Effect->SetFloatArray("SpecularLight[0]", (float*)(&Color3(1.0f, 1.0f, 1.0f)), 3);
Effect->SetFloatArray("DiffuseLight[0]", (float*)(&Color4(1.0f, 0.5f, 0.5f, 1.0f)), 4);
Effect->SetFloatArray("AmbientLight", (float*)(&Color3(0.5f, 0.2f, 0.2f)), 3);
D3DXVECTOR3 LightPos(3.0f, 4.0f, -20.0f);
D3DXVECTOR3 LightPos2(-10.0f, 4.0f, 10.0f);
D3DXVECTOR3 Origin(0.0f, 0.0f, 0.0f);
Effect->SetFloatArray("LightDirection[0]", (float*)&(LightPos - Origin), 3);
Effect->CommitChanges(); // <-------- The Extra CommitChanges()
Mesh[3].Render(Effect);;
Mesh[4].Render(Effect);
Effect->EndPass();
Effect->End();
// draw w/ textures
EffectTex->Begin(NULL, 0);
EffectTex->BeginPass(0);
m_d3ddev->SetVertexDeclaration(_VertexDecl::PositionNormalTextured::Decl);
EffectTex->SetMatrix("WorldViewProj", &WVP);
for (int i = 0; i < 3; i++)
Mesh.Render(EffectTex);
m_d3ddev->SetVertexDeclaration(_VertexDecl::PreTransformedColourTextured::Decl);
RenderText();
EffectTex->EndPass();
EffectTex->End();
m_d3ddev->EndScene();
// Present the scene to the buffer
HRESULT hResult = m_d3ddev->Present(NULL, NULL, NULL, NULL);
// If the device is lost
if (FAILED(hResult))
{
// Handle the lost device.
hResult = HandleLostDevice(hResult);
if (FAILED(hResult))
{
LOG_ERROR(hResult);
m_Quit = true;
}
}
}
The Mesh render function
void CMesh::Render(LPD3DXEFFECT pEffect)
{
m_vb.ReadyBuffer();
int StartIndex = 0;
for (UINT i = 0; i < m_nSubMeshes; i++)
{
if (m_Mats.Texture)
{
pEffect->SetTexture("Tex", m_Mats.Texture);
pEffect->CommitChanges();
}
m_vb.Render(D3DPT_TRIANGLELIST, m_nVertices, StartIndex, m_Mats.nFaces);
StartIndex += m_Mats.nFaces * 3;
}
}
Shader 1:
float4x4 WorldViewProj;
texture Tex;
sampler Sampler = sampler_state
{
Texture = (Tex);
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};
struct VS_OUTPUT
{
float4 Pos : POSITION;
float4 Col : COLOR0;
float2 UV : TEXCOORD0;
};
struct PS_OUTPUT
{
float4 Col : COLOR0;
};
VS_OUTPUT VShader(float4 Pos : POSITION, float3 Nor : NORMAL, float2 UV : TEXCOORD0)
{
VS_OUTPUT OUT;
OUT.Pos = mul(Pos, WorldViewProj);
OUT.Col = float4(0.7, 0.7, 0.7, 1);
OUT.UV = UV;
return OUT;
}
PS_OUTPUT PShader(VS_OUTPUT IN)
{
PS_OUTPUT OUT;
OUT.Col = tex2D(Sampler, IN.UV) * IN.Col;
return OUT;
}
technique FirstTechnique
{
pass FirstPass
{
Lighting = false;
CullMode = None;
VertexShader = compile vs_2_0 VShader();
PixelShader = compile ps_2_0 PShader();
}
}
Shader 2:
float4x4 WorldViewProj;
float4x4 World;
float4 MatDiffuse;
float3 MatAmbient;
float3 MatSpecular;
float MatPower;
#define MAX_LIGHTS 3
float3 AmbientLight;
float4 DiffuseLight[MAX_LIGHTS];
float3 SpecularLight[MAX_LIGHTS];
float3 LightDirection[MAX_LIGHTS];
float3 CamPosition;
int nLights;
struct VS_IN
{
float4 Position : POSITION;
float3 Normal : NORMAL;
};
struct VS_OUT
{
float4 Position : POSITION;
float3 Light[MAX_LIGHTS] : TEXCOORD0;
float3 Normal : TEXCOORD3;
float3 CamView : TEXCOORD4;
};
struct PS_OUT
{
float4 Colour : COLOR;
};
VS_OUT VShader(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.Position = mul(input.Position, WorldViewProj);
output.Normal = mul(float4(input.Normal, 0.0f), World).xyz;
output.CamView = CamPosition - mul(input.Position, World);
return output;
}
PS_OUT PShader(VS_OUT input)
{
PS_OUT output = (PS_OUT)0;
float3 Normal = normalize(input.Normal);
float3 TotalDiffuse = float3(0,0,0);
float3 TotalSpecular = float3(0,0,0);
for (int i = 0; i < nLights; i++)
{
input.Light = normalize(LightDirection);
float3 Half = normalize(input.Light + normalize(input.CamView));
TotalSpecular += (MatSpecular * SpecularLight) * pow(saturate(dot(Normal, Half)), MatPower);
TotalDiffuse += (MatDiffuse * DiffuseLight).rgb * saturate(dot(input.Light, Normal));
}
output.Colour.rgb = (MatAmbient * AmbientLight) + TotalDiffuse + TotalSpecular;
output.Colour.a = MatDiffuse.a;
return output;
}
technique FirstTechnique
{
pass FirstPass
{
Lighting = false;
CullMode = None;
VertexShader = compile vs_2_0 VShader();
PixelShader = compile ps_2_0 PShader();
}
}