Chiming in, since this about the only thread on the subject!
I’ve been struggling with the same issues the past few days. When using Single Pass Instanced rendering I’d simply get a Gray/Black image on the left & right eye, respectively. That is when using ScriptableRenderPass.Blit to do anything. This otherwise worked fine in 2019.4.
Unity’s “ColorCopy” pass calls RenderingUtils.Blit, which uses cmd.DrawProcedural if XR rendering is in use, and cmd.Blit otherwise. Harsh irony is that this function is inaccessible because it’s internal. But adopting the same functionality does make a difference:
Execute function
if (renderingData.cameraData.xrRendering)
{
cmd.SetRenderTarget(new RenderTargetIdentifier(cameraColorTarget, 0, CubemapFace.Unknown, -1), RenderBufferLoadAction.Load, RenderBufferStoreAction.Store);
cmd.DrawProcedural(Matrix4x4.identity, Material, 0, MeshTopology.Quads, 4, 1, null);
}
else
{
cmd.SetRenderTarget(cameraColorTarget);
Blit(cmd, mainTexHandle.id, cameraColorTarget, Material, 0);
}
Off this bat this didn’t appear to work. The pass was blitting into the render target, but nothing appeared to write into it. Apparently because the quad’s vertices weren’t being properly transformed into clip space.
Shader
To make this work, certain functions have to be used in the vertex shader used by the blitting material:
struct FullScreenAttributes
{
float3 positionOS : POSITION;
float2 uv : TEXCOORD0;
#if defined(STEREO_INSTANCING_ON) || _USE_DRAW_PROCEDURAL
uint vertexID : SV_VertexID;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct FullScreenVaryings
{
half4 positionCS : SV_POSITION;
half2 uv : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
FullScreenVaryings Vertex(FullScreenAttributes input)
{
FullScreenVaryings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
#if VERSION_GREATER_EQUAL(10,0) && defined(STEREO_INSTANCING_ON) || _USE_DRAW_PROCEDURAL
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
output.uv.xy = GetFullScreenTriangleTexCoord(input.vertexID);
#else
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv.xy = input.uv;
#endif
return output;
}
This requires adding
#if VERSION_GREATER_EQUAL(12,0)
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#else
#include "Packages/com.unity.render-pipelines.universal/Shaders/Utils/Fullscreen.hlsl"
#endif
You can actually just use the vertex shaders declared in this library, but it requires adding the following before executing a faux-Blit command. RenderingUtils.Blit also does this and the values are also constants.
cmd.SetGlobalVector("_BlitScaleBiasRt", new Vector4(1,1,0,0));
cmd.SetGlobalVector("_BlitScaleBias", new Vector4(1,1,0,0));
After adopting these changes I’m able to properly do proper blits to the camera’s color target for both eyes, in both 2020.3 and 2021.2. What @daneobyrd mentioned about the TEXTURE2D_X definitely holds true, since render targets are texture arrays when using SPI.
Notes:
- The
this.Blit(cmd, ref renderingData, Material, 0); function that uses a swap buffer, introduced in 2021.2, won’t work. Since it doesn’t use cmd.DrawProcedural for VR.
- In Unity 2020.3 the shader requires
#pragma multi_compile _ _USE_DRAW_PROCEDURAL (now obsolete)
- For simply copy Blit’s, you can use a material with the
“Hidden/Universal Render Pipeline/Blit” shader. And use cmd.SetGlobalTexture("
_SourceTex", ); to set the input/source.
- 2022.1 introduces a whole new paradigm involving the RTHandles system. Which likely means starting over.
That’s my harvest of the day, good luck! 