Xbox LIVE Indie Games
Sort Discussions: Previous Discussion Next Discussion
Page 1 of 1 (20 posts)

Converting old 2D water code to HLSL?

Last post 5/15/2015 4:03 PM by DrRage88. 19 replies.
  • 11/17/2008 5:30 AM

    Converting old 2D water code to HLSL?

    Hello, I was wondering if anybody would be able to assist in converting the code found here to HLSL. I was hoping to use it for a simpler method of rendering ripples then a full blown fluid solver, and though I have been able to get it working on the CPU (with a bunch of 1x1 textures and float arrays) the speed is understandably horrible for large textures. As such I figured I'd make a shader, unfortunately my ping-ponging textures (which I think are needed) end up getting a wierd streaking effect on them, or worse - the color simply bleeds across the screen. Any help would be greatly appreciated, thanks!

  • 11/17/2008 11:27 PM In reply to

    Re: Converting old 2D water code to HLSL?

    You need to set up a kind of feedback loop where the previous frame is fed back into the shader for the next frame. You can do this by rendering each frame into a renderTarget2D and then get the texture. You can then render this texture to the backbuffer so you can see it and then you put it into the parameter of the shader for the next frame.

    What is the exact problem you're having? Could you post your HLSL?

  • 11/18/2008 2:18 AM In reply to

    Re: Converting old 2D water code to HLSL?

    Well the problem that I am getting is that the colors just seem to bleed or blur across the texture. An example would be that if I place a white dot in the middle of the texture, it will just continually expand until the entire screen is white. I've managed to fix this by changing my mip, min and max filters to use linear instead of none. But the 'fix' can hardly be called that as it just blurs in one direction (causes a streak towards the bottom right of the texture) but it does fade out over time. My HLSL code is below, and should be self-explanatory (particularly if you read the page I linked), BufferOne starts off with the ripple data, BufferTwo starts off blank, this shader smoothes/spreads out the ripples and stores the result in BufferTwo. Then in my post-processor code I swap the data of BufferOne and BufferTwo. Meaning that the output of the shader, becomes the new input.

    float myDamping = 0.4f;  
    float myPixelWidth;  
    float myPixelHeight;  
     
    Texture myBufferOne;  
       
    sampler samplerBufferOne = sampler_state {   
    texture = <myBufferOne>;  
     magfilter = NONE;   
     minfilter = NONE;   
     mipfilter = NONE;   
     AddressU = clamp;   
     AddressV = clamp;  
    };  
     
    Texture myBufferTwo;  
       
    sampler samplerBufferTwo = sampler_state {   
    texture = <myBufferTwo>;  
     magfilter = NONE;   
     minfilter = NONE;   
     mipfilter = NONE;   
     AddressU = clamp;   
     AddressV = clamp;  
    };  
     
     struct VS_INPUT   
     {   
        float4 Position : POSITION0;  
        float2 Texcoord : TEXCOORD0;  
     };  
       
     VS_INPUT VertexShader(VS_INPUT Input)  
     {   
        VS_INPUT Output;  
        Output.Position = Input.Position;  
        Output.Texcoord = Input.Texcoord;  
        return Output;   
     }   
           
     float4 PixelShader(VS_INPUT Input) : COLOR0  
     {                      
        float bufferOneLeft = tex2D(samplerBufferOne, float2(Input.Texcoord.x-myPixelWidth, Input.Texcoord.y)).r;  
        float bufferOneRight = tex2D(samplerBufferOne, float2(Input.Texcoord.x+myPixelWidth, Input.Texcoord.y)).r;  
        float bufferOneUp = tex2D(samplerBufferOne, float2(Input.Texcoord.x, Input.Texcoord.y-myPixelHeight)).r;  
        float bufferOneDown = tex2D(samplerBufferOne, float2(Input.Texcoord.x, Input.Texcoord.y+myPixelHeight)).r;  
          
        float bufferTwo = tex2D(samplerBufferTwo, Input.Texcoord).r;  
          
        bufferTwo = (bufferOneLeft + bufferOneRight + bufferOneDown + bufferOneUp) / 2 - bufferTwo;  
        bufferTwo *= myDamping;  
         
        if (Input.Texcoord.x < myPixelWidth || Input.Texcoord.y < myPixelHeight || Input.Texcoord.x > (1.0f - myPixelWidth) || Input.Texcoord.y > (1.0f - myPixelHeight))  
        {  
            return 0;  
        }  
        else 
        {  
            return float4(bufferTwo, bufferTwo, bufferTwo, 1);  
        }  
     }   
            
     technique WaterTexture   
     {  
        pass P0   
        {  
            VertexShader = compile vs_2_0 VertexShader();  
            PixelShader = compile ps_2_0 PixelShader();   
        }   
     }  
     
  • 11/18/2008 11:08 AM In reply to

    Re: Converting old 2D water code to HLSL?

    This is what I do in my density smooth,

    float4 c = 0;  
          
        // Combine a number of weighted image filter taps.  
        for (int i = 0; i < SAMPLE_COUNT; i++)  
        {  
            c += tex2D(Buffer2Sampler, texCoord + SampleOffsets[i]);  
        }  
          
        c = c/2;  
        c -= tex2D(Buffer1Sampler,texCoord);  
        c = c*damping;  
        c=clamp(c, -1.5,1.5);  
        return c;  
     
  • 11/18/2008 3:24 PM In reply to

    Re: Converting old 2D water code to HLSL?

    Thank you for the help, after a lot of searching I found my problem to be in my swapping textures effect. I was using one rendertarget for doing the swapping, but apparently I was overwriting this texture before I could finish the swap. So while it wasn't actually a problem with my smoothing code, its good to see how someone else would do it (I hadn't thought of using a for loop, which is much easier to read/modify). Though I'm a little unsure as to why you clamp it between -1.5 and 1.5?
  • 11/19/2008 4:15 AM In reply to

    Re: Converting old 2D water code to HLSL?

    Hi, I managed to replicate the problem you had earlier with the increasing white space. I'm struggling to come up with the rest. Do you have the code working? I don't understand why the ripples constantly move to the bottom right of the screen.
  • 11/19/2008 7:08 AM In reply to

    Re: Converting old 2D water code to HLSL?

    Good to see I'm not the only one with that problem, if you use the code from my 2nd post (the 3rd post in the thread I think), it should work correctly for the rippling and what not. However the streaking problem seems to be caused from using non-power-of-2 textures (just use 128,256,512 etc.) and is aggravated by using anything but 'none' for your min/mag/mip filters. Hopefully that helps, otherwise I might be able to post my final code (though the implementation is somewhat harder than the HLSL). I've currently managed to get this water rippling code working alongside my 3D water surface (pretty much riemer's water) with reflection/refraction and it looks quite nice with a texture that is only 512x512 and runs smoothly.
  • 11/19/2008 8:15 AM In reply to

    Re: Converting old 2D water code to HLSL?

    you have to offset the texture coordinates by half a texel

    your damping is actually an acceleration whenever the point is moving towards zero

    I think the best way to damp a spring field is by using "velocity * damping" and use a force towards zero that increases exponentially with height

    (i don't see any mapping to and from the colour range 0 -> 1 to -n -> +n)

    and its called a "spring field" by the way

    here is some working code in 2D (not hlsl)

    force1 = Abs[src]^3 * Sign[src] * -1; // exponential force towards zero
    force2 = (srcLeft + srcRight) * 0.5 - src; // spring field force
    velocity = src - dst;
    result = src + velocity * 0.95  + (force1 + force2 * 0.2) * 0.1;

    tunable parameters:
    ^3 = exponential force
    0.95 = velocity damping factor
    0.2 = spring field force reduction factor
    0.1 = total force reduction factor


  • 11/19/2008 11:16 AM In reply to

    Re: Converting old 2D water code to HLSL?

    to stop microvibrations:

    If[Sign[result] != Sign[src] && Abs[result - src] < 0.02, result = 0];

    this snaps the new position to zero but only when crossing the zero line and when moving slowly

    (in other words it never adds velocity)


  • 11/20/2008 1:12 AM In reply to

    Re: Converting old 2D water code to HLSL?

    Could you possible post the project file? I have something that resembles ripples expanding and bouncing, but they eventually turn the entire screen white, and they have a lot of artifacts in them. I'm not sure if your HLSL code is all right, and I'm sure I'm getting tripped up elsewhere.
  • 11/20/2008 6:59 AM In reply to

    Re: Converting old 2D water code to HLSL?

    I won't be able to upload the project until the weekend (when I head home) but it seems like that would be a problem with your damping code (what makes the ripples get smaller, the post directly above yours deals with this and so that might help). Another suggestion would be to attempt to program it on the CPU first, that's what I tend to do with any graphical effects that I'm trying to implement (ones that are 2d atleast, as your water is). Simply create a new project, create a texture that is 1 pixel by 1 pixel in your LoadContent() and use this along with a spritebatch and a for loop to draw the pixels of the screen. By adjusting the blend color of your texture (one of the inputs for spritebatch.Draw()) you can create a black and white or multicolored texture that displays your data. This helps because most people (me atleast) can understand the idea of screen co-ordinates better than the [0-1] range used in HLSL effects, and it removes most of the middle-men (engines, screen-aligned quads etc.) that you've programmed which could be adding to your problem. Obviously the end result will be slow, but it will also give you a better idea of how the code is working and what might be your problem. Hopefully that'll help until I can get some working (relatively so) code up here.
  • 11/20/2008 11:10 PM In reply to

    Re: Converting old 2D water code to HLSL?

    Arkcann:
    I won't be able to upload the project until the weekend (when I head home) but it seems like that would be a problem with your damping code (what makes the ripples get smaller, the post directly above yours deals with this and so that might help). Another suggestion would be to attempt to program it on the CPU first, that's what I tend to do with any graphical effects that I'm trying to implement (ones that are 2d atleast, as your water is). Simply create a new project, create a texture that is 1 pixel by 1 pixel in your LoadContent() and use this along with a spritebatch and a for loop to draw the pixels of the screen. By adjusting the blend color of your texture (one of the inputs for spritebatch.Draw()) you can create a black and white or multicolored texture that displays your data. This helps because most people (me atleast) can understand the idea of screen co-ordinates better than the [0-1] range used in HLSL effects, and it removes most of the middle-men (engines, screen-aligned quads etc.) that you've programmed which could be adding to your problem. Obviously the end result will be slow, but it will also give you a better idea of how the code is working and what might be your problem. Hopefully that'll help until I can get some working (relatively so) code up here.
    Alright, thanks for the ideas. I'll give CPU a try.
  • 11/21/2008 12:50 AM In reply to

    Re: Converting old 2D water code to HLSL?

    Erglegrue:
    Could you possible post the project file? I have something that resembles ripples expanding and bouncing, but they eventually turn the entire screen white, and they have a lot of artifacts in them. I'm not sure if your HLSL code is all right, and I'm sure I'm getting tripped up elsewhere.


    I have spent a good amount of time tuning my spring field - it is not easy - I have written a graphical ui just for tweaking the parameters

    But I got results fast - once I could tune it interactively

    I have got better results than I hope for with code below

    but am now still trying to solve "microvibrations"

    When it "turns white" I think that is because a spring force alone will pull everything in one direction

    You will also find working EXE and HLSL here: http://www.humus.name/index.php?page=3D&&start=32
    humus technique is very simple but I can not replicate his beautiful results
    i get the impression his water only displaces upwards - because I can get the same results by "booting" my texture to all zeros and using no wave force
    but I want proper waves

    (also packing height and velocity into 16 bits each will give better results)

    here is my current attempt:

        //
        // SAMPLE TEXTURE (remember these values are between 0 and 1)
        //
        float4 p0 = tex2D(smpSpringField, Input.TexCoord0); p0.xy -= 0.5; // remap to -0.5 to +0.5
        float4 p1 = tex2D(smpSpringField, Input.TexCoord1); p1.x -= 0.5;
        float4 p2 = tex2D(smpSpringField, Input.TexCoord2); p2.x -= 0.5;
        float4 p3 = tex2D(smpSpringField, Input.TexCoord3); p3.x -= 0.5;
        float4 p4 = tex2D(smpSpringField, Input.TexCoord4); p4.x -= 0.5;
        //
        // ADD DROP
        //
        float2 offset = abs(Input.TexCoord0 - dropLocation);
        if (dropLocation.x != 0 && dropLocation.y != 0) {
            if (dropRadius > offset.x * offset.x + offset.y * offset.y) {
                //
                // THIS IS NEW DROP
                //
                p0.x = 1.0;
                p0.y = -0.1;
            }//if
        }//if
        //
        // CALCULATE SPRING FORCE
        //
        float springForce =
            p1.x +
            p2.x +
            p3.x +
            p4.x -
            p0.x * 4.0;
        //
        // CALCULATE WAVE FORCE
        //
        float waveForce = pow(abs(p0.x), waveExponent) * sign(p0.x) * -1.0;
        //
        // ADD ACCELERATION TO DAMPED VELOCITY
        //
        p0.y =
            p0.y * velocityDamping
            + waveForce * waveScale * elapsedTime
            + springForce * springScale * elapsedTime;
        //
        // CLAMP VELOCITY (experimental)
        //
        p0.y = clamp(p0.y, -0.2, 0.2);
        //
        // ADD VELOCITY TO HEIGHT
        //
        p0.x += p0.y * elapsedTime; // add velocity to height
        //
        // MAP BACK TO COLOR RANGE (remember this will clamp values)
        //
        p0.xy += 0.5;
        //
        // RETURN UPDATED PARTICLE FOR RENDER TARGET
        //
        return p0;
  • 11/21/2008 3:08 PM In reply to

    Re: Converting old 2D water code to HLSL?

    I finally got it the way I want it, things that caught me out:

    - precision of height and velocity as stored in texture
      - this limits what you can do - I have converted to packing height and velocity into float4(Pack(height), Pack(velocity)); which gives 65536 values instead of 256
    - to get around the microvibrations I use a power function when I sample the height map and clamp the lower values to zero
    - you have to use elapsed time to keep the wave motion constant independent of frame rate but ...
    - due to precision constraints if you run the shader too often nothing changes to solve that I keep track of elapsedTime since last draw and skip drawing if less than 2 milliseconds or so
    - by adjusting wave force and spring force factors you can get exactly the kind of water you want

    it is impossible to tune the springfield without a UI - I use a bunch of sliders on a windows form for the parameter
    using a bit of reflection to bind to variables in my object, then when I get the water the way I like it I press A and it copies the values to the copy buffer and I paste it into my code as constants

    also power functions on spring and wave force are invaluable

    no to combine this with procedural terrain and env map = infinite ocean with controllable turbulence


  • 2/25/2009 1:56 PM In reply to

    Re: Converting old 2D water code to HLSL?

    Arkcann, could you possible send me project file (interactive water 2d) for XNA 3.0 ???
    Thanx in advance!

    mladen3@hi.htnet.hr
  • 2/26/2009 8:41 PM In reply to

    Re: Converting old 2D water code to HLSL?

    Thanks for the interest Potter, I've sent you the project file so please reply once you receive it (sent via a hotmail account so it might be put into your junk mail folder). The included code is for the simplest version of the water possible and displays purely in grayscale but you should be able to find many ways to suit it to your needs. If anyone else is interested in the file just ask, I think this method is a really nice alternative to a full fluid solver and can even be used in 3D by passing the values through a normal-map filter and applying that as a normal map.
  • 3/2/2009 12:14 PM In reply to

    Re: Converting old 2D water code to HLSL?

    hey i was wondering if i could also get the project file for this as i have been wondering on how to do something like this but arnt entirly sure how to start this could be a big help

    thanks in advance my e-mail is danthekilla@hotmail.com
  • 5/26/2009 1:10 PM In reply to

    Re: Converting old 2D water code to HLSL?

    I'm very interesting in your project aswell, I've been searching for ages for a hlsl version i might be able to understand, so if you would like to share that would be great. genetransfer@bigpond.com
  • 7/12/2009 4:36 PM In reply to

    Re: Converting old 2D water code to HLSL?

    I would love to see this as well!  My email is digita1alchemy@hotmail.com
  • 5/15/2015 4:03 PM In reply to

    Re: Converting old 2D water code to HLSL?

    I all, is there anyone who has this project and who can share it with me? My e-mail is m.brigati@smartlandproject.com. Thank you!
Page 1 of 1 (20 posts) Previous Discussion Next Discussion