Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Efficient vignette implementation (no post-processing) for mobile VR

Discussion in 'Shaders' started by PatrickKa, Apr 6, 2020.

  1. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Hey,

    I'm currently trying to implement a very efficient vignette effect that doesn't require post-processing to make it work on mobile VR. My general idea how it should work is a full-screen mesh (basically a quad but with a hole in it). This way I can just rescale the mesh to adjust the strength of the vignette. The mesh would feature 2 materials. One fully opaque material for the outer part of the mesh and one transparent material for the inner part of the mesh. My idea would be to write to the Z-Buffer for the outer part to basically have everything else rejected. This gives me enough of a performance boost to make up for the overdraw caused by the inner transparent part of the mesh.

    So far I managed to make this work but I ran into many problems with sorting. It wasn't enough to set a low render queue and world space UI also ruined everything again...

    I came up with adding Offset -999999999, -999999999 in the shader and that fixed it. From what I understand this is not reliable and going to fall apart because I'm abusing a feature that isn't supposed to be used like this.

    Should I look into a stencil shader instead? Are they efficient on mobile? Or is my hacky approach actually a good enough solution? Any other ideas?
     
  2. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    823
    I would not recommend using absurd Offsets, they don't behave the same way on each platform (for iOS you would get artifacts for sure).
    You could just set the z value in your vertex shader to make sure it is at the near clipping plane
    Code (CSharp):
    1. Tags { "RenderType"="Opaque" "Queue"="Geometry-10"}
    2.        ZWrite On
    3.        ZTest Always
    4.         LOD 100
    5.  
    6. ...
    7.  
    8. v2f vert (appdata v)
    9. {
    10.    v2f o;
    11.    o.vertex = UnityObjectToClipPos(v.vertex);
    12.    o.vertex.z = UNITY_NEAR_CLIP_VALUE;
    13.    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    14.    return o;
    15. }
    If you use a plane that points in the z-axis as you described, this quad will always be in the front rendering before everything else.

    Maybe a opaque shader which renders at the end with blend mode to multiply and a white to black vertex color could be the most efficient setup, but I guess you will need to do tests for that.
     
    Nashoute likes this.
  3. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    This is a super neat and very elegant idea and I quickly prototyped it. So far it seems to work nicely and all the edge cases (literally) also worked out of the box. Nice!

    I will have to test it some more but its really promising and looks like the solution I was looking for. Thank you for that! I really appreciate!

    Of course, other ideas and feedback is still welcome!
     
  4. VoodooDetective

    VoodooDetective

    Joined:
    Oct 11, 2019
    Posts:
    238
    Is this something you'd be willing to share?
     
    Nashoute likes this.