We are attempting to use the Depth Texture in a Shader which is executed from **CommandBuffer.Blit**
during the **CameraEvent.BeforeForwardOpaque**
, in Single-Pass Stereo. We are using Unity 5.6.0f3, but are open to upgrading if necessary.
I’ve done a fair amount of reading and come across a few good, slightly different, methods for doing this outside of Single-Pass:
I’ve mainly been looking at Keijiro’s example as it is the most simplistic. It works in Multi-Pass VR, but does not account for Single-Pass.
Where I see these methods going wrong with Single-Pass are:
- UV Coordinates do not account for a double-wide Frame Buffer
- Camera’s Projection Matrix != Eye Projection Matrix
- World Space Camera Pos != World Space Eye Position
- ‘CameraToWorld’ Matrix != ‘EyeToWorld’ Matrix
Possible resolutions are:
- Calculate these values CPU-side myself as late as possible.
- UnityShaderVariables.cginc appears to have these variables (provided they are correctly populated)
Here is what I am doing currently, for simplicity I will focus only on the Left Eye:
void OnPreRender()
{
mat.SetVector("_MyProjectionParams", new Vector4(
1f, // x is 1.0 (or –1.0 if currently rendering with a flipped projection matrix)
cam.nearClipPlane, // y is the camera’s near plane
cam.farClipPlane, // z is the camera’s far plane
1f / cam.farClipPlane // w is 1/FarPlane.
));
Matrix4x4 leftEye = cam.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left);
mat.SetMatrix("_LeftEyeProjection", leftEye);
Matrix4x4 leftToWorld = cam.GetStereoViewMatrix(Camera.StereoscopicEye.Left).inverse;
mat.SetMatrix("_LeftEyeToWorld", leftToWorld);
}
Note: The reason why I am calculating the projection parameters myself is that it seems that the projection is not populated correctly at the time of Blit.
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityShaderVariables.cginc"
#include "UnityCG.cginc"
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert (appdata_img v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
sampler2D_float _CameraDepthTexture;
float4x4 _LeftEyeProjection; // Left Eye's Projection Matrix
float4x4 _LeftEyeToWorld; // Left Eye's "cameraToWorldMatrix"
float4 _MyProjectionParams; // Same as _ProjectionParams, but calculated myself
fixed4 frag(v2f i) : SV_Target
{
float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
#if defined(UNITY_REVERSED_Z)
d = 1 - d;
#endif
const float near = _MyProjectionParams.y;
const float far = _MyProjectionParams.z;
const float zPers = near * far / lerp(far, near, d);
float3 worldPos = 0;
if (i.uv.x < .5) // Left Eye Only
{
float2 uv = i.uv;
uv.x = saturate(uv.x * 2); // 0..1 for left side of buffer
const float2 p11_22 = float2(_LeftEyeProjection._11, _LeftEyeProjection._22);
float4 vpos = float3((uv * 2 - 1) / p11_22 * zPers, -zPers, 1);
worldPos = mul(_LeftEyeToWorld, vpos).xyz;
}
else
{
return 0; // TODO: Right Eye
}
half3 color = pow(abs(cos(worldPos * UNITY_PI * 4)), 20);
return fixed4(color, 1);
}
ENDCG
What I see when in the RenderTexture is this:
[gifv here]
I feel that this is close as the X & Z axis seem to be mostly static. My guess is that where this is going wrong is actually the Eye-To-World step as, from what I can tell, viewing the View Position looks correct to me. Of couse, I could be wrong in that observation.
Upon changing some values out with Unity-provided ones in ‘UnityShaderVariables.cginc’, I don’t see much of a difference. What I see available to me is:
#if defined(USING_STEREO_MATRICES)
CBUFFER_START(UnityStereoGlobals)
float4x4 unity_StereoMatrixP[2];
float4x4 unity_StereoMatrixV[2];
float4x4 unity_StereoMatrixInvV[2];
float4x4 unity_StereoMatrixVP[2];
float4x4 unity_StereoCameraProjection[2];
float4x4 unity_StereoCameraInvProjection[2];
float4x4 unity_StereoWorldToCamera[2];
float4x4 unity_StereoCameraToWorld[2];
float3 unity_StereoWorldSpaceCameraPos[2];
float4 unity_StereoScaleOffset[2];
CBUFFER_END
#endif
This leads me to believe that what I’m calculating myself is correct, but I am simply just missing a step that is unique to Single-Pass.
If anyone has any additional insight, it would be greatly appreciated.
Thanks in advance.
==