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

싱글 패스 인스턴스화 렌더링과 커스텀 셰이더

URP, HDRP, ShaderGraph, 표면 셰이더, 빌트인 셰이더는 이미 싱글 패스 스테레오 인스턴스화 렌더링을 지원합니다.하지만 에셋 스토어의 셰이더, 타사의 셰이더, 사용자가 직접 작성한 셰이더는 업데이트해야 할 수 있습니다.

셰이더에서의 인스턴스화 렌더링 지원에 대한 자세한 내용은 GPU 인스턴싱을 참조하십시오.이 섹션에서는 특히 스테레오 렌더링에 대한 내용을 설명하며 일반적으로 인스턴스화 렌더링을 지원하기 위해 수행해야 하는 모든 변경 사항을 포함하지 않을 수 있습니다.

버텍스 입력 속성 구조체 업데이트

UNITY_VERTEX_INPUT_INSTANCE_ID 매크로를 appdata 구조체에 추가합니다.

예:

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

    UNITY_VERTEX_INPUT_INSTANCE_ID //Insert
};

버텍스 출력 속성 구조체 업데이트

UNITY_VERTEX_OUTPUT_STEREO 매크로를 v2f 출력 구조체에 추가합니다.

예:

struct v2f
{
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;

    UNITY_VERTEX_OUTPUT_STEREO //Insert
};

메인 버텍스 셰이더 함수 업데이트

다음 매크로를 메인 vert 메서드의 처음에 추가합니다(순서대로).

  1. UNITY_SETUP_INSTANCE_ID()
  2. UNITY_INITIALIZE_OUTPUT(v2f, o)
  3. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO()

UNITY_SETUP_INSTANCE_ID()는 GPU가 어느 쪽 눈을 렌더링하느냐에 따라 빌트인 unity_StereoEyeIndexunity_InstanceID 셰이더 변수를 계산하여 올바른 값으로 설정합니다.

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
      }
   }
}

ShaderGraph 디버그 셰이더

ShaderGraph는 싱글 패스 스테레오 렌더링을 지원하는 데 필요한 매크로를 자동으로 추가합니다.ShaderGraph에서 디버그 셰이더를 구현하려면 눈 인덱스에 따라 기본 컬러를 설정하는 커스텀 함수 노드를 사용하면 됩니다.

unity_StereoEyeIndex 셰이더 속성을 사용하여 렌더링되는 눈 인스턴스에 따라 기본 컬러를 결정할 수 있습니다.위 예시의 커스텀 함수 노드에는 다음 코드가 포함되어 있습니다.

Out = lerp(LeftColor, RightColor, unity_StereoEyeIndex);
스테레오 렌더링
VR 프레임 타이밍