렌더 루프는 단일 프레임에서 발생하는 모든 렌더링 작업을 지칭하는 용어입니다. 이 페이지에서는 Unity의 스크립터블 렌더 파이프라인에 기반한 커스텀 렌더 파이프라인에서 간단한 렌더 루프를 만드는 방법에 대해 설명합니다.
이 페이지의 코드 예제는 스크립터블 렌더 파이프라인 사용의 기본 원칙을 보여줍니다. 이 정보를 사용하여 커스텀 스크립터블 렌더 파이프라인을 빌드하거나 Unity의 사전 빌드된 스크립터블 렌더 파이프라인이 작동하는 방식을 이해할 수 있습니다.
렌더 루프용 코드를 작성하려면 먼저 프로젝트를 준비해야 합니다.
이를 위한 단계는 다음과 같습니다.
스크립터블 렌더 파이프라인에서는 LightMode Pass 태그를 Unity 셰이더에 사용하여 지오메트리를 그리는 방법을 결정합니다. Unity 셰이더에 Pass 태그를 할당하는 방법에 대한 자세한 내용은 ShaderLab: Pass에 태그 할당을 참조하십시오.
이 작업은 LightMode Pass 태그 값으로 ExampleLightModeTag
를 사용하는 매우 간단한 언릿 Unity 셰이더를 만드는 방법을 보여줍니다.
// This is a simple unlit Unity shader 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 호환 Unity 셰이더를 사용하는 게임 오브젝트를 씬에 배치하는 방법을 보여줍니다.
준비의 마지막 단계는 커스텀 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();
}
}
}