Version: 2022.1
언어: 한국어
스테레오 렌더링
VR 프레임 타이밍

Single Pass Instanced rendering and custom shaders

URPO, HDRP, and built-in shaders already support single-pass instanced rendering. However, shaders from the Asset Store, from other third parties, or those that you have written yourself might need to be updated.

아래의 지침을 따르기 전에 인스턴싱을 사용할 수 있도록 커스텀 셰이더를 업데이트하십시오(GPU 인스턴싱 참조).

그런 다음, 커스텀 셰이더의 프래그먼트 셰이더(Vertex/Hull/Domain/Geometry) 전에 사용된 마지막 셰이더 단계에서 두 가지를 추가로 변경해야 합니다.

각 커스텀 셰이더에 대해 싱글 패스 인스턴스화를 지원하고 싶다면 다음 단계를 따르십시오.

1단계: UNITY_VERTEX_INPUT_INSTANCE_IDappdata struct에 추가합니다.

예:

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;

    UNITY_VERTEX_INPUT_INSTANCE_ID //Insert
};

2단계: UNITY_VERTEX_OUTPUT_STEREOv2f 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_StereoEyeIndexunity_InstanceID Unity 셰이더 변수를 계산하여 올바른 값으로 설정합니다.

UNITY_INITIALIZE_VERTEX_OUTPUT_STEREOunity_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
      }
   }
}
스테레오 렌더링
VR 프레임 타이밍