XNA Creators Club Online
Page 1 of 1 (4 items)
Sort Posts: Previous Next

Optimization help sought for pixel shader code - plenty of sin math

Last post 10/15/2009 7:54 PM by Magesterium. 3 replies.
  • 10/11/2009 8:06 PM

    Optimization help sought for pixel shader code - plenty of sin math

    Having only just started playing about with pixel shaders, and not fully understanding all the functions yet. Can someone give me a few pointers on how I can optimize the following bit of shader code. I am currently using to many arithmetic slots for shader 2.0 and I would prefer to keep to shader 2.0 if possible.
    The effect I am looking for is a wavy water effect, the attempt I have made still isn't ideal as it is still a bit too uniform in appearance.

    Input = offset value to maintain the effect while the screen scrolls. (float2)
    External = Radians that cycle. (float)
    xWaveLength1 , 2 etc = Variable to adjust the wave effect (float), I usually set these between 30 - 50.
    xWaveVar1 ,2 etc = as above (float), I usually set these between 0.5 - 2.5.

    I also shade the waves for a bit of a lighting effect.

    Its probably really obvious, but I just can't see it yet (the optimization I need to do that is)
    If you have any tips on less uniform wave patterns I would appreciate the advice.

    float4 PixelShaderFunction(float2 Tex : TEXCOORD0) : COLOR0 
    Tix.x = Tex.x + (Input.x/640); 
    Tix.y = Tex.y + (Input.y/480); 
    TexAdjustX1 = (Tix.x -(sin(Tix.y))+ sin(External * xWaveLength1))*xWaveVar1; 
    TexAdjustX2 = (Tix.x-(Tix.y*0.33) + sin(External * xWaveLength2))*xWaveVar2; 
     
    TexAdjustY1 = (Tix.y -(cos(Tix.x))+ sin(External * yWaveLength1))*yWaveVar1; 
    TexAdjustY2 = (Tix.y-(Tix.x*0.75) - sin(External * yWaveLength2))*yWaveVar2; 
     
    TexAdjustY1 = sin(TexAdjustY1)+sin(TexAdjustY2); 
    TexAdjustX1 = sin(TexAdjustX1)+sin(TexAdjustX2);     
        Tex.y = Tex.y + 
            ( 
                TexAdjustY1 
            ) * 0.01f; 
        Tex.x = Tex.x + 
            ( 
                TexAdjustX1 
            ) * 0.01f; 
        color = tex2D(TextureSampler, Tex); 
        color.a = color.a * 0.75; 
        color.r += 0.03 * 
            ( 
                TexAdjustY1 
                + 
                TexAdjustX1 
            ); 
        color.g += 0.04* 
            ( 
                TexAdjustY1 
                + 
                TexAdjustX1 
            ); 
        color.b += 0.05* 
            ( 
                TexAdjustY1 
                + 
                TexAdjustX1 
            ); 
        return color; 
         

  • 10/12/2009 12:41 AM In reply to

    Re: Optimization help sought for pixel shader code - plenty of sin math

    You could probably offload some of that to the vertex shader, but I'm not sure exactly what by looking at it as I've spent the whole day staring at nasty shader code already and my brain's fried.

    However, you're probably better served by using a texture look-up for the sin's. Generate it with a bit of code doing a loop and read it by setting your texture U coordinate to be the value you want, scaled appropriately. Allowing bilinear filtering will even give you some interpolation which will be techinically innacurate but more than serviceable if your texture has a good resolution to start with.

    If you want absolutely max comptibility, you'll have to store your sin's normalised as colours in an RGBA texture, possibly stretching over a couple of the components and there's source on the web showing how to do that. But assuming your own machine can make an R32F type texture, use that to get it all working first as you can just put floats in it unmolested.
    Paul Johnson - CEO of rubicondev.com, speaking for myself.
  • 10/12/2009 1:14 AM In reply to

    Re: Optimization help sought for pixel shader code - plenty of sin math

    Tix.x = Tex.x + (Input.x/640);    
    Tix.y = Tex.y + (Input.y/480);   
     

    That can go into the Vertex Shader (they are constant for each pixel, apart from the interpolated input value, so you may as well move the math to the vertex level, and interpolate post-math, you run the maths heaps less). In fact you might be able to do it in your C# code (once per draw).

    sin(External * xWaveLength1))*xWaveVar1; 

    You can probably move this term, and others like it, up to the Vertex Shader, or even CPU level, as well.

    You get the picture though - anything that involves constants and values that can be interpolated linearly should be done at the vertex shader level (the compiler will take care of expressions which only involve constants / parameters, and it will automatically move them out of the vertex shader to become a per-draw operation, I believe they call this a pre-shader).

    Things that shouldn't be done at the vertex shader level, are things like calling sin(x) where x should be a per pixel value. Obviously, if you call it at the vertex level it will get interpolated, and this won't look right.
    I'm too busy writing computer graphics for my day job to have any games in play-test or peer-review.
    Twitter: twitter/guysherman
    Blog: www.guysherman.com
  • 10/15/2009 7:54 PM In reply to

    Re: Optimization help sought for pixel shader code - plenty of sin math

    Thank you for your suggestions, they are much appreciated.
    I am applying the shader to a texture I have captured from drawing a combination of textures to the back buffer, so in effect a single 2D screen sized image.

    As I have been working only in 2D, I have only really dabbled in pixel shaders, is it possible to apply a vertex shader to a single flat 2D image? I am assuming that a single 2D image is made up of only 2 triangles.

    Would it be reasonable to sandwich a vertex heavy mesh for creating a water effect between layers of 2D images? I have been considering this option, however my TileEngine currently uses a fairly simple process for generating the water tiled areas and it allows me to smooth the corners, removing the blocky appearence. If I were to use a mesh I would need to change the mesh as the screen scrolls, or use a camera to scroll the screen.

    How it all looks currently. The land and character images are only place holder images, until I get my own graphics in. Visually very RMXP inspired at the moment.
Page 1 of 1 (4 items) Previous Next