Single Pass Instanced 렌더링(’스테레오 인스턴싱’이라고도 불림)을 사용하면 GPU가 단일 렌더 패스를 수행하여 각 드로우 콜을 인스턴스화된 드로우 콜로 교체합니다. 이렇게 하면 두 드로우 콜 간의 캐시 일관성으로 인해 CPU 사용이 대폭 감소하고, GPU 사용은 소폭 감소합니다. 또한 애플리케이션의 전력 소비도 크게 절감됩니다.
VPAndRTArrayIndexFromAnyShaderFeedingRasterizer
확장자를 지원해야 합니다.GL_NV_viewport_array2
GL_AMD_vertex_shader_layer
GL_ARB_shader_viewport_layer_array
참고: 디퍼드 렌더링을 사용하는 경우 Unity는 레거시 렌더 파이프라인에서 싱글 패스 스테레오 인스턴싱을 지원하지 않습니다.
이 기능을 활성화하려면 Player 설정(Edit > Project Settings 로 이동한 다음 Player 카테고리 선택)을 엽니다. Player 설정에서 하단의 XR Settings 패널로 이동하고 Virtual Reality Supported 옵션을 선택한 후 Stereo Rendering Method 드롭다운 메뉴에서 Single Pass Instanced (Preview) 를 선택합니다.
기본 Stereo Rendering Method 는 Multi Pass 입니다. 이 설정은 느리지만, 대개 커스텀 셰이더와 사용하면 효과적입니다. 커스텀 셰이더가 있는 경우 Single Pass Instanced 렌더링과 호환되도록 변경해야 할 수 있습니다.
아래의 지침을 따르기 전에 인스턴싱을 사용할 수 있도록 커스텀 셰이더를 업데이트하십시오(GPU 인스턴싱 참조).
그런 다음, 커스텀 셰이더의 프래그먼트 셰이더(Vertex/Hull/Domain/Geometry) 전에 사용된 마지막 셰이더 단계에서 두 가지를 추가로 변경해야 합니다.
각 커스텀 셰이더에 대해 싱글 패스 인스턴스화를 지원하고 싶다면 다음 단계를 따르십시오.
1단계: UNITY_VERTEX_INPUT_INSTANCE_ID
를 appdata struct
에 추가합니다.
예:
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID //Insert
};
2단계: UNITY_VERTEX_OUTPUT_STEREO
를 v2f output struct
에 추가합니다.
예:
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO //Insert
};
3단계: 메인 vert
메서드 시작 시 UNITY_SETUP_INSTANCE_ID()
매크로를 추가한 후 UNITY_INITIALIZE_OUTPUT(v2f, o)
및 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO()
를 호출합니다.
UNITY_SETUP_INSTANCE_ID()
는 GPU가 어느 쪽 눈을 렌더링하느냐에 따라 빌트인 unity_StereoEyeIndex
및 unity_InstanceID
Unity 셰이더 변수를 계산하여 올바른 값으로 설정합니다.
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;
}
포스트 프로세싱 셰이더가 싱글 패스 인스턴스화를 지원하도록 만들고 싶으면 커스텀 셰이더의 단계와 아래 단계를 따르십시오. 모든 Unity 기본 셰이더 스크립트는 Unity 웹사이트에서 다운로드할 수 있습니다.
싱글 패스 인스턴스화를 지원하도록 만들 각 포스트 프로세싱 셰이더에 대해 다음을 수행하십시오.
1단계: 특정 스테레오 렌더링 메서드 사용 시 GPU가 그에 적합한 텍스처 샘플러를 사용할 수 있도록 frag 메서드 외부의 UNITY_DECLARE_SCREENSPACE_TEXTURE(tex) 매크로를 셰이더 스크립트에 추가합니다(아래의 배치 예시 참조). 예를 들어, 멀티 패스 렌더링을 사용하는 경우 GPU가 텍스처 2D 샘플러를 사용합니다. 싱글 패스 인스턴스화 또는 멀티 뷰 렌더링의 경우 텍스처 샘플러는 텍스처 배열입니다.
2단계: 프래그먼트 셰이더 frag 메서드 시작 시 UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i)
를 추가합니다(아래의 배치 예시 참조). 이 매크로만 추가하면 unity_StereoEyeIndex
빌트인 셰이더 변수를 사용하여 GPU가 어느 쪽 눈에 대해 렌더링하고 있는지 확인할 수 있습니다. 이 기능은 포스트 프로세싱 효과를 테스트할 때 유용합니다.
3단계: UNITY_SAMPLE_SCREENSPACE_TEXTURE()
매크로를 사용하여 2D 텍스처를 샘플링합니다(아래의 배치 예시 참조). 스탠다드 셰이더는 2D 텍스처 기반 백 버퍼를 사용하여 텍스처를 샘플링합니다. 싱글 패스 스테레오 인스턴싱은 이 타입의 백 버퍼를 사용하지 않습니다. 따라서 2D 텍스처 샘플링에 다른 메서드를 지정하지 않으면 셰이더가 제대로 렌더링하지 못합니다. 이러한 렌더링 문제를 막기 위해 UNITY_SAMPLE_SCREENSPACE_TEXTURE()
매크로는 어느 스테레오 렌더링 경로가 사용 중인지 감지한 후 올바른 방식으로 텍스처를 자동 샘플링합니다. 뎁스 텍스처 및 스크린 공간 섀도우 맵에 사용되는 유사한 매크로에 대한 내용은 HLSLSupport.cginc에 대한 Unity 기술 자료를 확인하십시오.
예:
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;
}
아래는 템플릿 이미지 효과 셰이더의 간단한 예제이며 이전에 언급한 모든 변경 사항을 적용하여 싱글 패스 인스턴스화를 지원하도록 만들었습니다. 셰이더 코드에 대한 추가 부분은 코멘트(//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;
}
Graphics.DrawProceduralIndirect() 및 CommandBuffer.DrawProceduralIndirect() 메서드를 사용하여 GPU의 절차적 지오메트리를 완전히 드로우할 때는 두 메서드 모두 컴퓨트 버퍼에서 인자를 받는다는 점에 유의하십시오. 따라서 런타임 시점에 인스턴스 수를 늘리기가 어렵습니다. 인스턴스 수를 늘리려면 컴퓨트 버퍼에 포함된 인스턴스 수를 수동으로 두 배로 만들어야 합니다.
다음 셰이더 코드는 사용자의 왼쪽 눈에는 녹색으로, 사용자의 오른쪽 눈에는 적색으로 게임 오브젝트를 렌더링합니다. 이 셰이더를 사용하면 모든 스테레오 그래픽스가 제대로 동작 및 기능하는지 확인할 수 있기 때문에 스테레오 렌더링을 디버그할 때 특히 유용합니다.
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
}
}
}