• Advertisement
Sign in to follow this  

[SOLVED] Shaders - How to Set values of struct array in HLSL from Application ?

This topic is 2648 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a following structure in my HLSL Shader -


struct DirectionalLights
{
float3 revDirection;

float4 ambientColor : COLOR;
float4 diffuseColor : COLOR;
float4 specularColor : COLOR;
};

int numDirLights = 0;
DirectionalLights dirLights[2];

















How can i assign values to dirLights ???
I am using DX9 Effects framework.

Here the c++ code am using -


typedef struct chDirectionLight
{
D3DXVECTOR3 direction;
float pad0; //getting same error even after removing this optional variable

D3DXCOLOR ambientColor,diffuseColor,specularColor;

chDirectionLight()
{
pad0=0.0f;
direction = D3DXVECTOR3(0.0f,0.0f,0.0f);
diffuseColor=ambientColor=specularColor=D3DXCOLOR(0.0f,0.0f,0.0f,0.0f);
}
}chDirectionLight,*LPChDirectionalLight;

/////Later to set value I am using following call
effect->SetValue(this->dirLightHandle,(void *)ptrDirLight,sizeof(chDirectionLight));



















I am trying to set first member of array in above c++ code but it m getting - DirectX Reported Error: D3DERR_INVALIDCALL - Invalid

Please help me figure out how to do it correctly and also how we will assign values to 2nd member of dirLights array.



EDIT : I know how to set 2 elements togather using 2*sizeof(struct), but i want to know if there is some method to assign value to 2nd elemnt without bothering the first one. There is no option to set offset in ID3DXEFFECT::SetValue() Method.

EDIT 2: I am getting DirectX Reported Error: D3DERR_INVALIDCALL - Invalid call on this line :
effect->SetValue(this->dirLightHandle,(void *)ptrDirLight,sizeof(chDirectionLight));

[Edited by - Chetanhl on October 23, 2010 2:29:37 PM]

Share this post


Link to post
Share on other sites
Advertisement
* You forgot the parameter pad0 in your shader code. Take a look.
* Maybe you have to pass numElements * sizeof (chDirectionLight) to the 3rd of ID3DXBaseEffect::SetValue() function.

Share this post


Link to post
Share on other sites
Initially there wasn't any pad0 variable i added just becoz some random article on net (it's just on of search results i got while searching on google
) suggested to do so, as in HLSL float3 are saved as float4 in memory. I dunno if its correct but no matter if pad is there or not am getting same error message.

I know how to set 2 elements togather using 2*sizeof(struct), but i want to know if there is some method to assign value to 2nd elemnt without bothering the first one. There is no option to set offset in ID3DXEFFECT::SetValue() Method.

Share this post


Link to post
Share on other sites
Already tried to include padding in both even thats not working.

Here's new code for HLSL Struct -



struct DirectionalLights
{
float3 revDirection;
float pad0;

float4 ambientColor : COLOR;
float4 diffuseColor : COLOR;
float4 specularColor : COLOR;
};







c++ Struct Code -



typedef struct chDirectionLight
{
D3DXVECTOR3 direction;
float pad0;

D3DXCOLOR ambientColor,diffuseColor,specularColor;

chDirectionLight()
{
pad0=0.0f;
direction = D3DXVECTOR3(0.0f,0.0f,0.0f);
diffuseColor=ambientColor=specularColor=D3DXCOLOR(0.0f,0.0f,0.0f,0.0f);
}
}chDirectionLight,*LPChDirectionalLight;




Still no luck geting same error.

Share this post


Link to post
Share on other sites
Here's that line -

effect->SetValue(this->dirLightHandle,(void *)ptrDirLight,sizeof(chDirectionLight));

Share this post


Link to post
Share on other sites
This is choped of from my old project.
code:

