Jump to content
  • Advertisement
Sign in to follow this  
Jiia

HLSL (NumBones * NumLights)

This topic is 5461 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 no idea what I'm doing here, but I've managed to poke around and get multiple lights and bones going at the same time. I'm just wondering if there is a better way to do this. Keep in mind that until about 10 minutes ago, I've always had a single light. So now I have up to 4 lights and 4 bones. In other words, I've jumped into the really deep section of the pool.
vSkinOutput vsMethod_Skin(vSkinInput v_in, uniform int nBones, uniform int nLights)
{
...
}

...

int CurNumBones = 2;
int CurNumLights = 1;

...

VertexShader vs_Skin_HW[ 16 ] = {   compile vs_1_1 vsMethod_Skin( 1, 1 ),
                                    compile vs_1_1 vsMethod_Skin( 2, 1 ),
                                    compile vs_1_1 vsMethod_Skin( 3, 1 ),
                                    compile vs_1_1 vsMethod_Skin( 4, 1 ),
                                    compile vs_1_1 vsMethod_Skin( 1, 2 ),
                                    compile vs_1_1 vsMethod_Skin( 2, 2 ),
                                    compile vs_1_1 vsMethod_Skin( 3, 2 ),
                                    compile vs_1_1 vsMethod_Skin( 4, 2 ),
                                    compile vs_1_1 vsMethod_Skin( 1, 3 ),
                                    compile vs_1_1 vsMethod_Skin( 2, 3 ),
                                    compile vs_1_1 vsMethod_Skin( 3, 3 ),
                                    compile vs_1_1 vsMethod_Skin( 4, 3 ),
                                    compile vs_1_1 vsMethod_Skin( 1, 4 ),
                                    compile vs_1_1 vsMethod_Skin( 2, 4 ),
                                    compile vs_1_1 vsMethod_Skin( 3, 4 ),
                                    compile vs_1_1 vsMethod_Skin( 4, 4 )};

VertexShader vs_Skin_SW[ 16 ] = {   compile vs_2_sw vsMethod_Skin( 1, 1 ),
                                    compile vs_2_sw vsMethod_Skin( 2, 1 ),
                                    compile vs_2_sw vsMethod_Skin( 3, 1 ),
                                    compile vs_2_sw vsMethod_Skin( 4, 1 ),
                                    compile vs_2_sw vsMethod_Skin( 1, 2 ),
                                    compile vs_2_sw vsMethod_Skin( 2, 2 ),
                                    compile vs_2_sw vsMethod_Skin( 3, 2 ),
                                    compile vs_2_sw vsMethod_Skin( 4, 2 ),
                                    compile vs_2_sw vsMethod_Skin( 1, 3 ),
                                    compile vs_2_sw vsMethod_Skin( 2, 3 ),
                                    compile vs_2_sw vsMethod_Skin( 3, 3 ),
                                    compile vs_2_sw vsMethod_Skin( 4, 3 ),
                                    compile vs_2_sw vsMethod_Skin( 1, 4 ),
                                    compile vs_2_sw vsMethod_Skin( 2, 4 ),
                                    compile vs_2_sw vsMethod_Skin( 3, 4 ),
                                    compile vs_2_sw vsMethod_Skin( 4, 4 )};

..

technique t_Skin_HW
{
    pass p0
    {
        VertexShader = ( vs_Skin_HW[ (CurNumLights * 4) + CurNumBones ] );
    }
}

technique t_Skin_SW
{
    pass p0
    {
        VertexShader = ( vs_Skin_SW[ (CurNumLights * 4) + CurNumBones ] );
    }
}




Wow, what a freakin mess, eh? Can I use a loop or something here? Is there a better way to accomplish this? I need to read up on this stuff, but poking is a lot more fun. Let me know if anyone knows a way to make this slightly more attractive or just simply better. Thanks for any advice [smile] EDIT: Oh yeah, one other thing. I picked up on how to do this from the multi-animation sample. They had something like..
VertexShader vs_Norm_HW[ 4 ] =
{ compile vs_1_1 vsMethod_Norm( 1 ),
  compile vs_1_1 vsMethod_Norm( 2 ),
  compile vs_1_1 vsMethod_Norm( 3 ),
  compile vs_1_1 vsMethod_Norm( 4 ) };

...

technique t_Norm_HW
{
    pass p0
    {
        VertexShader = ( vs_Norm_HW[ CurNumBones ] );
    }
}



The thing I don't get is, how is [CurNumBones == 1] grabbing the 0 index of the array? Bah, I mean if CurNumBones is 1, and vs_Norm_HW[ 0 ] is using 1 bone, how is vs_Norm_HW[ CurNumBones ] grabbing vs_Norm_HW[ 0 ]? This part is throwing me off. Thanks again.

Share this post


Link to post
Share on other sites
Advertisement
You could use the fragment linker.

Create a non-boned world transform
Create a 4 boned world transforms (for 1-4 bones)
Create n directional light fragments
Create n point light fragments

In code, link the fragments to create the shader based on the context it's needed. This, using your example, you make 4 bone fragments, and 4 lights fragments, then link them. This is 8 fragmnets instead of 16 shaders.

This becomes more important when you start dealing with direction vs. point lights, fog, texture coordinate setup, and more. If you add fog, you'll need another 16 variants, for a total 32 shader variants. With the linker we need 1 more fragment, for a total of 9.

The more extra details you want to support, the better the fragment linker is, needing just one, two, three or four more section, instead of doubling, tripling, or quadrupling your shader count.

Share this post


Link to post
Share on other sites
Ahh, Fragments. Thanks much for the point in the right direction.

