0
\$\begingroup\$

I have written a shader (in the new LWRP shader graph) which simulates an ocean with vertices which offset to create a moving "waves" effect.

I believe that in order to have objects "float" on my moving waves, I shall need to create a mesh collider which is a trigger (please correct me if I'm wrong) which updates with the moving vertices of the mesh as per direction from the shader.

How is such an effect possible? Am I taking the correct approach here? Please advise :)

Many thanks in advance!!

(the original model for the water is a plane which has been subdivided multiple times to provide suitable resolution for the vertices to be offset)

Ocean shader screenshot with wireframe to show vertex offset

\$\endgroup\$
1
\$\begingroup\$

I would not recommend using a meshCollider for this. They're one of the more expensive types of collider to process, and every time you move the vertices the physics engine will need to recalculate all its acceleration structures that try to make looking up the right colliding triangles faster. You'll likely burn a ton of CPU this way.

One method I've seen used is to attach "floaters" to objects that are meant to float in the water. These behave like a virtual flotation device, exerting forces on the object according to their degree of immersion in the water.

Each physics update, each floater samples the water height at its position (eg. by evaluating the same wave function you use in the shader). If the floater is fully above the water, it exerts no force on its parent body. If the floater is partially or fully immersed (you can analytically model the floaters as spheres with a particular radius, for example), it calculates the total buoyancy force according to how much of it is underwater, and applies it as an upward force on the parent body, applied at its point of attachment.

These floaters can also compute & apply viscosity drag forces or lateral currents in a similar way. If you compute the local (low frequency) gradient vector of the waves, you can tilt the axis on which you apply these forces to push outward from larger sea swells.

With these, a floating object will not collide with the water like a solid floor, but ride within it on a fluid cushion spring. By adding more floaters distributed around your object, you can simulate more complex buffeting by waves (as eg. the starboard bow floaters take the wave first, causing the ship to lurch from the uneven forces on it)

Similarly for effects spawned at the water's surface - I wouldn't count on collision tests and raycasts to place them. Instead, sample your wave height function at the x/z coordinates of the effect and snap it to that height.

\$\endgroup\$
  • \$\begingroup\$ Hi @DMGregory Thanks for the answer. I have seen similar implementations, but I thought that the only way to do this was to raycast from various points on the "floating" model, which means the water mesh would need a collider(??). Secondly, how would you go about sampling the height of the vertices from a given point? Many thanks \$\endgroup\$ – Ben Hayward Aug 4 '18 at 14:05
  • \$\begingroup\$ "each floater samples the water height at its position (eg. by evaluating the same wave function you use in the shader)" That means you use the same math code in your floater script that you use in your shader. Because you're running the same math on the same input coordinates, you'll get the same answer the vertex shader came up with. \$\endgroup\$ – DMGregory Aug 4 '18 at 14:08
  • \$\begingroup\$ Oh I see what you're saying. The only disadvantage I can see in that, is that developers working on the project would need to guarantee that any alteration made to the logic in the shader is replicated exactly in the floater script (and vice versa). If one was able to sample directly from the mesh/shader there would be no need for duplication. Is there any way to do the latter? I get the impression the latter would be more costly but might make for more maintainable code? \$\endgroup\$ – Ben Hayward Aug 4 '18 at 14:20
  • \$\begingroup\$ You could run the floaters themselves on the GPU, referencing the same shader function that evaluates wave height in a common include. Each frame you'd provide a buffer of updated floater positions/sizes, then later read back the resulting forces to apply for each. It's more complicated and there's risk of stalls or added latency if not coordinated right, though since water is sloshy you probably wouldn't notice a frame or two of latency badly. You could also generate the shader and CPU-side wave function from a common source, transpiled to each language at build time so they stay in sync. \$\endgroup\$ – DMGregory Aug 4 '18 at 14:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.