So I’m working on a VR game that is basically Eagle Flight (Ubisoft) and since people are experiencing motion sickness from it, I’m in the process of copying some of the techniques Eagle Flight uses to mitigate that - namely what they call Dynamic Blinders. See what that is here
What they do is detect if an object is close to the player and dynamically black out a portion of the screen depending on the relative direction to the player and how close it is. They also black out parts if the player turns around very tightly but that’s not important here.
The way I’ve implemented this is by parenting a plane with a custom cutout shader to my camera, the way you would when creating a simple fade to black effect, where a black plane is right in front of the camera facing it and you lerp the alpha value over time. Only my plane is transparent and the shader will dynamically render black pixels where they need to be.
What the shader does is it has MaterialToggle integers that get set via SendMessage from hitboxes around the player and work as booleans. “Is there an object close to the right? → set int = 1”. Then it does some math to determine the pixels that need to be rendered black.
It works fine, I’m happy with the result considering this is my first attempt in manipulating shaders.
The problem:
(if the gif won’t show, here’s a link Screen recording 2018-02-15...)
When flying really close to objects, they get drawn on top of the plane, which shouldn’t be happening since the plane is as close to the camera as it can be before disappearing behind the near clipping plane (which I cannot fiddle with since this is a VR game and the VR headsets prevent Unity from making changes to things like the clipping planes, FOV etc.)
How do I fix this? Any ideas?
If it helps, find the shader and some screenshots here:
Shader "Unlit/Unlit_Transparent_Cutout_Custom"
{
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
_TransitionTex("Transition Texture", 2D) = "white" {}
//_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
/*_Cutoff_b("Cutoff_b", Range(0.01, 0.08)) = 0.01
_Cutoff_r("Cutoff_r", Range(0, 1)) = 0
_Cutoff_g("Cutoff_g", Range(0, 1)) = 0*/
[HideInInspector]
minTop ("MinTop", Float) = 0.6
[HideInInspector]
maxTop ("MaxTop", Float) = 0.9
_Intensity_Top ("_Intensity_Top", Range(0.6, 0.9)) = 0.9
[HideInInspector]
minBot("MinBot", Float) = 0.09
[HideInInspector]
maxBot("MaxBot", Float) = 0.4
_Intensity_Bottom ("_Intensity_Bottom", Range(0.09, 0.4)) = 0.09
[HideInInspector]
minRight("MinRight", Float) = 0.1
[HideInInspector]
maxRight("MaxRight", Float) = 0.53
_Intensity_Right ("_Intensity_Right", Range(0.1, 0.53)) = 0.53
[HideInInspector]
minLeft("MinLeft", Float) = 0.47
[HideInInspector]
maxLeft("MaxLeft", Float) = 0.9
_Intensity_Left ("_Intensity_Left", Range(0.47, 0.9)) = 0.47
[HideInInspector]
minTopRight("MinTopRight", Float) = 0.01
[HideInInspector]
maxTopRight("MaxTopRight", Float) = 0.08
_Intensity_TopRight("Intensity_TopRight", Range(0.01, 0.08)) = 0.01
[HideInInspector]
minTopLeft("MinTopLeft", Float) = 0.01
[HideInInspector]
maxTopLeft("MaxTopLeft", Float) = 0.08
_Intensity_TopLeft("Intensity_TopLeft", Range(0.01, 0.08)) = 0.01
[HideInInspector]
minBotRight("MinBotRight", Float) = 0.01
[HideInInspector]
maxBotRight("MaxBotRight", Float) = 0.08
_Intensity_BottomRight("Intensity_BottomRight", Range(0.01, 0.08)) = 0.01
[HideInInspector]
minBotLeft("MinBotLeft", Float) = 0.01
[HideInInspector]
maxBotLeft("MaxBotLeft", Float) = 0.08
_Intensity_BottomLeft("Intensity_BottomLeft", Range(0.01, 0.08)) = 0.01
[MaterialToggle] _Top("Top", int) = 0
[MaterialToggle] _Bottom("Bottom", int) = 0
[MaterialToggle] _Right("Right", int) = 0
[MaterialToggle] _Left("Left", int) = 0
[MaterialToggle] _TopRight("TopRight", int) = 0
[MaterialToggle] _TopLeft("TopLeft", int) = 0
[MaterialToggle] _BottomRight("BottomRight", int) = 0
[MaterialToggle] _BottomLeft("BottomLeft", int) = 0
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
LOD 200
CGPROGRAM
#pragma surface surf Lambert alpha
sampler2D _MainTex;
sampler2D _TransitionTex;
fixed4 _Color;
float _Cutoff;
//float _Cutoff_b;
//float _Cutoff_r;
//float _Cutoff_g;
float _Intensity_Top;
float _Intensity_Bottom;
float _Intensity_Right;
float _Intensity_Left;
float _Intensity_TopRight;
float _Intensity_TopLeft;
float _Intensity_BottomRight;
float _Intensity_BottomLeft;
int _Top;
int _Bottom;
int _Right;
int _Left;
int _TopRight;
int _TopLeft;
int _BottomRight;
int _BottomLeft;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
fixed4 transit = tex2D(_TransitionTex, IN.uv_MainTex);
o.Albedo = c.rgb;
if (_Top > 0)
if (IN.uv_MainTex.y > -pow(0.5 * IN.uv_MainTex.x - 0.25, 2) + _Intensity_Top)
o.Alpha = c.a;
if (_Bottom > 0)
if (IN.uv_MainTex.y < pow(0.5 * IN.uv_MainTex.x - 0.25, 2) + _Intensity_Bottom)
o.Alpha = c.a;
if (_Right > 0)
if (IN.uv_MainTex.x > -pow(0.5 * IN.uv_MainTex.y - 0.25, 2) + 0.5 + _Intensity_Right)
o.Alpha = c.a;
if (_Left > 0)
if (IN.uv_MainTex.x < pow(0.5 * IN.uv_MainTex.y -0.25, 2) -0.5 + _Intensity_Left)
o.Alpha = c.a;
if (_TopRight > 0)
if (IN.uv_MainTex.y > _Intensity_TopRight/(IN.uv_MainTex.x - 1) + 1) // 0.02 bis 0.08
o.Alpha = c.a;
if (_TopLeft > 0)
if (IN.uv_MainTex.y > _Intensity_TopLeft/(-IN.uv_MainTex.x) + 1) // 0.02 bis 0.08
o.Alpha = c.a;
if (_BottomRight > 0)
if (IN.uv_MainTex.y < _Intensity_BottomRight/(-IN.uv_MainTex.x + 1)) // 0.02 bis 0.08
o.Alpha = c.a;
if (_BottomLeft > 0)
if (IN.uv_MainTex.y < _Intensity_BottomLeft/(IN.uv_MainTex.x)) // 0.02 bis 0.08
o.Alpha = c.a;
/*if (_BottomLeft > 0)
if (transit.g > _Cutoff_g && transit.b > _Cutoff_b)
return col = lerp(col, _Color, _Fade);
*/
}
ENDCG
}
Fallback "Transparent/VertexLit"
}