0
votes

I'm trying to optimize my terrain shader for my XNA game as it seems to consume a lot of ressources. It takes around 10 to 20 FPS on my computer, and my terrain is 512*512 vertices, so the PixelShader is called a lot of times.

I've seen that branching is using some ressources, and I have 3/4 conditions in my shaders. What could I do to bypass them? Are triadic operators more efficient than conditions?

For instance:

float a = (b == x) ? c : d;

or

float a;
if(b == x)
    a = c;
else
    c = d;

I'm using also multiple times the functions lerp and clamp, should it be more efficient to use arithmetic operations instead?

Here's the less efficient part of my code:

    float fog;
    if(FogWaterActivated && input.WorldPosition.y-0.1 < FogWaterHeight)
    {
        if(!IsUnderWater)
            fog = clamp(input.Depth*0.005*(FogWaterHeight - input.WorldPosition.y), 0, 1);
        else
            fog = clamp(input.Depth*0.02, 0, 1);

        return float4(lerp(lerp( output * light, FogColorWater, fog), ShoreColor, shore), 1);
    }
    else
    {
        fog = clamp((input.Depth*0.01 - FogStart) / (FogEnd - FogStart), 0, 0.8);
        return float4(lerp(lerp( output * light, FogColor, fog), ShoreColor, shore), 1);
    }

Thanks!

1
I had a bunch of if statements in a shader I wrote, and I got around 20fps. Then I removed the if statements and used an alpha map, and got 60fps easy. I would try replacing my if statements with maybe something like an alpha map, and see if that helps. (Or try commenting the if statements out to see if there's a big difference.)davidsbro
Are FogWaterActivated and IsUnderWater global shader parameters? If so you could remove the conditionals and implement your different code paths as different shader techniques.Cole Campbell
Thanks for this idea! I'm a newbie with HLSL and I hadn't thought about it. Indeed theses 2 parameters are global, so do you think I should create 4 techniques for each cases (fog&&underwater, !fog&&underwater, fog&&!underwater, !fog&&!underwater)?Adrien Neveu
I can't say whether you should or not; I can only say that doing so will allow you to remove several of your conditionals. Try it and measure the result!Cole Campbell
Thanks. I didn't gained a lot of FPS, but it still worth it. I have another question, I have two "lerps" here: float4(lerp(lerp( output * light, FogColorWater, fog), ShoreColor, shore), 1); Do you think there's some kind of a trick to use only one for the same effect?Adrien Neveu

1 Answers

1
votes

Any time you can precalculate operations done on shader constants the better. Removing division operations by passing through the inverse into the shader is another useful tip as division is typically slower than multiplication.

In your case, precalculate (1 / (FogEnd - FogStart)), and multiply by that on your second-last line of code.