I'm trying to get into Direct3D 10 and build a framebuffer on the way, my current goal is to write a simple per-vertex lighting shader using HLSL/fx4 and cbuffers.
But there is a strange problem I've been trying to figure-out since yesterday. Simply put, some of the constant values I set in C++ are somehow not the actual values that get to the shader, this specifically happens when setting light constants which is a struct in it's own cbuffer.
My shader currently looks like this:
struct PointLight{ float3 pos; float4 ambient; float4 diffuse; float4 specular; float3 att; float range;};struct Material{ float4 diffuse; float4 specular; float power;};cbuffer cbPerFrame{ float3 gEyePos;};cbuffer cbPerObject{ float4x4 gWorld; float4x4 gWVP; Material gMaterial;};cbuffer cbPerLight{ PointLight gLight;};struct VS_IN{ float3 posL : POSITION; float3 normal : NORMAL; float2 tex : TEXCOORD0;};struct VS_OUT{ float4 posH : SV_POSITION; float4 color : COLOR;};float4 lightPoint(in PointLight light, float3 posL, float3 normal){ float3 dir = normalize(light.pos - posL); float d = distance(light.pos, posL); // Diffuse term float kd = max(dot(dir, normal), 0.0f); // Specular term float3 v = normalize(gEyePos - posL); float3 r = reflect(-dir, normal); float ks = pow(saturate(kd) * max(dot(v, r), 0.0f), gMaterial.power); return ((light.ambient) + ((light.diffuse * gMaterial.diffuse) * kd) + ((light.specular * gMaterial.specular) * ks)) / (dot(light.att, float3(1.0f, d, d * d)));}VS_OUT LightVS(VS_IN input){ VS_OUT output; output.posH = mul(float4(input.posL, 1.0f), gWVP); output.color = lightPoint(gLight, input.posL, input.normal); // The value in gLight.att is not the same value I set in C++! //output.color = float4(1.0f, gLight.att); return output;}float4 LightPS( float4 posH : SV_POSITION, float4 color : COLOR) : SV_TARGET{ return color;}technique10 LightTech{ pass P0 { SetVertexShader(CompileShader(vs_4_0, LightVS())); SetGeometryShader(NULL); SetPixelShader(CompileShader(ps_4_0, LightPS())); }}
I set the values in C++ like this:
// Load collada file and set experimental shadermMesh.reset(new Mesh(mDevice, L"models/teapot.dae", L"shaders/light.fx", 0.1f));// Setup material and lightmMtrl.diffuse = D3DXVECTOR4(0.6f, 0.4f, 0.5f, 1.0f);mMtrl.specular = D3DXVECTOR4(1.0f, 0.5f, 0.5f, 0.5f);mMtrl.power = 2.0f;mPointLight.ambient = D3DXVECTOR4(1.0f, 0.1f, 0.1f, 0.1f);mPointLight.diffuse = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);mPointLight.specular = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);mPointLight.att = D3DXVECTOR3(1.0f, 0.0f, 0.0f);mPointLight.pos = D3DXVECTOR3(0.0f, 5.0f, -10.0f);mPointLight.range = 40.0f;mMesh->getEffect()->setMaterial("gMaterial", mMtrl);mMesh->getEffect()->setObject<PointLight>("gLight", mPointLight);
And here is the definition of PointLight structure in C++ (identical to the one in shader):
struct PointLight{ PointLight() { memset(this, 0, sizeof(PointLight)); } D3DXVECTOR3 pos; D3DXVECTOR4 ambient; D3DXVECTOR4 diffuse; D3DXVECTOR4 specular; D3DXVECTOR3 att; float range;};
The strange thing is that setting Material constants works perfectly, and using a very similar shader for directional lights works perfectly too! I'm having this problem only with PointLight for some reason..
At first glance, I thought it was a packing issue, I tried to specify packing manually using register and packoffset, it didn't work and I'm not sure I did it right to begin with.
Did I miss something?
Thanks for any help :)