Sign in to follow this  
Waaayoff

Weirdest bug ever? Something to do with D3DXEffect::CommitChanges()?

Recommended Posts

In my scene i'm rendering Meshes with textures using my first Shader. I begin a pass, for each mesh set the texture and call CommitChanges(), then render the mesh.
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:
[code]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[i].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;
}
}
}[/code]

The Mesh render function
[code]void CMesh::Render(LPD3DXEFFECT pEffect)
{
m_vb.ReadyBuffer();

int StartIndex = 0;
for (UINT i = 0; i < m_nSubMeshes; i++)
{
if (m_Mats[i].Texture)
{
pEffect->SetTexture("Tex", m_Mats[i].Texture);
pEffect->CommitChanges();
}

m_vb.Render(D3DPT_TRIANGLELIST, m_nVertices, StartIndex, m_Mats[i].nFaces);
StartIndex += m_Mats[i].nFaces * 3;
}
}[/code]


Shader 1:
[code]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();
}
}[/code]


Shader 2:
[code]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[i] = normalize(LightDirection[i]);
float3 Half = normalize(input.Light[i] + normalize(input.CamView));
TotalSpecular += (MatSpecular * SpecularLight[i]) * pow(saturate(dot(Normal, Half)), MatPower);
TotalDiffuse += (MatDiffuse * DiffuseLight[i]).rgb * saturate(dot(input.Light[i], 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();
}
}[/code]

Share this post


Link to post
Share on other sites
I'm not sure if it has anything to do with the "wiggle," but you should set your effect parameters ( matrices, lights, etc. ) [i]before[/i] you begin the pass, even before effect->Begin(). Then you don't need to call CommitChanges at all for those parameters. You only need to call CommitChanges when you change an effect parameter [i]between[/i] BeginPass and EndPass, such as when you change the texture.

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