Sign in to follow this  

HLSL extern variable not updating

Recommended Posts

Bob_the_dev    186
I have an external variable in my shader that doesn't seem to be getting set properly. In the main program I set the variable every frame like so: HR(mFX->SetFloat(mhTime, dt)) And after debugging I determined dt holds the correct value. However, the shader's not working correctly. This was my first time to use PIX and debug a shader, so I think I'm reading this correctly. The c10 register seems to hold the time variable. I took 3 snap shots in PIX and the c10 registers hold values of .415, .407, .416 in that order. I don't know why the variable isn't updating properly, and it's very odd that the register value goes up and down by a small amount when it's supposed to constantly increase. Does anyone have any ideas as to why it's not getting the correct value being sent to it in the shader? ETA: When I use GetFloat to get the variable from the shader it returns the correct value. But my shader's not working correctly, the register that's supposed to hold the variable isn't holding the correct value, and I just don't know what's going on. [Edited by - Bob_the_dev on March 20, 2008 12:26:08 AM]

Share this post

Link to post
Share on other sites
Sc4Freak    643
What is mhTime? If it's a handle, try setting the variable by name.

Also, it may help to post more code. Post the shader itself, as well as any code to load the shader.

Share this post

Link to post
Share on other sites
Bob_the_dev    186
Original post by Sc4Freak
What is mhTime? If it's a handle, try setting the variable by name.

Also, it may help to post more code. Post the shader itself, as well as any code to load the shader.

mhTime is a handle.

This is the shader:

struct Mtrl
float4 ambient;
float4 diffuse;
float4 spec;
float specPower;

struct DirLight
float4 ambient;
float4 diffuse;
float4 spec;
float3 dirW;

uniform extern float gTime;
uniform extern float4x4 gWorld;
uniform extern float4x4 gWorldInv;
uniform extern float4x4 gWVP;
uniform extern Mtrl gMtrl;
uniform extern DirLight gLight;
uniform extern float3 gEyePosW;
uniform extern texture gEnvMap;

// Amplitudes
static float a = 10.0f;

// Angular wave numbers.
static float k = 1.0f;

// Angular frequency.
static float w = 1.0f;

// Phase shifts.
static float p = 0.0f;

float SumOfRadialSineWaves(float x, float z, out float dhOverdx, out float dhOverdz)
// Distance of vertex from source of waves (which we set
// as the origin of the local space).
float d = sqrt(x*x + z*z);

// Sum the waves.
float s = k*d - gTime*w + p;
float sum = a*sin(s);
dhOverdx = (a*k*x*cos(s))/d;
dhOverdz = (a*k*z*cos(s))/d;

return sum;

sampler EnvMapS = sampler_state
Texture = <gEnvMap>;
MaxAnisotropy = 8;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;

struct OutputVS
float4 posH : POSITION0;
float3 normalW : TEXCOORD1;
float3 posW : TEXCOORD2;

OutputVS WaterVS(float3 posL : POSITION0)
// Zero out our output.
OutputVS outVS = (OutputVS)0;

float dx;
float dz;
posL.y = SumOfRadialSineWaves(posL.x, posL.z, dx, dz);
float3 u = {1, dx, 0};
float3 v = {0, dz, 1};
float3 n = cross(u, v);
float3 norm = normalize(n);

// Water plane lies in xz-plane, so geometric normal is just (0, 1, 0).
outVS.normalW = mul(float4(n, 0.0f), gWorldInv).xyz;
outVS.normalW = normalize(outVS.normalW);

// Transform to homogeneous clip space.

outVS.posW = mul(float4(posL, 1.0f), gWorld).xyz;
outVS.posH = mul(float4(posL, 1.0f), gWVP);

// Done--return the output.
return outVS;

float4 WaterPS(float3 normalW : TEXCOORD1,
float3 posW : TEXCOORD2) : COLOR
float3 ToEye = normalize(gEyePosW - posW);

// Compute the reflection vector.
float3 r = reflect(-gLight.dirW, normalW);

