렌더 루프는 단일 프레임에서 발생하는 모든 렌더링 작업을 지칭하는 용어입니다. 이 페이지에서는 Unity의 스크립터블 렌더 파이프라인에 기반한 커스텀 렌더 파이프라인에서 간단한 렌더 루프를 만드는 방법에 대해 설명합니다.
이 페이지의 코드 예제는 스크립터블 렌더 파이프라인 사용의 기본 원칙을 보여줍니다. 이 정보를 사용하여 커스텀 스크립터블 렌더 파이프라인을 빌드하거나 Unity의 사전 빌드된 스크립터블 렌더 파이프라인이 작동하는 방식을 이해할 수 있습니다.
렌더 루프용 코드를 작성하려면 먼저 프로젝트를 준비해야 합니다.
이를 위한 단계는 다음과 같습니다.
스크립터블 렌더 파이프라인에서는 LightMode
패스 태그를 사용하여 지오메트리를 어떻게 드로우할지 정합니다. 패스 태그에 관한 자세한 내용은 ShaderLab: 패스에 태그 할당하기를 참조하십시오.
이 작업을 통해 LightMode 패스 태그 값이 ExampleLightModeTag
인 매우 간단한 언릿 셰이더 오브젝트를 만드는 방법을 알아볼 수 있습니다.
// 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 호환 셰이더를 사용하는 게임 오브젝트를 씬에 배치하는 방법을 알아볼 수 있습니다.
준비의 마지막 단계는 커스텀 SRP에 필요한 기본 소스 파일을 생성하고, 커스텀 SRP를 사용하여 렌더링을 시작하도록 Unity에 지시하는 것입니다.
RenderPipeline
과 호환 가능 렌더 파이프라인 에셋에서 상속되는 클래스를 생성합니다.렌더 루프에서 기본 작업은 다음과 같습니다.
지우기는 마지막 프레임 동안 그린 대상을 지우는 작업을 의미합니다. 렌더 타겟은 대개 화면입니다. 하지만 텍스처로 렌더링하여 “화면 속 화면(PIP)” 효과를 구현할 수도 있습니다. 이 예제는 화면에 렌더링하는 방법(Unity의 기본 동작)을 보여줍니다.
스크립터블 렌더 파이프라인에서 렌더 타겟을 지우려면 다음 단계를 따르십시오.
Clear
커맨드를 사용하여 CommandBuffer
를 설정합니다.ScriptableRenderContext
의 커맨드 대기열에 CommandBuffer
를 추가합니다. 이렇게 하려면 ScriptableRenderContext.ExecuteCommandBuffer를 호출합니다.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();
}
}
컬링은 카메라에 보이지 않는 지오메트리를 필터링하는 프로세스입니다.
스크립터블 렌더 파이프라인에서 컬링을 수행하려면 다음 단계를 따르십시오.
ScriptableCullingParameters
구조체의 값을 수동으로 업데이트합니다.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에서 그리기를 수행하려면 다음 단계를 따르십시오.
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);
// 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();
}
}
}