By the way, what about the other thing? The index 1 grabbing array 0 thing? This is totally messing with me. Why does it grab index 0 when CurNumLights is 1? It seems like I should be saying VertexShader = ( vs_Norm_SW[ CurNumLights - 1 ] ); rather than VertexShader = ( vs_Norm_SW[ CurNumLights ] ); See what I'm saying? vs_Norm_SW[ 0 ] uses 1 light. vs_Skin_SW[ 0 ] uses 1 bone.

Damn, I can't rate you. Already have ya maxed out. Someone give Name a rating for me? [smile]

Share this post


Link to post
Share on other sites
Your 16 shaders are in an array, like so:

vsMethod_Skin( 1, 1 ),
vsMethod_Skin( 2, 1 ),
vsMethod_Skin( 3, 1 ),
vsMethod_Skin( 4, 1 ),
vsMethod_Skin( 1, 2 ),
vsMethod_Skin( 2, 2 ),
...

You're using (bones + lights*4) to index into that array.
Array entry 0 (0 bones + 0 lights) says "vsMethod_Skin( 1, 1 )", or 1 bone and 1 light.

If you were to allow 0 to 4 bones and 0 to 4 lights, then you'd have 25 permutations to enter into your array, but the numBones and numLights would start to make sense.

ie:
vsMethod_Skin( 0, 0 );
vsMethod_Skin( 1, 0 ),
vsMethod_Skin( 2, 0 ),
vsMethod_Skin( 3, 0 ),
vsMethod_Skin( 4, 0 ),
vsMethod_Skin( 0, 1 ),
vsMethod_Skin( 1, 1 ),
vsMethod_Skin( 2, 1 ),
...

Share this post


Link to post
Share on other sites
Quote:
Original post by Jiia
By the way, what about the other thing? The index 1 grabbing array 0 thing? This is totally messing with me. Why does it grab index 0 when CurNumLights is 1? It seems like I should be saying VertexShader = ( vs_Norm_SW[ CurNumLights - 1 ] ); rather than VertexShader = ( vs_Norm_SW[ CurNumLights ] ); See what I'm saying? vs_Norm_SW[ 0 ] uses 1 light. vs_Skin_SW[ 0 ] uses 1 bone.

Perhaps CurNumBones ranges from 0 to 3 inclusive, instead of 1 to 4?

Quote:
Original post by Jiia
Damn, I can't rate you. Already have ya maxed out. Someone give Name a rating for me? [smile]

Can't do - already maxed him out when the rating system came out. Since then, I regularly forget and try to rate him up every now and then. The only complaint one can have against him is the not-so-finger-friendly nick...[grin]
However, we now just say ntnet, so it's not a problem. I still remember the days when I used to fully type out his name, though...

Share this post


Link to post
Share on other sites
Quote:
Original post by Coder
Perhaps CurNumBones ranges from 0 to 3 inclusive, instead of 1 to 4?

Ah, you're probably right. Actually, that's the only thing that makes sense. That means one of my lights are on and I just haven't set it's values to see it. I think I need to change the names of those two variables. LastLight? HighestIndexLight? hehe. Maybe a minus 1 would look better.

Quote:
Original post by Coder
Quote:
Original post by Jiia
Damn, I can't rate you. Already have ya maxed out. Someone give Name a rating for me? [smile]

Can't do - already maxed him out when the rating system came out. Since then, I regularly forget and try to rate him up every now and then. The only complaint one can have against him is the not-so-finger-friendly nick...[grin]
However, we now just say ntnet, so it's not a problem. I still remember the days when I used to fully type out his name, though...

Hahaha, ntnet. Sounds like a MS logo.

Thanks for the help!

Share this post


Link to post
Share on other sites
Quote:
Original post by Jiia
I have no idea what I'm doing here, but I've managed to poke around and get multiple lights and bones going at the same time. I'm just wondering if there is a better way to do this. Keep in mind that until about 10 minutes ago, I've always had a single light. So now I have up to 4 lights and 4 bones. In other words, I've jumped into the really deep section of the pool.



An Alternative to the fragment linker is to use EffectCompiler to produce n differnt versions of your technique. Basically, the psuedocode would look something like (sorry, don't remember all the arguments exactly):

Compiler = D3DXCreateEffectCompiler("myfile.fx")
Compiler->SetLiteral("CurNumBones", TRUE);
Compiler->SetLiteral("CurNumLights", TRUE);

for(int i = 0;i < 4;i++)
{
for(int j = 0;j < 4;j++)
{
Compiler->SetInt("CurNumBones", i);
Compiler->SetInt("CurNumLights", j);
Effect[j] = Compiler->CompileEffect(...);
}
}



Share this post


Link to post
Share on other sites
Quote:
Original post by EvilDecl81
Quote:
Original post by Jiia
I have no idea what I'm doing here, but I've managed to poke around and get multiple lights and bones going at the same time. I'm just wondering if there is a better way to do this. Keep in mind that until about 10 minutes ago, I've always had a single light. So now I have up to 4 lights and 4 bones. In other words, I've jumped into the really deep section of the pool.



An Alternative to the fragment linker is to use EffectCompiler to produce n differnt versions of your technique. Basically, the psuedocode would look something like (sorry, don't remember all the arguments exactly):

Compiler = D3DXCreateEffectCompiler("myfile.fx")
Compiler->SetLiteral("CurNumBones", TRUE);
Compiler->SetLiteral("CurNumLights", TRUE);

for(int i = 0;i < 4;i++)
{
for(int j = 0;j < 4;j++)
{
Compiler->SetInt("CurNumBones", i);
Compiler->SetInt("CurNumLights", j);
Effect[j] = Compiler->CompileEffect(...);
}
}


BTW, SetLiteral tells the compiler to reinterpret a variable as a literal, thereby 'inlineing' code. This is a good way to produce lots of permutations of a shader.

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!