Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Camera: Clear Depth but NOT Stencil?

Discussion in 'General Graphics' started by BearHugMark, Sep 22, 2016.

  1. BearHugMark

    BearHugMark

    Joined:
    Feb 21, 2016
    Posts:
    20
    Hi guys, I'm making a magic mirror that you can see through to another room in the scene.

    I'm using the stencil buffer and two cameras. Camera 1 renders the scene and mirror (creates a stencil of the mirror area). Camera 2 renders the scene from the next room, testing for the stencil mask.

    The problem is, Camera 2 needs to clear the depth buffer so it renders correctly, but without clearing the stencil mask because it needs it.

    Anyone know any solutions to this? I don't want to use render to texture to do this for a variety of reasons.
     
  2. Deleted User

    Deleted User

    Guest

    I cringe for you. I really do. Took me 40 hours just to get stencil buffers to work, and sounds like you need them to do back flips in sparkling leotards.
     
  3. BearHugMark

    BearHugMark

    Joined:
    Feb 21, 2016
    Posts:
    20
    Yeah I saw your other posts on the stencil buffer, I've probably spent a good 6 so far :)

    It can be done in OpenGL I believe, but Unity doesn't appear to have separate depth/stencil clear flags exposed to the Camera system from what I can see.

    I can possibly clear the depth of the screen with a full-screen blit, but it seems....wasteful.
     
  4. Deleted User

    Deleted User

    Guest

    I know you said you don't wanna do an extra blit but I think you gonna have to, and save the stencil as a black and white image, and pass that black and white image to the second rooms shader (as a global texture).

    You know.. what you're trying to do has actually already been done before: https://www.assetstore.unity3d.com/en/#!/content/59185, and its a free asset.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    I would just have the object that renders the mirror also render to depth.

    fixed4 frag(out float depth : SV_Depth) : SV_Target {
    depth = 1.0; // clear depth
    return 0;
    }
     
    jvo3dc likes this.
  6. Deleted User

    Deleted User

    Guest

    @bgolus this seems like a really ez way to access the depth. Do you know if there is a way to access the stencil value from the fragment, as easy as this? :p
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Not consistently available, no. SV_StencilRef exists, but it requires DX11.3 or DX12, and I have no idea what or if an equivalent exists for OpenGL. You can try playing with it and see if even compiles in Unity.

    Also note that is not a way to "access" depth as the value doesn't contain the scene depth, you can only write to it with a value other than the depth of the original fragment.
     
  8. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    339
    Hi,

    I'm stuck with a similar problem, but with another goal in mind.

    I would like to render 3D windows opening the view to different scenes. I've made a first test in webgl using the threejs javascript lib, and I've got this first test result (ignore the clouds in background and the text bloc):
    3dwindows.png
    For now only a bunch of cubes is displayed against a randomized background color for each window.
    To do this, I'm following these steps :
    1) render the main scene, including windows blue containers
    2) enable the webgl stencil tests, and render the front "opened" face of each window with a different value
    3) clear depth buffer to allow rendering of the inner scene of each windows
    4) for all windows : set the corresponding stencil test, and render its inner window
    5) disable the stencil tests

    Since the stencil tests are "global" in standard webgl, I don't have to use different shaders for the similar materials in each window, but it seems in Unity I'll have to define the stencil value for each shader according to the stencil buffer index of its parent 3d window. That's annoying but it looks like I'll not have an alternative way ... If you know one, I'm interested !

    But for now, my main concern is how to clear the depth buffer in my step 3) and keeping the stencil buffer intact ?
    Of course, if someone has a better/simpler solution to achieve the same result, I'm interested ;)

    I'm already exploring the rendertotexture alternative, but I fear it might use to much vram since I may have a lot of textures to render...
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Render a full screen quad with ZTest Always and ZWrite On at the far plane.

    Assuming you're using the default Unity quad, you'd just need:

    ZWrite On // write to depth
    ZTest Always // render over everything
    ColorMask 0 // only render to depth

    void vert(appdata_img v, out float4 opos : SV_POSITION) {
    #ifdef UNITY_REVERSED_Z
    float far = 0; // far projection distance at 0 on dx11, exists so this works in editor
    #else
    float far = 1;
    #endif
    opos = float4(v.vertex.xy * 2.0, far, 1); // default quad -0.5 to 0.5 on x and y, so expand to -1 to 1, this output directly in clip space, no mul needed
    }

    // we only care about depth, so frag does nothing
    fixed4 frag() : SV_Target { return 0; }


    It's possible you'll need to use a value just under the far plane, like 0.99999 (0.00001 for reversed z) for it to not get clipped, but it should be very fast to render, even for webgl. And it shouldn't clear the stencil. You could render this with a graphics.draw call, or just have a quad attached to the camera as a child gameobject so it's always in view. Orientation and scale don't matter as the shader ignores them.
     
    Alesk likes this.
  10. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    339
    Ok thanks a lot for this idea !

    So, to control the render order of each pass, I should use multiple cameras, right ?
     
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Absolutely not. Just use the shader queue or material queue.
     
  12. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    339
    Ha yes ! I figured how to get it to work with multiple cameras, it was easier to do it that way (even if I've spent a lot of time to find the right setup).
    Now that I have everything layered and working, I can try to redo it using the shader queue and remove the multiple cameras :)

    For now, this is working like this :

    1) render background
    2) render stencil buffer geometry from each window opened face
    3) clear depth
    4) render windows contents, filtered by the stencil buffer
    5) fill depth again for each window opened face (to prevent the main scene to render inside each window)
    6) render the main scene

    So I've got 6 cameras (the first two could be merged) ... I'm working now on replacing this setup with shader queue only.

    Thanks a lot for your help !