- Home /
The question is answered, right answer was accepted
Incorrect depth buffer in unlit shader when running on VR device
I have a problem with my depth buffer, which is correct when running in the Editor, but wrong when running on my Oculus Quest 2.
I want to visualize molecules with sets of spheres. To decrease the number of vertices I render quads instead of spheres. In an unlit shader (see below) I use the fragment shader to calculate the correct lighting per fragment and the correct depth value (ray-sphere intersection).
In the Editor everything works fine, here the depth buffer seems to range from 1 to 0. On my Oculus Quest 2 my spheres look right, but when I place them behind unity objects they are still visible. I assume this is because of my depth buffer. Until now I found out than the my depth buffer in VR ranges from 0 to 1.
Is there anything wrong with my depth buffer calculation or does anyone know how the depth buffer is calculated in VR for other objects, which use the standard shader?
I use MacOS, Unity 2020, Metal as Graphics API, Oculus Quest 2. Additionally I use GPU Instancing.
Thanks!
Fragment shader starts at line 74.
Shader "Custom/Ilusion"
{
Properties
{
_Color("Color", Color) = (0.5, 0.5, 0.5, 1)
_Radius("Radius", Float) = 0.25
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 fragPos : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct fragOutput {
fixed4 color : SV_Target;
float depth:SV_Depth;
};
float3 spherePos (float rad, float3 center, float3 origin, float3 dir)
{
dir = normalize(dir);
float3 o_c = origin - center;
float delta = pow(dot(dir, o_c), 2) - (pow(length(o_c), 2) - rad * rad);
float d = -(dot(dir, o_c));
if(delta < 0){
discard;
}
if(delta > 0){
d = min(d + sqrt(delta), d - sqrt(delta));
}
return origin + d * dir;
}
float4 _Color;
float _Radius;
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
o.fragPos = mul(unity_ObjectToWorld, v.vertex);
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fragOutput frag (v2f i)
{
UNITY_SETUP_INSTANCE_ID(i);
float4 ambient = float4(0.1, 0.1, 0.1, 0.0);
float3 origin = mul(unity_ObjectToWorld, float4(0.0,0.0,0.0,1.0)).xyz;
float3 camera = _WorldSpaceCameraPos;
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
float3 ray = i.fragPos - camera;
// depth value calculation in world space
float3 sphereP = spherePos(_Radius, origin, camera, ray);
float3 nrm = normalize(sphereP - origin);
float lamb = max(0, dot(nrm, lightDir));
fixed4 col = _Color * lamb + ambient;
// world to clipposition
float4 pos = mul(UNITY_MATRIX_VP, float4(sphereP, 1.0));
fragOutput o;
o.color = col;
// dehomogenizing
o.depth = (pos.z / pos.w);
return o;
}
ENDCG
}
}
}
This is the correct image. In VR the sphere is fully visible, although it is actually half inside the cube.
Follow this Question
Related Questions
VR shader - unlit with dynamic reflections? 0 Answers
What water should I use for VR specifically a google cardboard game. 1 Answer
iPhone Shader - Unlit, 2 textures (alpha blend), Base needs tint. 1 Answer
Desaturating based on camera depth in an image effect? 0 Answers
Find out if an object is in front of a target in fragment shader? 0 Answers