URP, HDRP, ShaderGraph, Surface shaders, and built-in shaders already support single-pass stereo instanced rendering. However, shaders from the Asset Store, from other third parties, or those that you have written yourself might need to be updated.
For more information about supporting instanced rendering in your shaders, see GPU Instancing. The information in this section specifically talks about stereo rendering and might not include all changes you need to make to support instanced rendering in general.
Add the UNITY_VERTEX_INPUT_INSTANCE_ID
macro to the appdata
struct.
示例:
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID //插入
};
Add UNITY_VERTEX_OUTPUT_STEREO
macro to the v2f
output struct.
示例:
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO //插入
};
Add the following macros to the beginning of your main vert
method (in order):
UNITY_SETUP_INSTANCE_ID()
UNITY_INITIALIZE_OUTPUT(v2f, o)
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO()
UNITY_SETUP_INSTANCE_ID()
calculates and sets the built-in unity_StereoEyeIndex
and unity_InstanceID
shader variables to the correct values based on which eye the GPU is currently rendering.
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO
根据 unity_StereoEyeIndex
的值告诉 GPU 应该渲染到纹理数组中的哪只眼睛。此宏还从顶点着色器传输 unity_StereoEyeIndex
的值,确保仅当在片元着色器 frag
方法中调用 UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX
时才能在片元着色器中访问该值。
UNITY_INITALIZE_OUTPUT(v2f,o)
将所有 v2f
值初始化为 0。
示例:
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v); //插入
UNITY_INITIALIZE_OUTPUT(v2f, o); //插入
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //插入
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
If you want your Post-Processing shaders to support single-pass stereo instancing, follow the steps for custom shaders as well as the steps below.
Note: You can download all Unity base shader scripts from the Unity website.
Do the following for each Post-Processing shader that you want to support single-pass instancing:
Add the UNITY_DECLARE_SCREENSPACE_TEXTURE(tex) macro outside the frag method (see the example below for placement) in your Shader script, so that when you use a particular stereo rendering method the GPU uses the appropriate texture sampler. For example, if you use multi-pass rendering, the GPU uses a texture 2D sampler. For single-pass instancing or multi-view rendering, the texture sampler is a texture array.
Add UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i)
at the beginning of the fragment shader frag method (See the example below for placement). You only need to add this macro if you want to use the unity_StereoEyeIndex
built-in shader variable to find out which eye the GPU is rendering to. This is useful when testing post-processing effects.
Use the UNITY_SAMPLE_SCREENSPACE_TEXTURE()
macro when sampling 2D textures (See the example below). Standard shaders use a 2D texture-based back buffer to sample textures. Single-pass stereo instancing does not use this type of back buffer, so if you do not specify a different method for 2D texture sampling, your shader does not render correctly. To prevent rendering issues, the UNITY_SAMPLE_SCREENSPACE_TEXTURE()
macro detects which stereo rendering path you are using and then automatically samples the texture in the correct manner. See Unity documentation on HLSLSupport.cginc to learn more about similar macros used for depth textures and screen-space shadow maps.
示例:
UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex); //插入
fixed4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); //插入
fixed4 col = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv); //插入
// 仅插入颜色
col = 1 - col;
return col;
}
Below is a simple example of the template image effect shader with all of the previously mentioned changes applied to support single-pass stereo instancing. The lines added to the shader code are marked with the comment: //Insert
.
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID //插入
};
//v2f 输出结构
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO //插入
};
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v); //插入
UNITY_INITIALIZE_OUTPUT(v2f, o); //插入
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //插入
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex); //插入
fixed4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); //插入
fixed4 col = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv); //插入
// 插入颜色
col = 1 - col;
return col;
}
If you use the Graphics.DrawProceduralIndirect() and CommandBuffer.DrawProceduralIndirect() methods to draw fully procedural geometry on the GPU, note that both methods receive their arguments from a compute buffer. This means that it is difficult to increase the instance count at run time. To increase the instance count, you must manually double the instance count contained in your compute buffers.
以下着色器代码将游戏对象渲染为绿色(用户左眼)和红色(右眼)。此着色器对于调试立体渲染非常有用,因为它可用于验证所有立体图形是否正常工作。
Shader "XR/StereoEyeIndexColor"
{
Properties
{
_LeftEyeColor("Left Eye Color", COLOR) = (0,1,0,1)
_RightEyeColor("Right Eye Color", COLOR) = (1,0,0,1)
}
SubShader
{
Tags { "RenderType" = "Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 _LeftEyeColor;
float4 _RightEyeColor;
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_OUTPUT(v2f, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
return lerp(_LeftEyeColor, _RightEyeColor, unity_StereoEyeIndex);
}
ENDCG
}
}
}
ShaderGraph automatically adds the macros required to support single-pass stereo rendering. To implement the debug shader in ShaderGraph you can use a Custom Function Node that sets the base color based on the eye index.
Use the unity_StereoEyeIndex
shader attribute to determine the base color depending on which eye instance is being rendered. The Custom Function Node in the example above contains the following code:
Out = lerp(LeftColor, RightColor, unity_StereoEyeIndex);