const UINT MAX_ACTIVE_LIGHTS = 8; //
...
D3DXHANDLE HNumLights;
D3DXHANDLE HLightPosition[MAX_ACTIVE_LIGHTS];
D3DXHANDLE HLightAmbient[MAX_ACTIVE_LIGHTS];
D3DXHANDLE HLightDiffuse[MAX_ACTIVE_LIGHTS];
D3DXHANDLE HLightSpecular[MAX_ACTIVE_LIGHTS];
D3DXHANDLE HLightRadius[MAX_ACTIVE_LIGHTS];
...//and other attributes
...
D3DXHANDLE hLight = 0;
UINT i = 0;
for(; i < MAX_ACTIVE_LIGHTS; ++i)
{
hLight = Effect->GetParameterElement("Lights", i);
if(0 == hLight)
{
...error
return false;
}
HLightPosition = Effect->GetParameterByName(hLight, "Position");
if(0 == HLightPosition)
{
...error
return false;
}
HLightAmbient = Effect->GetParameterByName(hLight, "Ambient");
if(0 == HLightAmbient)
{
return false;
}
HLightDiffuse = Effect->GetParameterByName(hLight, "Diffuse");
if(0 == HLightDiffuse)
{
...error
return false;
}
HLightSpecular = Effect->GetParameterByName(hLight, "Specular");
if(0 == HLightSpecular)
{
...error
return false;
}
HLightRadius = Effect->GetParameterByName(hLight, "Radius");
if(0 == HLightRadius)
{
...error
return false;
}
...//other attributes
}
...
//then you set each value using handles




shader:

#define MAX_ACTIVE_LIGHTS 8

int NumLights;//num lights currently affecting this model
...
struct Light
{
float3 Position;
float4 Ambient;
float4 Diffuse;
float4 Specular;
float Radius;
...//other attributes
};

Light Lights[MAX_ACTIVE_LIGHTS];
...




hope it helps.

Share this post


Link to post
Share on other sites
For the error you can pass an error buffer when creating your shader then any failures would be available in human readable form. You can also use fxc.exe as well, just ignore the 'main() not found' error since that is only required by fxc. Both methods will give you the line number and column of the error. I prefer the first since I log all of my errors in a text file.

Share this post


Link to post
Share on other sites
@belfegor Thanks for the code it worked.

But got another problem now.
I am always getting black colored objects in output.



Here's my full shader code am using (It worked in Nvdia FX Composer) -
(I am using 1 directional light for now )


/*

Lights and Texture Shader Halfway implementation


*/


float4x4 worldMat : World;
float4x4 viewProj : ViewProjection;
float4x4 wMatInvTrans : WorldInverseTranspose;
float3 pEye : POSITION;

bool isLightEnabled = true;


struct Material
{
float4 ambientColor : COLOR0;
float4 diffuseColor : COLOR1;
float4 specularColor : COLOR2;

float4 emissive : COLOR3;

float power;
};
Material currentMtrl;

float3 AmbientLight = (0.0f,0.0f,0.0f) ;

struct DirectionalLights
{
float3 revDirection;

float4 ambientColor : COLOR0;
float4 diffuseColor : COLOR1;
float4 specularColor : COLOR2;
};

struct PointLights
{
float3 position;
float range;
float att0,att1,att2;

float4 ambientColor : COLOR0;
float4 diffuseColor : COLOR2;
float4 specularColor : COLOR1;
};

struct SpotLights
{
float3 position;
float3 revDirection;

float fallOff;
float theta,phi;

float range;
float att0,att1,att2;

float4 ambientColor : COLOR0;
float4 diffuseColor : COLOR1;
float4 specularColor : COLOR2;
};

struct VCOLOR
{
float3 ambColor : COLOR0;
float3 diffuseColor : COLOR1;
float3 specColor : COLOR2;
};

const int lights_MAXD = 2;
const int lights_MAXP = 5;
const int lights_MAXS = 5;

int numDirLights = 0;
DirectionalLights dirLights[2];

int numPointLights = 0;
PointLights pointLights[5];

int numSpotLights = 0;
SpotLights spotLights[5];


VCOLOR CalcDirLight(float3 normalW,float3 vecPosW)
{
VCOLOR res = (VCOLOR)0;
float angle;
float3 halfway;

vecPosW = normalize(pEye-vecPosW);

for(int i=0;i<numDirLights;i++)
{
res.ambColor += dirLights.ambientColor.rgb;

angle = max(dot(normalW,dirLights.revDirection),0.0f);
res.diffuseColor = res.diffuseColor + angle*dirLights.diffuseColor.rgb;

halfway = normalize(vecPosW + dirLights.revDirection);
angle = pow(max(dot(halfway,normalW),0.0f),currentMtrl.power);
res.specColor += angle*dirLights.specularColor.rgb;
}

res.ambColor *= currentMtrl.ambientColor.rgb;
res.diffuseColor *= currentMtrl.diffuseColor.rgb;
res.specColor *= currentMtrl.specularColor.rgb;

return res;
}


