{}!Google Tag Manager end}} 뎁스 텍스처에서 픽셀의 월드 공간 포지션 재구성 | Universal RP | 14.0.9
docs.unity3d.com
    목차 표시/숨기기

    뎁스 텍스처에서 픽셀의 월드 공간 포지션 재구성

    이 예제의 Unity 셰이더는 뎁스 텍스처와 스크린 공간 UV 좌표를 사용하여 픽셀의 월드 공간 포지션을 재구성합니다. 셰이더는 포지션을 시각화하기 위해 메시 위에 체커보드 패턴을 그립니다.

    다음 그림에 최종 결과가 나와 있습니다.

    재구성한 월드 공간 포지션을 시각화하는 체커보드 패턴.

    이 페이지는 다음 섹션으로 구성됩니다.

    • 샘플 씬 생성

    • ShaderLab 코드 편집

    • 완전한 ShaderLab 코드

    샘플 씬 생성

    샘플 씬을 생성하려면 이 섹션의 다음 단계를 따르십시오.

    1. 기존 Unity 프로젝트에 URP를 설치하거나, 유니버설 프로젝트 템플릿을 사용하여 새 프로젝트를 생성합니다.

    2. 샘플 씬에서 평면 게임 오브젝트를 생성하고 일부 게임 오브젝트를 가리도록 배치합니다.

      평면 생성

    3. 새 머티리얼을 생성하여 평면에 할당합니다.

    4. 새 셰이더를 생성하여 머티리얼에 할당합니다. URP 언릿 기본 셰이더 페이지의 Unity 셰이더 소스 코드를 복사하여 붙여넣습니다.

    5. URP 에셋을 선택합니다. 유니버설 렌더 파이프라인 템플릿을 사용하여 프로젝트를 생성한 경우 URP 에셋 경로는 Assets/Settings/UniversalRP-HighQuality입니다.

    6. URP 에셋의 General 섹션에서 Depth Texture를 활성화합니다.

      URP 에셋에서 Depth Texture 활성화

    7. 4단계에서 생성한 셰이더를 엽니다.

    ShaderLab 코드 편집

    이 섹션에서는 URP 언릿 기본 셰이더 페이지의 소스 코드를 붙여넣었다고 가정합니다.

    ShaderLab 코드를 다음과 같이 변경하십시오.

    1. HLSLPROGRAM 블록에서 뎁스 텍스처 셰이더 헤더에 대한 include 선언을 추가합니다. 예를 들어 Core.hlsl에 대한 기존 include 선언 아래에 배치할 수 있습니다.

      #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
      
      // DeclareDepthTexture.hlsl 파일에는 카메라 뎁스 텍스처를 샘플링하기 위한 유틸리티가
      // 포함되어 있습니다.
      #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
      

      DeclareDepthTexture.hlsl 파일에는 카메라 뎁스 텍스처를 샘플링하기 위한 함수가 포함되어 있습니다. 이 예제에서는 SampleSceneDepth 함수를 사용하여 픽셀의 Z 좌표를 샘플링합니다.

    2. 프래그먼트 셰이더 정의에 Varyings IN을 입력으로 추가합니다.

      half4 frag(Varyings IN) : SV_Target
      

      이 예제에서 프래그먼트 셰이더는 Varyings 구조체의 positionHCS 프로퍼티를 사용하여 픽셀의 위치를 가져옵니다.

    3. 프래그먼트 셰이더에서 뎁스 버퍼를 샘플링하기 위한 UV 좌표를 계산하려면 픽셀 위치를 렌더 타겟 해상도 _ScaledScreenParams로 나눕니다. _ScaledScreenParams.xy 프로퍼티는 다이내믹 해상도와 같은 렌더 타겟의 모든 스케일링을 고려합니다.

      float2 UV = IN.positionHCS.xy / _ScaledScreenParams.xy;
      
    4. 프래그먼트 셰이더에서 SampleSceneDepth 함수를 사용하여 뎁스 버퍼를 샘플링합니다.

      #if UNITY_REVERSED_Z
          real depth = SampleSceneDepth(UV);
      #else
          // Z를 조정하여 OpenGL용 NDC에 맞춥니다.
          real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
      #endif
      

      SampleSceneDepth 함수는 DeclareDepthTexture.hlsl 파일에서 가져옵니다. 이 함수는 [0, 1] 범위의 Z값을 반환합니다.

      재구성 함수(ComputeWorldSpacePosition)가 작동하려면 뎁스값이 NDC(Normalized Device Coordinate) 공간에 있어야 합니다. D3D에서 Z는 [0,1] 범위이고, OpenGL에서 Z는 [-1, 1] 범위입니다.

      이 예제에서는 UNITY_REVERSED_Z 상수를 사용하여 플랫폼을 결정하고 Z 값 범위를 조정합니다. 자세한 설명은 이 예제의 6단계를 참조하십시오.

      UNITY_NEAR_CLIP_VALUE 변수는 클립 공간에 대한 플랫폼 독립적인 근거리 클리핑 평면 값입니다.

      자세한 내용은 플랫폼별 렌더링 차이를 참조하십시오.

    5. 픽셀의 UV 및 Z 좌표에서 월드 공간 포지션을 재구성합니다.

      float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);
      

      ComputeWorldSpacePosition은 UV와 뎁스(Z) 값으로부터 월드 공간 포지션을 계산하는 유틸리티 함수입니다. 이 함수는 SRP 코어 패키지의 Common.hlsl 파일에 정의되어 있습니다.

      UNITY_MATRIX_I_VP는 클립 공간에서 월드 공간으로 포인트를 변환하는 인버스 뷰 투사 매트릭스입니다.

    6. 픽셀의 월드 공간 포지션을 시각화하기 위해 체커보드 효과를 만듭니다.

      uint scale = 10;
      uint3 worldIntPos = uint3(abs(worldPos.xyz * scale));
      bool white = (worldIntPos.x & 1) ^ (worldIntPos.y & 1) ^ (worldIntPos.z & 1);
      half4 color = white ? half4(1,1,1,1) : half4(0,0,0,1);
      

      scale은 체커보드 패턴 크기의 인버스 스케일입니다.

      abs 함수는 패턴을 음의 좌표 쪽으로 미러링합니다.

      worldIntPos 변수에 대한 uint3 선언은 좌표 포지션을 정수로 스내핑합니다.

      <integer value> & 1 표현식의 AND 연산자는 값이 짝수(0) 또는 홀수(1)인지 확인합니다. 이 표현식을 통해 코드는 표면을 사각형으로 나눕니다.

      <integer value> ^ <integer value> 표현식의 XOR 연산자는 사각형 컬러를 반전합니다.

      지오메트리가 렌더링되지 않는 영역의 경우 뎁스 버퍼에 유효한 값이 없을 수 있습니다. 다음 코드는 이러한 영역에 검은색을 그립니다.

      #if UNITY_REVERSED_Z
          if(depth < 0.0001)
              return half4(0,0,0,1);
      #else
          if(depth > 0.9999)
              return half4(0,0,0,1);
      #endif
      

      플랫폼마다 원거리 클리핑 평면에 다른 Z 값을 사용합니다(0 == far 또는 1 == far). UNITY_REVERSED_Z 상수를 사용하면 코드가 모든 플랫폼을 올바르게 처리할 수 있습니다.

      셰이더 코드를 저장하면 예제가 준비됩니다.

    다음 그림에 최종 결과가 나와 있습니다.

    3D 체커보드

    완전한 ShaderLab 코드

    아래는 이 예제의 완전한 ShaderLab 코드입니다.

    // 이 Unity 셰이더는 뎁스 텍스처와 스크린 공간 UV 좌표를 사용하여
    // 픽셀의 월드 공간 포지션을 재구성합니다. 셰이더는 메시 위에 체커보드 패턴을 그려서
    // 포지션을 시각화합니다.
    Shader "Example/URPReconstructWorldPos"
    {
        Properties
        { }
    
        // 셰이더 코드가 포함된 서브셰이더 블록입니다.
        SubShader
        {
            // 서브셰이더 태그는 서브셰이더 블록 또는 패스가 실행되는 시기와
            // 조건을 정의합니다.
            Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
    
            Pass
            {
                HLSLPROGRAM
                // 이 줄은 버텍스 셰이더의 이름을 정의합니다.
                #pragma vertex vert
                // 이 줄은 프래그먼트 셰이더의 이름을 정의합니다.
                #pragma fragment frag
    
                // Core.hlsl 파일에는 자주 사용되는 HLSL 매크로 및 함수에 대한 정의가 포함되어 있으며,
                // 다른 HLSL 파일(예: Common.hlsl, SpaceTransforms.hlsl 등)에 대한
                // #include 레퍼런스도 포함되어 있습니다.
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    
                // DeclareDepthTexture.hlsl 파일에는 카메라 뎁스 텍스처를 샘플링하기 위한 유틸리티가
                // 포함되어 있습니다.
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
    
                // 이 예제에서는 버텍스 셰이더의 입력 구조로 Attributes
                // 구조를 사용합니다.
                struct Attributes
                {
                    // positionOS 변수에는 오브젝트 공간의 버텍스 포지션이
                    // 포함됩니다.
                    float4 positionOS   : POSITION;
                };
    
                struct Varyings
                {
                    // 이 구조체의 포지션에는 SV_POSITION 시맨틱이 있어야 합니다.
                    float4 positionHCS  : SV_POSITION;
                };
    
                // Varyings 구조에 정의된 프로퍼티가 있는 버텍스 셰이더
                // 정의입니다. vert 함수의 타입은 반환하는 타입(구조체)과
                // 일치해야 합니다.
                Varyings vert(Attributes IN)
                {
                    // 출력 오브젝트(OUT)를 Varyings 구조체로 선언합니다.
                    Varyings OUT;
                    // TransformObjectToHClip 함수는 버텍스 포지션을 오브젝트 공간에서
                    // 균일한 클립 공간으로 변환합니다.
                    OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
                    // 출력을 반환합니다.
                    return OUT;
                }
    
                // 프래그먼트 셰이더 정의입니다.
                // Varying 입력 구조에는 버텍스 셰이더에서 보간된 값이
                // 포함됩니다. 프래그먼트 셰이더는 `Varyings` 구조체의 `positionHCS`
                // 프로퍼티를 사용하여 픽셀의 위치를 가져옵니다.
                half4 frag(Varyings IN) : SV_Target
                {
                    // 뎁스 버퍼를 샘플링하기 위한 UV 좌표를 계산하려면
                    // 픽셀 위치를 렌더 타겟 해상도 _ScaledScreenParams로
                    // 나눕니다.
                    float2 UV = IN.positionHCS.xy / _ScaledScreenParams.xy;
    
                    // 카메라 뎁스 텍스처에서 뎁스를 샘플링합니다..
                    #if UNITY_REVERSED_Z
                        real depth = SampleSceneDepth(UV);
                    #else
                        // Z를 조정하여 OpenGL용 NDC([-1, 1])에 맞춥니다.
                        real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
                    #endif
    
                    // 월드 공간 포지션을 재구성합니다.
                    float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);
    
                    // 다음 부분은 체커보드 효과를 만듭니다.
                    // 스케일은 사각형의 인버스 크기입니다.
                    uint scale = 10;
                    // 좌표를 확대/축소하고, 미러링하고, 스내핑합니다.
                    uint3 worldIntPos = uint3(abs(worldPos.xyz * scale));
                    // 표면을 사각형으로 나눕니다. 컬러 ID 값을 계산합니다.
                    bool white = ((worldIntPos.x) & 1) ^ (worldIntPos.y & 1) ^ (worldIntPos.z & 1);
                    // ID 값(검정 또는 흰색)을 기준으로 사각형의 컬러를 지정합니다.
                    half4 color = white ? half4(1,1,1,1) : half4(0,0,0,1);
    
                    // 원거리 클리핑 평면에 근접한 컬러를 검정색으로
                    // 설정합니다.
                    #if UNITY_REVERSED_Z
                        // D3D와 같이 REVERSED_Z가 있는 플랫폼의 경우입니다.
                        if(depth < 0.0001)
                            return half4(0,0,0,1);
                    #else
                        // OpenGL과 같이 REVERSED_Z가 없는 플랫폼의 경우입니다.
                        if(depth > 0.9999)
                            return half4(0,0,0,1);
                    #endif
    
                    return color;
                }
                ENDHLSL
            }
        }
    }
    
    맨 위로
    Copyright © 2023 Unity Technologies —
    • Your Privacy Choices (Cookie Settings)