I'm trying to achieve the following setup:
- 2 cubes. In the image attached they are the green and pink cube. They are both rendered culling their front faces, so that they are visible if a camera stands inside of them.
- The 2 cubes intersect, as show in the image.
- The pink cube has an opening (door, window, portal, whathaveyou) thru which a camea facing in the direction of the opening, can see the green cube.
- Here is the interesting part: if the camera is not looking thru the opening however, I want the green cube face on the right side of the image to not be visible.
The culling is easy: just say Cull Front in a surface shader. The part that I'm not sure how to pull of in Unity is the last point.
The way I would solve this in OpenGL, in a forward rendering pipeline, would be by turning on depth testing
glEnable(GL_DEPTH_TEST) and, when rendering the green box, I'd disable depth writing to the z buffer but keep testing on. i.e.
glDepthMask(GL_FALSE) then render the cube and then re-enable writes to the z buffer. Essentially treating the green cube as if it were a skybox.
But I have not found anywhere in the ShaderLab documentation an equivalent of
glDepthMask. there is
ZTest but these just are equivalent to
glDepthFunc, not to the mask.
Alternatively, I was thinking of using clipping planes . In GL this would be using
gl_ClipDistance in the shaders. I would render the green cube with a clipping distance equal to the intersection point of both cubes - 1, so it chops off that face. And the render the other cube without the clipping plane. But this would require updating the shader each time the clipping plane (intersection between the cubes) changes.
I actually think that ShaderLab's
ZWrite <On|Off> is the equivalent of
glDepthMask. The issue is that I don't seem to be able to control rendering the green cube after Unity's skybox. If I were, the approach I'd take would be:
- Unity renders it's skybox.
- I render my green cube with
ZWrite Off. This implies z testing takes place against the fragments of the cube, but the buffer won't be updated with the z values of the cube after this pass.
- Render the rest of the geometry as usual.
Since step 2 did not write to the z buffer, the geometry should cover everything as it normally does with respect to the engine's skybox. This means it would cover the green cube too. But, if the geometry (pink cube) had any openings, the pink cube would not write to the z-buffer since there is nothing there. The buffer in those areas should be 1 (the default for infinitely away).
I tried the above, which just meant creating a new surface shader with
ZWrite Off and a tag
"Queue" = "Background+1", hoping it would mean "render after the skybox". But while it does prevent the green cube rendering on top of the pink cube, it also makes Unity's skybox render on top of the green cube. So not sure how to tell it to render after the skybox.