Implementing volumetric clipping?

Hello, I’m working on a mobile AR game where objects can move beyond the visible bounds of a gameboard, and I need some way to cleanly clip the part of the mesh that hangs over the bounds.

So far, the only way I know is to switch the material of meshes hanging over the edge to use a shader that does a boundary check and then clips. But that feels like a really brute forced way to do things, and the clip() calls might be expensive on mobile. But instead of calling clip(), I’ll try looking into the performance of nuking vertices by setting NaN.

I’ve read a little bit about stencil CSG, but all the examples I’ve seen are on subtraction, and I think I would need intersection CSG, where the stencil mesh is a box that encapsulates the gameboard. I’ve not worked with stencil buffers yet, so I’m not sure whether this is the right path, and what the performance would be like on mobile.

I’m also wondering if there are any camera tricks that can be used. It seems like I need the frustum clipping of an an isometric camera, but the actual rendering of the objects needs to be perspective projection. But I’m not sure if it possible to perform clipping based upon only one camera frustum, and it sounds like I would have to render all meshes on two cameras then.

Any advice on which approach to pursue? Thanks!

Stencils are a screen space thing. While it’s possible to do 3D CSG like operations with it, doing so requires extreme control over the draw order of everything in the scene. Something like limiting a thing to draw within a 3d volume is much easier accomplished with a shader using clip().

Using clip() really is the correct way to do this. The other way is to do real CSG on the CPU, but that’s way more expensive. The clip() call is certainly more expensive on mobile than desktop, but I would suggest trying just having everything use the clip() shader and see what the performance is like, then optimize afterward. Assuming your play area is made up of several parts, changing the material once a section is close to the edge, and hiding it completely once you know it’s completely off the “board”, is going to be the best bet.

There’s also no such thing as setting the vertices to NaN. Not really. You’re either drawing a mesh or you’re not. If you’re drawing a mesh you’re paying for the cost of calculating the vertices, and while collapsing the vertices may prevent having to pay the cost of the fragment shader, not drawing the mesh to begin with is a much more efficient way of accomplishing that goal.

1 Like

Hey @bgolus , thanks for chiming in!

Thanks for sharing your experience with stencils/CSG. Sounds like I can rule this out.

I would be following a system like what you suggested. All meshes that are fully outside of the bounds will simply have their renderer turned off. And only meshes on the edge of bounds will use a special shader that collapses OOB vertices as a cheaper alternative (I presume) to calling clip() on the fragment shader. Something like:

           float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
           if (worldPos.z > 20) {
              float NaN = 0.0/0.0;
              v.vertex = float4(NaN, 0, 0, 0);
           }

And meshes that are fully within the bounds will use a normal, non-boundary checking shader.

Anyways, I think I’ll try implementing the clip approach as you’ve suggested, and then seeing how performance is.

Thanks bgolus!