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

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?

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

Tags { "RenderType"="Opaque" "Queue"="Geometry-10"}
       ZWrite On
       ZTest Always
        LOD 100

...

v2f vert (appdata v)
{
   v2f o;
   o.vertex = UnityObjectToClipPos(v.vertex);
   o.vertex.z = UNITY_NEAR_CLIP_VALUE;
   o.uv = TRANSFORM_TEX(v.uv, _MainTex);
   return o;
}

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.

1 Like

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!

Is this something you’d be willing to share?

1 Like