Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm doing a little 2D game in C++ with Direct3D 11.

In the game I want to render a sort of shadow that covers part of the screen:

pict.1

To do this I am using this pixel shader:

float4 PS_Main( PS_Input frag) : SV_TARGET 
{
    float4 color = {0, 0, 0, 1};
    for (int cont=0; cont<lights; cont++)
    {
        int dist = pow(frag.pos[0] - singleLight[cont][0], 2) + pow(frag.pos[1] - singleLight[cont][2], 2);

        if (dist < singleLight[cont][3] * singleLight[cont][4])
        {
            color[3] -= 1 - (dist / (singleLight[cont][5] * singleLight[cont][6]));
        }
    }

    return color;
};

The constant buffer I pass to the shader is:

cbuffer PSbuffer : register( b0 )
{
    int lights;
    float4 singleLight[15];
};

I also pass an array to the shader, each element of which contains the position and radius of a light.

The code works with more than one light, but if I try to use more than ten lights the FPS drops down to 40 or 50. How can I optimize this effect?

pict.2

Thank to all!! I try to optimize the pixel shader code but i earn 4-5 fps so i decide to to a "light map" in this way; I create a second Render Target View i will use to render the lights(sprite i draw). The light will be alpha-channel inverted in order to have to clear the render target view with color{0,0,0,0}; draw the light on the second target view like this:pict.3 and then create a texture with this render target view and render it on the first with a shader that invert the alpha channel (color.a=1-color.a); but, since i am new in directx i dont now how to do it and i cant find a good tutorial.Can you help me??

share|improve this question

marked as duplicate by Josh Petrie Jan 3 at 16:56

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
Please don't edit your question to include a significantly new or extended question after the fact; for that you should post a new question, although in both the case of your original and updated question I think the linked duplicate is appropriate. –  Josh Petrie Jan 3 at 16:57
add comment

2 Answers 2

up vote 1 down vote accepted

You could create a (low-resolution) "light map" in which you render your "lights" and then do a simple postprocessing pass in which you multiply both sources.

Loops in shaders tend to become expensive very quickly.

As a short term improvement: Try removing the if, at first glance it looks easy to replace.

Jumps (including ifs) are also expensive.

share|improve this answer
add comment

A few comments:

  • is frag.pos[1] - singleLight[cont][2] correct? I think you want [1] here.
  • pow(x, 2) is not guaranteed to be understood as x * x and might therefor be slow.
  • avoid if() when what’s inside is not very complex, try to use min, max, clamp etc.

Here is how I'd rewrite the shader:

float4 PS_Main( PS_Input frag) : SV_TARGET 
{
    float4 color = {0, 0, 0, 1};
    for (int cont = 0; cont < lights; cont++)
    {
        float2 V = frag.pos.xy - singleLight[cont].xy;
        float K = 1.0 / (singleLight[cont][2] * singleLight[cont][2]);
        color.a -= max(1.0 - K * dot(V, V), 0.0);
    }

    return color;
};

Final note: if all you’re going to do with singleLight[cont][2] is compute that value K, you should precompute K on the CPU instead. That’s one more computation on the CPU, but several million fewer divisions on the GPU. The fragment shader would then be:

float4 PS_Main( PS_Input frag) : SV_TARGET 
{
    float4 color = {0, 0, 0, 1};
    for (int cont = 0; cont < lights; cont++)
    {
        float2 V = frag.pos.xy - singleLight[cont].xy;
        color.a -= max(1.0 - dot(V, V) * singleLight[cont][2], 0.0);
    }

    return color;
};
share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.