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 //Insert
};
Add UNITY_VERTEX_OUTPUT_STEREO
macro to the v2f
output struct.
예:
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO //Insert
};
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()
는 GPU가 어느 쪽 눈을 렌더링하느냐에 따라 빌트인 unity_StereoEyeIndex
및 unity_InstanceID
셰이더 변수를 계산하여 올바른 값으로 설정합니다.
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); //Insert
UNITY_INITIALIZE_OUTPUT(v2f, o); //Insert
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert
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); //Insert
fixed4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); //Insert
fixed4 col = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv); //Insert
// just invert the colors
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 //Insert
};
//v2f output struct
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO //Insert
};
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v); //Insert
UNITY_INITIALIZE_OUTPUT(v2f, o); //Insert
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex); //Insert
fixed4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); //Insert
fixed4 col = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv); //Insert
// invert the colors
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);