Sign in to follow this  
YanickSalzmann

[XNA] Skysphere kills performance

Recommended Posts

YanickSalzmann    102
Ahoi

As the title says im rendering the sky as an untextured sphere and calculate the color depending on the angle of every pixel. While the results on the screen are very satisfying i have some problems with the performance. If I render the scene without the sky i get framerates up to 100 (with VSync turned off in fullscreen and 1280x1024) and if i render the sky it drops to about 30 - 40 FPS. The scene looks like that:
http://sv1.imagefire.net/image/4c03b4da18e3.png



I could see that the problem is what happens in the pixel shader because when i return a default color there without calculations i get no loss in framerate. The pixel shader is like:
[code]

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float3 diff = input.PosOld;
float2 diffXZ = diff.xz;
float dist = 300;
float angle = 0;
if(dist == 0)
{
if(diff.y < 0)
angle = -90;
else
angle = 90;
}
else
{
float sinx = diff.y / dist;
angle = atan(sinx) * 180.0f / 3.1415926;
}

if(angle > 90)
angle = 90;
else if(angle < -90)
angle = -90;

float4 color = float4(1, 1, 1, 1);

if(angle >= -90 && angle < -45)
{
float s = (angle + 90) / 45;
color = lerp(colorLow, colorMidLow, s);
}
else if(angle >= -45 && angle < -5)
{
float s = (angle + 45) / 40;
color = lerp(colorMidLow, colorMid, s);
}
else if(angle >= -5 && angle < 30)
{
float s = (angle + 5) / 35;
color = lerp(colorMid, colorMidHigh, s);
}
else if(angle >= 30 && angle < 60)
{
float s = (angle - 30) / 30;
color = lerp(colorMidHigh, colorHigh, s);
}
else if(angle >= 60 && angle < 90)
{
float s = (angle - 60) / 30;
color = lerp(colorHigh, colorTop, s);
}
return color;
}
[/code]

Problems start with the first if that includes the angle. If i return before that i also get the same FPS like no sky is rendered.

Is it normal that this drops fps to nearly 30% of the original? Or is there something that is wrong that causes that loss?

Thank you for any advice
Yanick

Share this post


Link to post
Share on other sites
YanickSalzmann    102
Ok, ive implemented this and the sky shader now is very simple:
[code]

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float3 diff = input.PosOld;
float2 diffXZ = diff.xz;
float dist = 300;
float angle = 0;
float sinx = diff.y / dist;
angle = atan(sinx) * 180.0f / 3.1415926;

angle = min(max(angle, -90), 90);

return float4(1, 1, 1, 1); //tex2D(ColorSampler, float2((angle + 90) / 180.0f, 0.0f));
}
[/code]

Gain: ~2 FPS not more. Why is that? The texture lookup absolutely kills the performance now...

Share this post


Link to post
Share on other sites
unbird    8338
Welcome to the forum.

[quote]The texture lookup absolutely kills the performance now[/quote]
It's not the lookup alone, you misjudge your last snipped: Returning just a constant color will compile to one instruction only, since the compiler will strip out everything that is not needed.

Not sure if it's your only bottleneck but using atan generates a lot of instructions (about 20), so I recommend using a simpler mapping to reduce the instruction count in your pixel shader (e.g. normalize your 2D viewing direction and map "up" from [-1,1] to [0,1]).

To get a feeling for the compiler I recommend looking at the shader assembly. Can't remember if you can get a disassemble from XNA, but you can use the command line compiler fxc: Install the DirectX SDK and compile your effects offline:

[code]
fxc.exe /Zi /T fx_2_0 /Fx skysphere.asm skysphere.fx
[/code]
This will generate a assembly listing skysphere.asm from your effect file skysphere.fx. The /Zi option will also include debugging information (line numbers, this makes it easier to identify parts of your original code).

It's not essential to understand shader assembly completely - actually it's pretty hard to read - but it will give you a estimate for the amount of instructions generated. At the end of each shader you get something like this:

[code]
// approximately 27 instruction slots used (1 texture, 26 arithmetic)
[/code]

Share this post


Link to post
Share on other sites
YanickSalzmann    102
Ahh, i see i removed the atan and did the following:
[code]

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float3 diff = input.PosOld;
float viewDist = 400.0f; // TODO: replace by variable that holds dynamic view distance

float coordTmp = diff.y / viewDist;
float coord = (coordTmp + 1) / 2.0f;

return tex1D(ColorSampler, coord);
}
[/code]

That gives the correct results and now it renders like a charm!


Thanks for the tip i forgot that the shader compiler also has an optimizer :D

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