Version: 2021.1
언어: 한국어
커스텀 렌더 파이프라인에서 렌더 파이프라인 에셋과 렌더 파이프라인 인스턴스 생성
카메라

커스텀 렌더 파이프라인에서 단순한 렌더 루프 생성

렌더 루프는 단일 프레임에서 발생하는 모든 렌더링 작업을 지칭하는 용어입니다. 이 페이지에서는 Unity의 스크립터블 렌더 파이프라인에 기반한 커스텀 렌더 파이프라인에서 간단한 렌더 루프를 만드는 방법에 대해 설명합니다.

이 페이지의 코드 예제는 스크립터블 렌더 파이프라인 사용의 기본 원칙을 보여줍니다. 이 정보를 사용하여 커스텀 스크립터블 렌더 파이프라인을 빌드하거나 Unity의 사전 빌드된 스크립터블 렌더 파이프라인이 작동하는 방식을 이해할 수 있습니다.

프로젝트 준비

렌더 루프용 코드를 작성하려면 먼저 프로젝트를 준비해야 합니다.

이를 위한 단계는 다음과 같습니다.

  1. SRP 호환 셰이더를 만듭니다.
  2. 렌더링할 게임 오브젝트를 하나 이상 생성합니다.
  3. 커스텀 SRP의 기본 구조를 생성합니다.
  4. 선택 사항: 간단한 커스텀 SRP를 확장하여 더욱 복잡한 기능을 추가하려면 SRP Core 패키지를 설치하십시오. SRP Core 패키지는 셰이더에 SRP 배처 호환성을 더하는 데 사용할 수 있는 SRP Core 셰이더 라이브러리와 일반 연산을 위한 유틸리티 함수를 포함합니다. 자세한 내용은 SRP Core 패키지 문서를 참조하십시오.

SRP 호환 셰이더 만들기

스크립터블 렌더 파이프라인에서는 LightMode 패스 태그를 사용하여 지오메트리를 어떻게 드로우할지 정합니다. 패스 태그에 관한 자세한 내용은 ShaderLab: 패스에 태그 할당하기를 참조하십시오.

이 작업을 통해 LightMode 패스 태그 값이 ExampleLightModeTag인 매우 간단한 언릿 셰이더 오브젝트를 만드는 방법을 알아볼 수 있습니다.

  1. 프로젝트에 새로운 셰이더 에셋을 만듭니다. 셰이더 에셋을 만드는 방법은 셰이더 에셋을 참조하십시오.
  2. 프로젝트 뷰에서 셰이더 에셋을 더블 클릭하여 텍스트 에디터에서 셰이더 소스 코드를 엽니다.
  3. 기존 코드를 다음으로 대체합니다.
// This defines a simple unlit Shader object that is compatible with a custom Scriptable Render Pipeline.
// It applies a hardcoded color, and demonstrates the use of the LightMode Pass tag.
// It is not compatible with SRP Batcher.

Shader "Examples/SimpleUnlitColor"
{
    SubShader
    {
        Pass
        {
            // The value of the LightMode Pass tag must match the ShaderTagId in ScriptableRenderContext.DrawRenderers
            Tags { "LightMode" = "ExampleLightModeTag"}

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

    float4x4 unity_MatrixVP;
            float4x4 unity_ObjectToWorld;

            struct Attributes
            {
                float4 positionOS   : POSITION;
            };

            struct Varyings
            {
                float4 positionCS : SV_POSITION;
            };

            Varyings vert (Attributes IN)
            {
                Varyings OUT;
                float4 worldPos = mul(unity_ObjectToWorld, IN.positionOS);
                OUT.positionCS = mul(unity_MatrixVP, worldPos);
                return OUT;
            }

            float4 frag (Varyings IN) : SV_TARGET
            {
                return float4(0.5,1,0.5,1);
            }
            ENDHLSL
        }
    }
}

렌더링할 게임 오브젝트 생성

