Describe the bug
I have installed AR Foundation v.5.0.2 and ARCore. The ARCore plugin uses the ARCoreBackgroundAfterOpaques.shader to occlude objects. There are two passes. The second one works fine. The first pass however, is broken. In this pass variables are used which are not defined, functions are used which are not defined and vectors are accessed wrong.
To Reproduce
The wrong shader can be found under Packages -> Google ARCore XR Plugin -> Assets -> Shaders -> ARCoreBackgroundAfterOpaques.shader.
Expected behavior
Normally the first pass should improve the performance as far as I understand since it is only discarding background pixels when the environment depth is telling the shader that those are behind the already drawn geometry.
Actual behavior
But since the errors listed above the first pass is broken and does not do anything.
Smartphone (please complete the following information):
Unity version: 2021.3.6f1
ARFoundation version: 5.0.2
The wrong shader code:
Shader "Unlit/ARCoreBackgroundCopy/AfterOpaques"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_EnvironmentDepth("Texture", 2D) = "black" {}
}
SubShader
{
Name "ARCore Background (After Opaques)"
Tags
{
"Queue" = "Background"
"RenderType" = "Background"
"ForceNoShadowCasting" = "True"
}
Pass
{
Name "ARCore Background Occlusion Handling"
Cull Off
ZTest GEqual
ZWrite On
Lighting Off
LOD 100
Tags
{
"LightMode" = "Always"
}
GLSLPROGRAM
#pragma multi_compile_local __ ARCORE_ENVIRONMENT_DEPTH_ENABLED
#pragma only_renderers gles3
#include "UnityCG.glslinc"
#ifdef SHADER_API_GLES3
#extension GL_OES_EGL_image_external_essl3 : require
#endif // SHADER_API_GLES3
// Device display transform is provided by the AR Foundation camera background renderer.
uniform mat4 _UnityDisplayTransform;
#ifdef VERTEX
varying vec2 textureCoord;
void main()
{
#if defined(SHADER_API_GLES3) && defined(ARCORE_ENVIRONMENT_DEPTH_ENABLED)
// Transform the position from object space to clip space.
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
// Get quad uvs for sampling camera texture
textureCoordQuad = gl_MultiTexCoord0;
// Remap the texture coordinates based on the device rotation.
textureCoordEnvironment = (_UnityDisplayTransform * vec4(gl_MultiTexCoord0.x, 1.0f - gl_MultiTexCoord0.y, 1.0f, 0.0f)).xy;
#endif // SHADER_API_GLES3 && ARCORE_ENVIRONMENT_DEPTH_ENABLED
}
#endif // VERTEX
#ifdef FRAGMENT
varying vec2 textureCoordQuad;
varying vec2 textureCoordEnvironment;
uniform float _UnityCameraForwardScale;
#ifdef ARCORE_ENVIRONMENT_DEPTH_ENABLED
uniform sampler2D _EnvironmentDepth;
uniform sampler2D _CameraDepthTexture;
#endif // ARCORE_ENVIRONMENT_DEPTH_ENABLED
float ConvertDistanceToDepth(float d)
{
d = _UnityCameraForwardScale > 0.0 ? _UnityCameraForwardScale * d : d;
float zBufferParamsW = 1.0 / _ProjectionParams.y;
float zBufferParamsY = _ProjectionParams.z * zBufferParamsW;
float zBufferParamsX = 1.0 - zBufferParamsY;
float zBufferParamsZ = zBufferParamsX * _ProjectionParams.w;
// Clip any distances smaller than the near clip plane, and compute the depth value from the distance.
return (d < _ProjectionParams.y) ? 1.0f : ((1.0 / zBufferParamsZ) * ((1.0 / d) - zBufferParamsW));
}
void main()
{
#if defined(SHADER_API_GLES3) && defined(ARCORE_ENVIRONMENT_DEPTH_ENABLED)
vec3 result = texture(_MainTex, textureCoord).xyz;
float depth = texture(_CameraDepthTexture, textureCoordQuad).x;
float distance = texture(_EnvironmentDepth, textureCoordEnvironment).x;
float environmentDepth = ConvertDistanceToDepth(distance);
#ifndef UNITY_COLORSPACE_GAMMA
result = GammaToLinearSpace(result);
#endif // !UNITY_COLORSPACE_GAMMA
if (depth >= environmentDepth)
{
discard;
}
gl_FragColor = vec4(result, 1.0);
gl_FragDepth = depth;
#endif // SHADER_API_GLES3 && ARCORE_ENVIRONMENT_DEPTH_ENABLED
}
#endif // FRAGMENT
ENDGLSL
}
Pass
{
Name "AR Camera Background (ARCore)"
Cull Off
ZTest LEqual
ZWrite On
Lighting Off
LOD 100
Tags
{
"LightMode" = "Always"
}
GLSLPROGRAM
#pragma multi_compile_local __ ARCORE_ENVIRONMENT_DEPTH_ENABLED
#pragma only_renderers gles3
#include "UnityCG.glslinc"
#ifdef SHADER_API_GLES3
#extension GL_OES_EGL_image_external_essl3 : require
#endif // SHADER_API_GLES3
// Device display transform is provided by the AR Foundation camera background renderer.
uniform mat4 _UnityDisplayTransform;
#ifdef VERTEX
varying vec2 textureCoord;
void main()
{
#ifdef SHADER_API_GLES3
// Transform the position from object space to clip space.
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
// Remap the texture coordinates based on the device rotation.
textureCoord = (_UnityDisplayTransform * vec4(gl_MultiTexCoord0.x, 1.0f - gl_MultiTexCoord0.y, 1.0f, 0.0f)).xy;
#endif // SHADER_API_GLES3
}
#endif // VERTEX
#ifdef FRAGMENT
varying vec2 textureCoord;
uniform samplerExternalOES _MainTex;
uniform float _UnityCameraForwardScale;
#ifdef ARCORE_ENVIRONMENT_DEPTH_ENABLED
uniform sampler2D _EnvironmentDepth;
#endif // ARCORE_ENVIRONMENT_DEPTH_ENABLED
#if defined(SHADER_API_GLES3) && !defined(UNITY_COLORSPACE_GAMMA)
float GammaToLinearSpaceExact (float value)
{
if (value <= 0.04045F)
return value / 12.92F;
else if (value < 1.0F)
return pow((value + 0.055F)/1.055F, 2.4F);
else
return pow(value, 2.2F);
}
vec3 GammaToLinearSpace (vec3 sRGB)
{
// Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
return sRGB * (sRGB * (sRGB * 0.305306011F + 0.682171111F) + 0.012522878F);
// Precise version, useful for debugging, but the pow() function is too slow.
// return vec3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b));
}
#endif // SHADER_API_GLES3 && !UNITY_COLORSPACE_GAMMA
float ConvertDistanceToDepth(float d)
{
d = _UnityCameraForwardScale > 0.0 ? _UnityCameraForwardScale * d : d;
float zBufferParamsW = 1.0 / _ProjectionParams.y;
float zBufferParamsY = _ProjectionParams.z * zBufferParamsW;
float zBufferParamsX = 1.0 - zBufferParamsY;
float zBufferParamsZ = zBufferParamsX * _ProjectionParams.w;
// Clip any distances smaller than the near clip plane, and compute the depth value from the distance.
return (d < _ProjectionParams.y) ? 1.0f : ((1.0 / zBufferParamsZ) * ((1.0 / d) - zBufferParamsW));
}
void main()
{
#ifdef SHADER_API_GLES3
vec3 result = texture(_MainTex, textureCoord).xyz;
float depth = 1.0;
#ifdef ARCORE_ENVIRONMENT_DEPTH_ENABLED
float distance = texture(_EnvironmentDepth, textureCoord).x;
depth = ConvertDistanceToDepth(distance);
#endif // ARCORE_ENVIRONMENT_DEPTH_ENABLED
#ifndef UNITY_COLORSPACE_GAMMA
result = GammaToLinearSpace(result);
#endif // !UNITY_COLORSPACE_GAMMA
gl_FragColor = vec4(result, 1.0);
gl_FragDepth = depth;
#endif // SHADER_API_GLES3
}
#endif // FRAGMENT
ENDGLSL
}
}
FallBack Off
}
My Fix (I do not see any performance improvement but at least the first pass is not broken anymore):
Shader "Unlit/ARCoreOcclusionFix"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_EnvironmentDepth("Texture", 2D) = "black" {}
}
SubShader
{
Name "ARCore Background (After Opaques)"
Tags
{
"Queue" = "Background"
"RenderType" = "Background"
"ForceNoShadowCasting" = "True"
}
Pass
{
Name "ARCore Background Occlusion Handling"
Cull Off
ZTest GEqual
ZWrite On
Lighting Off
LOD 100
Tags
{
"LightMode" = "Always"
}
GLSLPROGRAM
#pragma multi_compile_local __ ARCORE_ENVIRONMENT_DEPTH_ENABLED
#pragma only_renderers gles3
#include "UnityCG.glslinc"
#ifdef SHADER_API_GLES3
#extension GL_OES_EGL_image_external_essl3 : require
#endif // SHADER_API_GLES3
// Device display transform is provided by the AR Foundation camera background renderer.
uniform mat4 _UnityDisplayTransform;
#ifdef VERTEX
varying vec2 textureCoordQuad;
varying vec2 textureCoordEnvironment;
void main()
{
#if defined(SHADER_API_GLES3) && defined(ARCORE_ENVIRONMENT_DEPTH_ENABLED)
// Transform the position from object space to clip space.
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
// Get quad uvs for sampling camera texture
textureCoordQuad = vec2(gl_MultiTexCoord0.x, gl_MultiTexCoord0.y);
// Remap the texture coordinates based on the device rotation.
textureCoordEnvironment = (_UnityDisplayTransform * vec4(gl_MultiTexCoord0.x, 1.0f - gl_MultiTexCoord0.y, 1.0f, 0.0f)).xy;
#endif // SHADER_API_GLES3 && ARCORE_ENVIRONMENT_DEPTH_ENABLED
}
#endif // VERTEX
#ifdef FRAGMENT
varying vec2 textureCoordQuad;
varying vec2 textureCoordEnvironment;
uniform float _UnityCameraForwardScale;
uniform samplerExternalOES _MainTex;
#ifdef ARCORE_ENVIRONMENT_DEPTH_ENABLED
uniform sampler2D _EnvironmentDepth;
uniform sampler2D _CameraDepthTexture;
#endif // ARCORE_ENVIRONMENT_DEPTH_ENABLED
float ConvertDistanceToDepth(float d)
{
d = _UnityCameraForwardScale > 0.0 ? _UnityCameraForwardScale * d : d;
float zBufferParamsW = 1.0 / _ProjectionParams.y;
float zBufferParamsY = _ProjectionParams.z * zBufferParamsW;
float zBufferParamsX = 1.0 - zBufferParamsY;
float zBufferParamsZ = zBufferParamsX * _ProjectionParams.w;
// Clip any distances smaller than the near clip plane, and compute the depth value from the distance.
return (d < _ProjectionParams.y) ? 1.0f : ((1.0 / zBufferParamsZ) * ((1.0 / d) - zBufferParamsW));
}
vec3 GammaToLinearSpace(vec3 sRGB)
{
// Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
return sRGB * (sRGB * (sRGB * 0.305306011F + 0.682171111F) + 0.012522878F);
// Precise version, useful for debugging, but the pow() function is too slow.
// return vec3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b));
}
void main()
{
#if defined(SHADER_API_GLES3) && defined(ARCORE_ENVIRONMENT_DEPTH_ENABLED)
vec3 result = texture(_MainTex, textureCoordEnvironment).xyz;
float depth = texture(_CameraDepthTexture, textureCoordQuad).x;
float distance = texture(_EnvironmentDepth, textureCoordEnvironment).x;
float environmentDepth = ConvertDistanceToDepth(distance);
#ifndef UNITY_COLORSPACE_GAMMA
result = GammaToLinearSpace(result);
#endif // !UNITY_COLORSPACE_GAMMA
if (depth >= environmentDepth)
{
discard;
}
gl_FragColor = vec4(result, 1.0);
gl_FragDepth = depth;
#endif // SHADER_API_GLES3 && ARCORE_ENVIRONMENT_DEPTH_ENABLED
}
#endif // FRAGMENT
ENDGLSL
}
Pass
{
Name "AR Camera Background (ARCore)"
Cull Off
ZTest LEqual
ZWrite On
Lighting Off
LOD 100
Tags
{
"LightMode" = "Always"
}
GLSLPROGRAM
#pragma multi_compile_local __ ARCORE_ENVIRONMENT_DEPTH_ENABLED
#pragma only_renderers gles3
#include "UnityCG.glslinc"
#ifdef SHADER_API_GLES3
#extension GL_OES_EGL_image_external_essl3 : require
#endif // SHADER_API_GLES3
// Device display transform is provided by the AR Foundation camera background renderer.
uniform mat4 _UnityDisplayTransform;
#ifdef VERTEX
varying vec2 textureCoord;
void main()
{
#ifdef SHADER_API_GLES3
// Transform the position from object space to clip space.
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
// Remap the texture coordinates based on the device rotation.
textureCoord = (_UnityDisplayTransform * vec4(gl_MultiTexCoord0.x, 1.0f - gl_MultiTexCoord0.y, 1.0f, 0.0f)).xy;
#endif // SHADER_API_GLES3
}
#endif // VERTEX
#ifdef FRAGMENT
varying vec2 textureCoord;
uniform samplerExternalOES _MainTex;
uniform float _UnityCameraForwardScale;
#ifdef ARCORE_ENVIRONMENT_DEPTH_ENABLED
uniform sampler2D _EnvironmentDepth;
#endif // ARCORE_ENVIRONMENT_DEPTH_ENABLED
#if defined(SHADER_API_GLES3) && !defined(UNITY_COLORSPACE_GAMMA)
float GammaToLinearSpaceExact(float value)
{
if (value <= 0.04045F)
return value / 12.92F;
else if (value < 1.0F)
return pow((value + 0.055F) / 1.055F, 2.4F);
else
return pow(value, 2.2F);
}
vec3 GammaToLinearSpace(vec3 sRGB)
{
// Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
return sRGB * (sRGB * (sRGB * 0.305306011F + 0.682171111F) + 0.012522878F);
// Precise version, useful for debugging, but the pow() function is too slow.
// return vec3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b));
}
#endif // SHADER_API_GLES3 && !UNITY_COLORSPACE_GAMMA
float ConvertDistanceToDepth(float d)
{
d = _UnityCameraForwardScale > 0.0 ? _UnityCameraForwardScale * d : d;
float zBufferParamsW = 1.0 / _ProjectionParams.y;
float zBufferParamsY = _ProjectionParams.z * zBufferParamsW;
float zBufferParamsX = 1.0 - zBufferParamsY;
float zBufferParamsZ = zBufferParamsX * _ProjectionParams.w;
// Clip any distances smaller than the near clip plane, and compute the depth value from the distance.
return (d < _ProjectionParams.y) ? 1.0f : ((1.0 / zBufferParamsZ) * ((1.0 / d) - zBufferParamsW));
}
void main()
{
#ifdef SHADER_API_GLES3
vec3 result = texture(_MainTex, textureCoord).xyz;
float depth = 1.0;
#ifdef ARCORE_ENVIRONMENT_DEPTH_ENABLED
float distance = texture(_EnvironmentDepth, textureCoord).x;
depth = ConvertDistanceToDepth(distance);
#endif // ARCORE_ENVIRONMENT_DEPTH_ENABLED
#ifndef UNITY_COLORSPACE_GAMMA
result = GammaToLinearSpace(result);
#endif // !UNITY_COLORSPACE_GAMMA
gl_FragColor = vec4(result, 1.0);
gl_FragDepth = depth;
#endif // SHADER_API_GLES3
}
#endif // FRAGMENT
ENDGLSL
}
}
FallBack Off
}
Describe the bug I have installed AR Foundation v.5.0.2 and ARCore. The ARCore plugin uses the ARCoreBackgroundAfterOpaques.shader to occlude objects. There are two passes. The second one works fine. The first pass however, is broken. In this pass variables are used which are not defined, functions are used which are not defined and vectors are accessed wrong.
To Reproduce The wrong shader can be found under Packages -> Google ARCore XR Plugin -> Assets -> Shaders -> ARCoreBackgroundAfterOpaques.shader.
Expected behavior Normally the first pass should improve the performance as far as I understand since it is only discarding background pixels when the environment depth is telling the shader that those are behind the already drawn geometry.
Actual behavior But since the errors listed above the first pass is broken and does not do anything.
Smartphone (please complete the following information):
The wrong shader code:
My Fix (I do not see any performance improvement but at least the first pass is not broken anymore):