# 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.

## 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 on other sites
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 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 on other sites

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 on other sites
Quote:
 Original post by JiiaBy 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 JiiaDamn, 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 on other sites
Quote:
 Original post by CoderPerhaps 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 JiiaDamn, 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 on other sites
Quote:
 Original post by JiiaI 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 on other sites
Quote:
Original post by EvilDecl81
Quote:
 Original post by JiiaI 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.

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 15
• 22
• 16
• 13
• 14