My Interactive Real-Time Water Simulation ( Video and Download )

Started by
9 comments, last by gfxbean 9 years, 5 months ago

Looks amazing! Are you going to release the source code? Would love to see how you got the 3D grid for the simulation

Cheers and again, awesome work

Thanks! I'm thinking of using the effect, around 2000 lines of setup and shader code for a video tutorial for ShaderFlex. I will also most likely ship the source to my FFT Water, fluids, fur, grass and other tech along with the tool, but that won't be till early 2015.

As for the grid, it was a bit of a headache. So NVidia lays out a bunch of world alighned grids around the viewer at different resolutions and blends between them. I wanted to try the screen space projected grid approach and had some issues. There's another ocean sample using it but their demo fixed the camera to never roll or tilt off the horizon for a reason. The minute you do, everything looks like shit, your triangles get skewed and start sticking out of knowwhere. My solution actually worked out nicely, I rotated my projection of the grid to always align with the horizon and it fixed it all. It was a bit tricky because you have to also do some compensating for the screen's aspect ratio when rotating your -1 to 1 screen space vertices.

If you're not familiar with the approach, you basically generate say a 400x800 grid of vertices, and lay them out from -1,-1 to 1,1 which is my final viewport projection. Then in the vertex shader you use your inverseprojection matrix and you transform each vertex position into world space. You then take the that and the camera position to get the vertices direction vector. You cast a ray from that point into yoru world and calculate an intersection on the water plane and that is your new world space grid position for that vertice. Problems arise when the vertice is then displaced by the FFT effect, the water will ripple in and out of the screen at the edges so you need to extend your -1 to 1 to -2 to 2 for example, it's a bit wasteful, but works. I use more vertices in the vertical because there's usually more vertices needed as they get projected out into the horizon. My code for this is a bit of a mess and not optimized yet but here it is...


float2 Aspect = Surface.TargetSize.xy / Surface.TargetSize.y;
float  AspectRatio = Aspect.x / Aspect.y;
float  GridPadding = 0; <<m_GridPadding.Evaluate()>>;
float  GridFalloff = 0; <<m_GridFalloff.Evaluate()>>;
                    
                   
float3 Up = normalize( mul( float3( 0, 1, 0 ), (float3x3)Surface.ViewMatrix ) );
float Cos = dot( normalize( Up.xy ), float2( 0, 1 ) ); // transform the world's up vector into camera space so you can find out the 2D angle between the horizon and your camera's up vector
float Sign = ( Up.x < 0 ) ? -1 : 1;
                        
Vertex.Position.xz = ssRotateVector( Vertex.Position.xz, Sign * acos( Cos ), true ); // rotate your vertex to align with the horizon
                    
float3 CameraGridPosition = mul( float4( Vertex.Position.xz * Aspect.yx * GridPadding, 1, 1 ), Surface.InverseProjectionMatrix ).xyz; // tranform from screenspace into world space so you cna calculate a direction vector
float3 WorldGridPosition = mul( float4( CameraGridPosition, 1 ), Surface.CameraMatrix ).xyz;        
                    
float3 FinalPosition;
Intersects = ssIntersectLineAndPlane( Surface.CameraPosition, normalize( WorldGridPosition - Surface.CameraPosition ), float3( 0, 0, 0 ), float3( 0, 1, 0 ), FinalPosition );
                    
Interp.Position = ( Intersects ) ? FinalPosition : Surface.CameraPosition * float3( 1, 0, 1 ) + Surface.CameraLook * float3( 1, 0, 1 ) * 100000000; // hack to ignore vertices that can't project to the water plane
                    
// you then read your displacement FFT texture using this world space position and dispace your vertex. There's probably an easier way to do this, but I just wanted to get it working for now.

This topic is closed to new replies.

Advertisement