VCOLOR CalcPointLight(float3 normalW,float3 vecPosW)
{}


VCOLOR CalcSpotLight(float3 normalW,float3 vecPosW)
{}


texture gTex0 : TEXTURE;

sampler texS0 = sampler_state
{
Texture = <gTex0>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};


texture gTex1 : TEXTURE;

sampler texS1 = sampler_state
{
Texture = <gTex1>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};



struct VS_INPUT
{
float3 posL : POSITION;
float3 normalL : NORMAL0;
float2 tex0 : TEXCOORD0;
};

struct VS_OUTPUT
{
float4 posH : POSITION;
float4 color : COLOR0;
float3 spec : COLOR1;
float2 tex0 : TEXCOORD0;
};


VS_OUTPUT mainVS(VS_INPUT input)
{
VS_OUTPUT output = (VS_OUTPUT)0;

float3 posW = mul(float4(input.posL,1.0f),worldMat).xyz;
float3 normalW = mul(float4(input.normalL,0.0f),wMatInvTrans).xyz;
normalW=normalize(normalW);

output.spec = float3(0.0f,0.0f,0.0f);
output.color = float4(1.0f,1.0f,1.0f,1.0f);

if(isLightEnabled)
{
///Light Calculations
output.color.rgb = AmbientLight*currentMtrl.ambientColor.rgb + currentMtrl.emissive.rgb;
output.color.a = currentMtrl.diffuseColor.a;

VCOLOR col = CalcDirLight(normalW,posW);

output.color.rgb += col.ambColor + col.diffuseColor;
output.spec += col.specColor;

}

output.posH = mul(float4(input.posL,1.0f),viewProj);
output.tex0 = input.tex0;

return output;

}

float4 mainPS(float4 c : COLOR0, float3 spec : COLOR1, float2 tex0 : TEXCOORD0) : COLOR
{
float3 texColor = tex2D(texS0, tex0).rgb;
float3 diffuse = c.rgb * texColor;
return float4(diffuse + spec, c.a);
}

technique techniqueLightsTexture{
pass p0 {
VertexShader = compile vs_3_0 mainVS();
PixelShader = compile ps_3_0 mainPS();
}
}






Here's my C++ Code for assigning values to directional light array -



lightIndexHandle = effect->GetParameterElement("dirLights",0);
if(lightIndexHandle==0)
{return false;
}

tempHandle = effect->GetParameterByName(lightIndexHandle,"revDirection");
if(tempHandle==0)
{return false;
}
chUtility::FailedHR(effect->SetFloatArray(tempHandle,(float*)ptrDirLight->direction,3));

tempHandle = effect->GetParameterByName(lightIndexHandle,"ambientColor");
if(tempHandle==0)
{return false;
}
chUtility::FailedHR(effect->SetFloatArray(tempHandle,(float*)ptrDirLight->ambientColor,4));

tempHandle = effect->GetParameterByName(lightIndexHandle,"diffuseColor");
if(tempHandle==0)
{
return false;
}
chUtility::FailedHR(effect->SetFloatArray(tempHandle,(float*)ptrDirLight->diffuseColor,4));

tempHandle = effect->GetParameterByName(lightIndexHandle,"specularColor");
if(tempHandle==0)
{return false;
}
chUtility::FailedHR(effect->SetFloatArray(tempHandle,(float*)ptrDirLight->specularColor,4));
effect->CommitChanges();





While debugging in PIX i found that res.diffuseColor = res.diffuseColor + angle*dirLights.diffuseColor.rgb;
,is always assigning res.diffuseColor to (0,0,0,0), at this point i=0, angle = 1 and dirLights[0] have values passed from application.


Pix File (500 kb)

Share this post


Link to post
Share on other sites
There were couple of issues 1) I was assigning texture to tex2 variable and using tex1 in shader 2) diffuse color was always 0.

Anyways thanks all for your help.


Method provided by belfegor works great.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement