0
\$\begingroup\$

I'm trying to achieve the following setup:

enter image description here

  • 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 ZWrite and ZTest but these just are equivalent to glEnable(GL_DEPTH_TEST) and glDepthFunc, not to the mask.

Any thoughts?

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.

UPDATE:

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:

  1. Unity renders it's skybox.
  2. 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.
  3. 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.

\$\endgroup\$
  • \$\begingroup\$ First, in what case do you actually need this? For me this looks like a bad design in some cases. Next, why do you want, if you really need this, to handle this on shader side. I would attach a script to the cube, that when object X oder anything is watching the wall, set it's rendered to false. \$\endgroup\$ – Yosh Synergi Sep 27 '16 at 7:25
  • \$\begingroup\$ The use case is relatively complex to explain and not part of the question (I basically need to be able to intersect volumes of arbitrary sizes with openings over a fixed size static volume). Handling this on the rendering side (note that glDepthMask is not shader side but client side) is actually the most performant way, since it does not disturb the pipeline other than to bypass one write pass to the zbuff (same pass the cube was going to do anyway). The approach you suggest would fail at raycasts not perpendicular to the wall and would require state changes in the scene graph. \$\endgroup\$ – SaldaVonSchwartz Sep 27 '16 at 9:17
  • \$\begingroup\$ to elaborate on why your approach would fail: consider staring at the ceiling but where your field of view still allows seeing the wall I want hidden in that case. You would still see the wall until the raycast hits that actual wall / collider. Also consider the case where the 'green' cube has more than one intersecting side with the pink, perpendicular to where the opening is. If you enabled the green cube you'd also see the perpendicular side intersecting the pink. And raycasting involves the physics engine; another layer of performance penalty. Thanks for the thought though. \$\endgroup\$ – SaldaVonSchwartz Sep 27 '16 at 9:22
  • \$\begingroup\$ You are totally right. In these cases, using my approach is too much of a performance impact. Sr i wasn't able to assist you, as writing my own shaders isn't my best practice x) \$\endgroup\$ – Yosh Synergi Sep 27 '16 at 9:56
  • \$\begingroup\$ Made a chat room with more info: chat.stackexchange.com/rooms/45965/… \$\endgroup\$ – Coburn Sep 27 '16 at 13:34

Your Answer

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

Browse other questions tagged or ask your own question.