렌더 루프가 작동하는지 테스트하려면 렌더할 대상을 만들어야 합니다. 이 작업을 통해 이전 작업에서 만든 SRP 호환 셰이더를 사용하는 게임 오브젝트를 씬에 배치하는 방법을 알아볼 수 있습니다.

  1. Unity 프로젝트에 새 머티리얼 에셋을 만듭니다. 방법은 머티리얼을 참조하십시오.
  2. 머티리얼 에셋에 셰이더 에셋을 할당합니다. 방법은 머티리얼을 참조하십시오.
  3. 씬에 큐브를 만듭니다. 방법은 기본 오브젝트를 참조하십시오.
  4. 큐브에 머티리얼을 할당합니다. 방법은 머티리얼을 참조하십시오.

커스텀 SRP의 기본 구조 생성

준비의 마지막 단계는 커스텀 SRP에 필요한 기본 소스 파일을 생성하고, 커스텀 SRP를 사용하여 렌더링을 시작하도록 Unity에 지시하는 것입니다.

  1. 렌더 파이프라인 인스턴스와 렌더 파이프라인 에셋 생성의 지침에 따라 RenderPipeline과 호환 가능 렌더 파이프라인 에셋에서 상속되는 클래스를 생성합니다.
  2. 활성 렌더 파이프라인 에셋 설정의 지침에 따라 활성 렌더 파이프라인 에셋을 생성합니다. Unity는 커스텀 SRP를 사용하여 즉시 렌더링을 시작합니다. 즉 커스텀 SRP에 코드를 추가하기 전까지 씬 뷰와 게임 뷰는 비어 있습니다.

렌더 루프 생성

렌더 루프에서 기본 작업은 다음과 같습니다.

  • 렌더 타겟 지우기 - 마지막 프레임 동안 그린 지오메트리를 제거합니다.
  • 컬링 - 카메라에 보이지 않는 지오메트리를 필터링합니다.
  • 그리기 - 그리려는 지오메트리와 그리는 방법을 GPU에 알립니다.

렌더 타겟 지우기

지우기는 마지막 프레임 동안 그린 대상을 지우는 작업을 의미합니다. 렌더 타겟은 대개 화면입니다. 하지만 텍스처로 렌더링하여 “화면 속 화면(PIP)” 효과를 구현할 수도 있습니다. 이 예제는 화면에 렌더링하는 방법(Unity의 기본 동작)을 보여줍니다.

스크립터블 렌더 파이프라인에서 렌더 타겟을 지우려면 다음 단계를 따르십시오.

  1. Clear 커맨드를 사용하여 CommandBuffer를 설정합니다.
  2. ScriptableRenderContext의 커맨드 대기열에 CommandBuffer를 추가합니다. 이렇게 하려면 ScriptableRenderContext.ExecuteCommandBuffer를 호출합니다.
  3. ScriptableRenderContext의 커맨드 대기열을 수행하도록 그래픽스 API에 지시합니다. 이렇게 하려면 ScriptableRenderContext.Submit를 호출하십시오.

다른 모든 스크립터블 렌더 파이프라인 작업과 마찬가지로, RenderPipeline.Render 메서드를 이 코드의 엔트리 포인트로 사용합니다. 다음 예제 코드는 이를 수행하는 방법을 보여줍니다.

