Any way to use clipping planes wgen rendering a scene?

Godot Version

4.6.2

Question

I’m creating a shader that acts as a mirror. It works in conjunction with a camera that is captures the mirrored version of the scene. Basically, every frame the “mirror” camera is updated to copy the player’s point of view, reflected across the plane of the mirror. The mirror camera renders to a Subviewport canvas that’s the same dimensions as the viewport.

It’s working pretty well, but there’s one issue - if there’s an object on the far side of the mirror (ie, between the back of the mirror and the mirror camera), it will be included in the reflection. It would be nice if there were some way I could add a clipping plane to everything rendered by my mirror camera to simply clip away anything behind the plane of the mirror. I’d know how to do this if I were programming in OpenGL, but the Godot pipeline seems to have limited options when it comes to manipulating cameras. Camera layers are not terribly helpful since they operate on entire objects. It would also be tricky to set up if there were multiple mirrors positioned in different points in the room. And as far as I can tell, Godot shaders only let you manipulate vertices, fragments and “lights”, so I don’t see how I could discard or clip triangles there.

Is there any way to clip away the geometry I don’t need?

Have you tried putting things on a different visibility layers and only having the camera show the layers you want?

I could, but that’s a big headache. It means that I’m going to have to custom set up the camera for each mirror I use, and it won’t handle objects that penetrate the mirror properly. Also, clipping the scene meshes seems more like the more neat solution, if it’s possible.

Add a compositor effect to the mirror camera. Effect’s compute shader can read the depth buffer. Reconstruct pixel’s world space position from that and projection matrix, clip the position against the plane.

I don’t think that’s going to work. Compositor effects seem to work on the entire computed viewport buffer, not a pass for each object. So unless there’s some way I can composite every mesh individually, discarding fragments that are on the wrong side of my clip plane will just leave holes in the final result.

How would doing it per object differ from doing it on the entire image if the goal is to plane-clip everything?

I want to plane clip everything everything behind the mirror plane. So if there is an object between the mirror camera and the mirror, I want to clip that away. But I want to draw everything on the front side of the mirror. So if I only have the complete depth buffer to work with, clipping based on depth is only going to tell me which fragments failed the test, not allow through whatever is behind them. I’d need to composite every object individually for that to work.

Then you’ll have to do it with a shader. Send the list of mirrors and corresponding cameras to the shader, if the the pixel and the camera are on the same side, discard it.

Too bad Godot doesn’t have per-camera shader override. That’d be very useful for solving many compositing problems.

Right. But to do it with shaders, I’d need to use custom shaders for every object in my scene. And also feed the clip plane into each of them, and for each camera they’re rendered by. That’d be really hard to both create and maintain.

Not a big deal really. Make a shader include that implements the check/discard macro. Include it in every shader and just call the macro at the beginning of its fragment function. Use global uniforms (also declared in the shader include) to pass the data into the shader so you only need to set them at one place. Afaik you can’t use global uniform arrays, but a few of mat4s should be sufficient if the number of mirrors is reasonably low.

This would also need to pass different clipping info per viewport. So for this example, each camera-mirror would have its own clipping plane and the main scene renderer would have none. So each shader would need to know which camera/viewport it was being rendered with.

Just pass all camera position and plane pairs into the shader. Iterate in the vertex function and determine the plane you need to use by checking camera positions against the rendered camera position.

Depending on the rest of your setup you can abuse CAMERA_VISIBLE_LAYERS built in to instantly get the camera index in the input data.

This way you don’t really need to manage anything except setting the uniforms and calling the check macro in your shaders.