Passing structs to shaders

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
3DModelerMan
Posts: 1691
Joined: Sun May 18, 2008 9:42 pm

Passing structs to shaders

Post by 3DModelerMan »

I have an HLSL struct that looks like this:

Code: Select all

 
struct Light
{
float4 DiffuseColor;
 
float4 SpecularColor;
 
float4 AmbientColor;
 
float4 Attenuation;
 
float OuterCone;
 
float InnerCone;
 
float Falloff;
        
float4 Position;
 
float4 Direction;
 
float Radius;
 
int LightType;
};
 
I also defined light types and a light array in the shader:

Code: Select all

 
#define MaxLights 8 
 
static int POINT = 0;
static int SPOT = 1;
static int DIRECTIONAL = 2;
 
Light lights[MaxLights];
 
I'm trying to pass this C++ struct to HLSL:

Code: Select all

 
struct Light
{
        irr::video::SColorf DiffuseColor;
 
        irr::video::SColorf SpecularColor;
 
        irr::video::SColorf AmbientColor;
 
        irr::core::vector3df Attenuation;
        float pad0;
 
        float OuterCone;
 
        float InnerCone;
 
        float Falloff;
 
        irr::core::vector3df Position;
        float pad1;
 
        irr::core::vector3df Direction;
        float pad2;
 
        float Radius;
 
        irr::u32 LightType;
};
 
I didn't decide to use the Irrlicht SLight structure because it doesn't have padding. This is how I pass the data to the shader:

Code: Select all

 
if ( UseLights && MaxLights > 0 )
        {
                irr::u32 numLights = driver->getDynamicLightCount();
 
                for (irr::u32 i=0; i<numLights; ++i)
                {
                        if ( i > MaxLights )
                                break;
 
                        //Light structure to be passed to shader
                        Light light;
                        //Irrlicht light structure (can't be directly passed because it contains no padding).
                        irr::video::SLight irrLight = driver->getDynamicLight(i);
 
                        //Copy to the padded light struct
                        light.DiffuseColor = irrLight.DiffuseColor;
                        light.SpecularColor = irrLight.SpecularColor;
                        light.AmbientColor = irrLight.AmbientColor;
                        light.Attenuation = irrLight.Attenuation;
                        light.OuterCone = irrLight.OuterCone;
                        light.InnerCone = irrLight.InnerCone;
                        light.Falloff = irrLight.Falloff;
                        light.Position = irrLight.Position;
                        light.Direction = irrLight.Direction;
                        light.Radius = irrLight.Radius;
                        light.LightType = (irr::u32)irrLight.Type;
 
                        services->setPixelShaderConstant("lights", reinterpret_cast<irr::f32*>(&light), 1);
                }
        }
 
Any idea what's wrong with it? I've never passed structs before, so I don't know if I'm supposed to be passing them in a loop or if there's a different way.
That would be illogical captain...

My first full game:
http://www.kongregate.com/games/3DModel ... tor#tipjar
3DModelerMan
Posts: 1691
Joined: Sun May 18, 2008 9:42 pm

Re: Passing structs to shaders

Post by 3DModelerMan »

Do I even need padding?
That would be illogical captain...

My first full game:
http://www.kongregate.com/games/3DModel ... tor#tipjar
Klunk
Posts: 264
Joined: Mon Jan 10, 2011 5:21 pm

Re: Passing structs to shaders

Post by Klunk »

I've no idea if that would work but shouldn't the 1 in setPixelShaderConstant be sizeof(Light)/4 ?
3DModelerMan
Posts: 1691
Joined: Sun May 18, 2008 9:42 pm

Re: Passing structs to shaders

Post by 3DModelerMan »

Oh yeah. It's the number of floats to set, not the number of variables. I forgot that part. I'll change my code when I get a chance and post back if it works.
That would be illogical captain...

My first full game:
http://www.kongregate.com/games/3DModel ... tor#tipjar
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Passing structs to shaders

Post by Mel »