/* 
This is a simplified example of a custom Scriptable Render Pipeline.
It demonstrates how a basic render loop works.
It shows the clearest workflow, rather than the most efficient runtime performance.
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // Create and schedule a command to clear the current render target
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // Instruct the graphics API to perform all scheduled commands
        context.Submit();
    }
}

컬링

컬링은 카메라에 보이지 않는 지오메트리를 필터링하는 프로세스입니다.

스크립터블 렌더 파이프라인에서 컬링을 수행하려면 다음 단계를 따르십시오.

  1. ScriptableCullingParameters 구조체를 카메라에 대한 데이터로 채웁니다. 이렇게 하려면 Camera.TryGetCullingParameters를 호출하십시오.
  2. 선택 사항: ScriptableCullingParameters 구조체의 값을 수동으로 업데이트합니다.
  3. ScriptableRenderContext.Cull을 호출하고, 그 결과를 CullingResults 구조체에 저장합니다.

다음 예제 코드는 위 예제 코드의 확장으로, 렌더 타겟을 지운 후 컬링 작업을 수행하는 방법을 보여줍니다.

/* 
This is a simplified example of a custom Scriptable Render Pipeline.
It demonstrates how a basic render loop works.
It shows the clearest workflow, rather than the most efficient runtime performance.
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // Create and schedule a command to clear the current render target
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // Iterate over all Cameras
        foreach (Camera camera in cameras)
        {
            // Get the culling parameters from the current Camera
            camera.TryGetCullingParameters(out var cullingParameters);

            // Use the culling parameters to perform a cull operation, and store the results
            var cullingResults = context.Cull(ref cullingParameters);
        }

        // Instruct the graphics API to perform all scheduled commands
        context.Submit();
    }
}

그리기

그리기는 특정 설정으로 특정 지오메트리 집합을 그리도록 그래픽스 API에 지시하는 프로세스입니다.

SRP에서 그리기를 수행하려면 다음 단계를 따르십시오.

  1. 위 설명대로 컬링 작업을 수행하고 그 결과를 CullingResults 구조체에 저장합니다.
  2. FilteringSettings 구조체를 생성하고 설정합니다. 이 구조체는 컬링 결과를 필터링하는 방법을 설명합니다.
  3. DrawingSettings 구조체를 생성하고 설정합니다. 이 구조체는 그리려는 지오메트리와 그리는 방법을 설명합니다.
  4. 선택 사항: 기본적으로 Unity는 셰이더 오브젝트에 기반하여 렌더 상태를 설정합니다. 드로우할 지오메트리 일부 또는 전부의 렌더 상태를 오버라이드하려면 RenderStateBlock 구조체를 사용하십시오.
  5. ScriptableRenderContext.DrawRenderers를 호출하고 파라미터로 생성한 구조체를 전달합니다. Unity는 해당 설정에 따라 필터링된 지오메트리 집합을 그립니다.

다음 예제 코드는 위 예제 코드의 확장으로, 렌더 타겟을 지우고 컬링 작업을 수행한 후 결과 지오메트리를 그리는 방법을 보여줍니다.

/* 
This is a simplified example of a custom Scriptable Render Pipeline.
It demonstrates how a basic render loop works.
It shows the clearest workflow, rather than the most efficient runtime performance.
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // Create and schedule a command to clear the current render target
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // Iterate over all Cameras
        foreach (Camera camera in cameras)
        {
            // Get the culling parameters from the current Camera
            camera.TryGetCullingParameters(out var cullingParameters);

            // Use the culling parameters to perform a cull operation, and store the results
            var cullingResults = context.Cull(ref cullingParameters);

            // Update the value of built-in shader variables, based on the current Camera
            context.SetupCameraProperties(camera);

            // Tell Unity which geometry to draw, based on its LightMode Pass tag value
            ShaderTagId shaderTagId = new ShaderTagId("ExampleLightModeTag");

            // Tell Unity how to sort the geometry, based on the current Camera
            var sortingSettings = new SortingSettings(camera);

            // Create a DrawingSettings struct that describes which geometry to draw and how to draw it
            DrawingSettings drawingSettings = new DrawingSettings(shaderTagId, sortingSettings);

            // Tell Unity how to filter the culling results, to further specify which geometry to draw
            // Use FilteringSettings.defaultValue to specify no filtering
            FilteringSettings filteringSettings = FilteringSettings.defaultValue;
        
            // Schedule a command to draw the geometry, based on the settings you have defined
            context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);

            // Schedule a command to draw the Skybox if required
            if (camera.clearFlags == CameraClearFlags.Skybox && RenderSettings.skybox != null)
            {
                context.DrawSkybox(camera);
            }

            // Instruct the graphics API to perform all scheduled commands
            context.Submit();
        }
    }
}
커스텀 렌더 파이프라인에서 렌더 파이프라인 에셋과 렌더 파이프라인 인스턴스 생성
카메라