I'm trying to do lighting calculations for an array of point lights in HLSL. I simply want to pass light direction vectors from the vertex shader to the pixel shader. Here is sample code:

static const int MAXLIGHTS = 8;
float4 g_vLightPosition[MAXLIGHTS];
float4x4 mW : WorldTransform; // model to world
float4x4 mV : ViewTransform; // world to view
float4x4 mP : ProjectionTransform; // view to project

void VS_Lighting( in float4 PositionMS : POSITION0,
out float4 PositionCS : POSITION0,
out float4 Texcoord[MAXLIGHTS] : TEXCOORD )
    // view-projection
    float4x4 mVP = mul(mV, mP);

    // world position
    float4 vPosWS = mul(PositionMS, mW);

    // clip space pos
    PositionCS = mul(vPosWS, mVP);

    // compute light direction vectors
    for(int i = 0; i < g_nLightCount && i < MAXLIGHTS; ++i)
        Texcoord[i].xyz = g_vLightPosition[i] - vPosWS;

The above code forces the loop to unroll and gives the following warning:

warning X3550: array reference cannot be used as an l-value; not natively addressable, forcing loop to unroll

I would like for this code to be dynamic so as to reduce the instruction count. I understand that the problem is accessing the array in the loop. How can I rewrite this code to prevent unrolling during compilation? I am using ps 2.0 or 3.0.


2 Answers 2


You can't rewrite that loop so that it can't be unrolled. GPUs do not in general support a varying number of attributes to be passed between stages.

You can, however, eliminate the loop entirely. Just pass vPosWS to the fragment shader, and do the loop there. Then the unrolling will actually be helpful.

Bonus: You don't waste an absurd amount of bandwidth transmitting all those relative light vectors between stages just to save a few subtractions in the pixel shader. You also get per pixel lighting, rather than per vertex.

  • \$\begingroup\$ agreed thanks...however I could pass the vectors and normalize in the pixel shader and still get per-pixel lighting rather than vertex...I use a similar loop to transform light direction vectors in a bump shader...Aside from the lighting calculation though I wanted to know how to avoid the problem in general...cant be done though right? \$\endgroup\$
    – P. Avery
    Nov 17, 2014 at 23:02
  • 1
    \$\begingroup\$ You could pass the vectors, but each value you pass needs to be interpolated between the stages, which is has a relatively high cost. Unrolling is basically required on old PS 2.0 or 3.0 models, because each shader invocation needs to access the same memory; they can't diverge and do different things. \$\endgroup\$
    – user41442
    Nov 17, 2014 at 23:16

Unroll. The instruction cost is minimal - just a subtraction! You can try and put "[unroll]" (without quotes) just above the "for" line, or just unroll manually, but, really, unroll. You won't even have the comparison instruction for the for loop check.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .