Sign in to follow this  
brekehan

HLSL - dynamic array size?

Recommended Posts

I am going to, reword my question from a previous thread, in hope of being more descriptive and getting an answer. Is there a way to create an array of variables in HLSL of undetermined size? something like an std::vector<myvar> vars; ??? In the MSDN light example:
// Application Code
//
// Update lighting variables
//
g_pLightDirVariable->SetFloatVectorArray( (float*)vLightDirs, 0,    2 );
g_pLightColorVariable->SetFloatVectorArray( (float*)vLightColors, 0,    2 );

// Shader Code
//
// Pixel Shader
//
float4 PS( PS_INPUT input) : SV_Target
{
   float4 finalColor = 0;
        
   //do NdotL lighting for 2 lights
   for(int i=0; i<2; i++)
   {
      finalColor += saturate( dot( (float3)vLightDir[i],input.Norm) * vLightColor[i] );
   }
      return finalColor;
}
You see that they depend on there only being 2 lights. What if I wanted to use the same shader for any number of lights? Or am I forced to make a decision on a maximum number of lights and come up a way of determining if only x number were set and y number are unitialized?

Share this post


Link to post
Share on other sites
No dynamic arrays in HLSL unfortunately.

For a multi-light combination you should be fine with pre-baking values using techniques and/or multi-passing the rendering.

Unless you're really tight for constant registers you can define a maximum size array - say 8 elements and then use uniform parameters in your shader code to determine how many iterations are performed. If you want 4 lights then you fill up the first 4 slots and ignore the last 4 for example.

Typically this will work fine as most real-time scenarios have only a handful of active and relevant lights so you can keep the possible combinations to a reasonable number.

If you need more than this you can add multi-pass on top, so for a shader that can handle up to 8 lights in a pass (as per my previous example) you could run 3 passes should you have between 16 and 24 active lights.

It can be interesting to dynamically explore the balance between lights per pass and total number of passes. The overhead versus the shader complexity can lead to different results for different chipsets.

hth
Jack

Share this post


Link to post
Share on other sites
If you're using the effect framework, you can use multiple techniques and uniform variables to auto-generate a series of shaders for you. Here's a simple example:


const static int MAX_LIGHTS = 4
float3 vLightDirs[MAX_LIGHTS];
float3 vLightColors[MAX_LIGHTS];

float4 PS( PS_INPUT input, uniform int iNumLights ) : COLOR0
{
float3 vColor = 0;

for(int i=0; i<iNumLights ; i++)
vColor += saturate(dot(vLightDir[i], input.Norm) * vLightColor[i]);


return float4(vColor, 1.0f);
}

technique 1Light
{
pass p0
{
VertexShader = compile vs_3_0 VS();
PixelShader = compile ps_3_0 PS(1);
}
}

technique 2Light
{
pass p0
{
VertexShader = compile vs_3_0 VS();
PixelShader = compile ps_3_0 PS(2);
}
}

// and so on...

Share this post


Link to post
Share on other sites
I have yet to delve into multipasses.

Do you have any resources you can share on how multiple passes are achieved and work together?

I understand the concept, but not the details.

Share this post


Link to post
Share on other sites
Quote:
Original post by brekehan
I have yet to delve into multipasses.

Do you have any resources you can share on how multiple passes are achieved and work together?

I understand the concept, but not the details.


For multipass you render an object with your light shader exactly as normal. The only thing you have to do is disable blending on the first pass, then enable additive blending on all subsequent passes with the same mesh. You'll also want to make sure that the ambient term is only added once.


for each mesh being rendered
for each light affecting the mesh
if (first light)
render first light with ambient and no blending
else
render nth light with no ambient and additive belnding

Share this post


Link to post
Share on other sites
Quote:
Original post by Dunge
Uniform is a constant? I understand the number of light remain constant in one shader pass, but why put the emphasis on it?


The values are not calculated per vertex or per pixel, so they are constant in the context of one draw call.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dunge
I'm not the original thread author but the subject interest me. I understand multipass, but from your multiple technique example it seems as if it wouldn't be needed, just use the correct technique for the correct number of lights no?


Yes that's the exact purpose of writing your effect that way: handling multiple lights in one pass. When you specify a uniform variable in a technique, the effect compiler then knows that this value will be constant as far as that technique is concerned and will compile a version of the shader for that technique with that in mind. This means no branching or dynamic loops or anything like that is needed...it can just unroll the loop (or use a loop with a constant number of iterations).

This is an extremely useful feature of the effect compiler, as it lets you use one set of shader code to create several permutations. I like to use it for creating several gaussian blur shaders with various radii, or to control whether I encode the output to a certain HDR format.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this