// Determine how much (if any) specular light makes it into the eye.
float t = pow(max(dot(r, ToEye), 0.0f), gMtrl.specPower);

// Determine the diffuse light intensity that strikes the vertex.
float s = max(dot(gLight.dirW, normalW), 0.0f);

// If the diffuse light intensity is low, kill the specular lighting term.
// It doesn't look right to add specular light when the surface receives
// little diffuse light.
if(s <= 0.0f)
t = 0.0f;

// Get the reflected color. Also add some scale of normalT to
// the environment map look-up vector. This perturbs the look-up
// vector in a different way each frame (since normalT changes),
// which gives a ripple effect.
float3 envMapTex = reflect(-ToEye, normalW) + (sin(normalW)*2.0f);
float3 reflectedColor = texCUBE(EnvMapS, envMapTex);

// Weighted average between the reflected color and usual diffuse material.
float3 ambientMtrl = (0.5f*reflectedColor + 0.5f*gMtrl.ambient);
float3 diffuseMtrl = (0.5f*reflectedColor + 0.5f*gMtrl.diffuse);

// Compute the ambient, diffuse and specular terms separatly.
float3 spec = t*(gMtrl.spec*gLight.spec).rgb;
float3 diffuse = s*(diffuseMtrl*gLight.diffuse.rgb);
float3 ambient = ambientMtrl*gLight.ambient;

float3 final = ambient + diffuse + spec;

// Output the color and the alpha.
return float4(final, gMtrl.diffuse.a);

technique WaterTech
pass P0
// Specify the vertex and pixel shader associated with this pass.
vertexShader = compile vs_2_0 WaterVS();
pixelShader = compile ps_2_0 WaterPS();

// For transparency.
AlphaBlendEnable = true;
SrcBlend = SrcAlpha;
DestBlend = InvSrcAlpha;

Code that builds the effect:

ID3DXBuffer* errors = 0;
HR(D3DXCreateEffectFromFile(gd3dDevice, "Water.fx",
0, 0, D3DXSHADER_DEBUG, 0, &mFX, &errors));
if( errors )
MessageBox(0, (char*)errors->GetBufferPointer(), 0, 0);

mhTech = mFX->GetTechniqueByName("WaterTech");
mhWorld = mFX->GetParameterByName(0, "gWorld");
mhWorldInv = mFX->GetParameterByName(0, "gWorldInv");
mhWVP = mFX->GetParameterByName(0, "gWVP");
mhEyePosW = mFX->GetParameterByName(0, "gEyePosW");
mhLight = mFX->GetParameterByName(0, "gLight");
mhMtrl = mFX->GetParameterByName(0, "gMtrl");
mhEnvMap = mFX->GetParameterByName(0, "gEnvMap");
mhTime = mFX->GetParameterByName(0, "gTime");

Share this post

Link to post
Share on other sites
ankhd    2304
If you are trying to up date the member var between the mFX->Begin(&numPasses, 0);and this hr = mFX->BeginPass(0);
then you will need to call hr = mFX->CommitChanges(); for it to take effect.

Hope this helps

Share this post

Link to post
Share on other sites
Bob_the_dev    186
I fixed it (finally). It was a matter of setting the time variable right before beginning the drawing and effects passes instead of in the update portion of the frame.

Not sure I really understand why though. How does DirectX handle external variables?

Share this post

Link to post
Share on other sites
Sc4Freak    643
As ankhd mentioned, you need to call CommitChanges() if you modify shaders after a call to Begin().

This is because ID3DXEffect will set all the necessary render state and shader state calls in Begin() and BeginPass() and not when you call SetFloat(). That means that if you call SetFloat() (or similar calls) after Begin(), the necessary device states will not be updated. That's why you need to call CommitChanges(), which will force ID3DXEffect to commit the changes to the device.

An alternative is to simply move the SetFloat() call outside of the ID3DXEffect::Begin()/End() pair, which is what you did.

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