Make sure that the size of each structure matches in both places. Shaders get mainly floats, And irrlichts passes floats in the constant set callbacks. (the last parameter of the constants set methods is a float*) So, technically, you can't pass integers. But that's an issue that probably can be solved if you cast the light structure address to a float*, and the size of the light structure is a multiple of the size of a float.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
3DModelerMan
Posts: 1691
Joined: Sun May 18, 2008 9:42 pm

Re: Passing structs to shaders

Post by 3DModelerMan »

I tried and it still wouldn't work. I even tried just setting a single struct instead of an array of them:

Code: Select all

 
//Light structure to be passed to shader
                Light light;
                //Irrlicht light structure (can't be directly passed because it contains no padding).
                irr::video::SLight irrLight = driver->getDynamicLight(0);
 
                //Copy to the padded light struct
                light.DiffuseColor = irrLight.DiffuseColor;
                light.SpecularColor = irrLight.SpecularColor;
                light.AmbientColor = irrLight.AmbientColor;
                light.Attenuation = irrLight.Attenuation;
                light.OuterCone = irrLight.OuterCone;
                light.InnerCone = irrLight.InnerCone;
                light.Falloff = irrLight.Falloff;
                light.Position = irrLight.Position;
                light.Direction = irrLight.Direction;
                light.Radius = irrLight.Radius;
                light.LightType = (irr::u32)irrLight.Type;
 
                services->setPixelShaderConstant("light", reinterpret_cast<irr::f32*>(&light), (sizeof(Light)/4));
 
And the shader now has this instead of a loop:

Code: Select all

 
output.Diffuse.rgb = light.DiffuseColor;
output.Diffuse.a = 1.0f;
 
That would be illogical captain...

My first full game:
http://www.kongregate.com/games/3DModel ... tor#tipjar
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Passing structs to shaders

Post by Mel »

And it still doesn work?... Well, shaders can be very tight in some matters. For instance, 4x4 matrices become 3x3 matrices when the shaders get compiled if you only use 3 components in a vector, and stuff like that. Maybe a struct can't be optimized the same, because of the potential waste of space if a variable is unused within a structure. But i can't tell for sure.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
docWild
Posts: 38
Joined: Wed Nov 30, 2011 4:29 pm

Re: Passing structs to shaders

Post by docWild »

I used to use structs all the time in C but I have no luck in using them for C++. I can't see what you're doing wrong, but what I generally do these days is use a class with public methods/attributes instead. The only real difference being that class objects are always passed by reference.
aanderse
Posts: 155
Joined: Sun Aug 10, 2008 2:02 pm
Location: Canada

Re: Passing structs to shaders

Post by aanderse »

what is the sizeof (Light) ?
Radikalizm
Posts: 1215
Joined: Tue Jan 09, 2007 7:03 pm
Location: Leuven, Belgium

Re: Passing structs to shaders

Post by Radikalizm »

I've had some issues with passing structs to hlsl shaders in the past having to do with alignment (which went beyond the simple 4 byte alignment)
DX warned me though when I tried to pass a non-aligned structure though when running a debug build and informed me about the expected size. Maybe try to run a debug build of irrlicht to see whether DX gets more verbose?

I was using DX10 though back then, don't know if it will make a difference with DX9
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Re: Passing structs to shaders

Post by serengeor »

aanderse wrote:what is the sizeof (Light) ?
I might have misunderstood your question. I think it's the size of struct/class Light, as sizeof(..) returns size in bytes.
Working on game: Marrbles (Currently stopped).
aanderse
Posts: 155
Joined: Sun Aug 10, 2008 2:02 pm
Location: Canada

Re: Passing structs to shaders

Post by aanderse »

yes sorry i wasn't clear
i meant what is the actual size of that struct for 3DModelerMan on his compiler/computer setup
i just wanted to confirm the actual size of the struct (in bytes, as you mentioned) isn't funky/unexpected due to hidden compiler padding, etc...
Post Reply