커스텀 포스트 프로세스
고해상도 렌더 파이프라인(HDRP)을 사용하여 볼륨에 자동으로 통합되는 포스트 프로세싱 효과를 직접 작성할 수 있습니다. 커스텀 효과에는 두 파일이 필요합니다. 하나는 C# Custom Post Process(C# 파일)이며 다른 하나는 관련 FullScreen Shader(HLSL 파일)입니다. 다음과 같이 각각의 템플릿을 생성할 수 있습니다.
C# Custom Post Process: Assets 폴더에서 마우스 오른쪽을 클릭하고 Create > Rendering > C# Post Process Volume을 선택합니다.
FullScreen Shader: Assets 폴더에서 마우스 오른쪽을 클릭하고 Create > Shader > HDRP > Post Process를 선택합니다.
기본적으로 커스텀 효과는 볼륨에 추가만 한 경우에 실행되지 않습니다. 프로젝트의 지원되는 효과 리스트에도 효과를 추가해야 합니다(효과의 순서에 사용되는 동일한 리스트이며 효과 순서 섹션 참조).
예제
이 예제는 그레이스케일 효과를 만드는 방법을 보여줍니다. 시작하려면 다음 단계를 따르십시오.
C# Custom Post Process 파일을 만들고(Assets 폴더에서 오른쪽 클릭: Create > Rendering > C# Post Process Volume) 이름을 GrayScale이라고 지정합니다. Unity에서 직렬화가 작업하는 방식으로 인해 파일 이름과 클래스 이름이 반드시 동일해야 합니다. 그렇지 않으면 Unity가 올바르게 직렬화하지 않습니다.
그레이스케일 C# 스크립트 섹션에서 예제 코드를 C# Post Process Volume으로 복사합니다.
전체 화면 포스트 프로세스 셰이더를 만들고(Assets 폴더에서 마우스 오른쪽 클릭: Create > Shader > HDRP > Post Process) 이름을 GrayScale로 지정합니다.
그레이스케일 셰이더 섹션에서 예제 코드를 포스트 프로세스 셰이더로 복사합니다.
프로젝트가 시행하는 커스텀 포스트 프로세스 리스트에 그레이스케일 효과를 추가합니다. 이렇게 하려면 Edit > Project Settings > HDRP Default Settings로 이동하여 After Post Process 리스트 하단에서 + 를 클릭한 다음 GrayScale을 선택합니다.
이제 씬의 Volumes에 GrayScale 포스트 프로세스 오버라이드를 추가할 수 있습니다. 해당 효과 설정을 변경하려면 폴드아웃 화살표 바로 아래에 있는 작은
all
텍스트를 클릭하고 Intensity 슬라이더로 조정합니다.선택적으로 포스트 프로세싱 효과에 대한 커스텀 에디터를 만들 수 있습니다. 커스텀 에디터를 만드는 방법에 대한 자세한 내용은 커스텀 에디터를 참조하십시오.
그레이스케일 C# 스크립트
이 파일은 C# Custom Post Process 파일입니다. 커스텀 포스트 프로세스 효과는 동일한 클래스에 설정 데이터와 로직을 모두 저장합니다. 이 효과에 대한 설정을 만들려면 VolumeParameter
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using System;
[Serializable, VolumeComponentMenu("Post-processing/Custom/GrayScale")]
public sealed class GrayScale : CustomPostProcessVolumeComponent, IPostProcessComponent
{
[Tooltip("Controls the intensity of the effect.")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
Material m_Material;
public bool IsActive() => m_Material != null && intensity.value > 0f;
public override CustomPostProcessInjectionPoint injectionPoint => CustomPostProcessInjectionPoint.AfterPostProcess;
public override void Setup()
{
if (Shader.Find("Hidden/Shader/GrayScale") != null)
m_Material = new Material(Shader.Find("Hidden/Shader/GrayScale"));
}
public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
{
if (m_Material == null)
return;
m_Material.SetFloat("_Intensity", intensity.value);
m_Material.SetTexture("_InputTexture", source);
HDUtils.DrawFullScreen(cmd, m_Material, destination);
}
public override void Cleanup() => CoreUtils.Destroy(m_Material);
}
먼저 예제 코드는 익숙하지 않은 타입인 ClampedFloatParameter를 사용합니다. 이 타입은 범위에 고정할 수 있는 플로트입니다. 생성자에서는 다음과 같습니다.
첫 번째 파라미터는 프로퍼티의 기본 값입니다.
두 번째 파라미터는 프로퍼티를 고정할 최소값을 나타냅니다.
세 번째 파라미터는 프로퍼티를 고정할 최대값을 나타냅니다.
다음에는 IsActive() 함수가 있습니다. HDRP는 Render 함수가 이 효과를 처리할 수 있는지 확인하기 전에 이 함수를 호출합니다. 이 함수가 false
를 반환하면 HDRP는 이 효과를 처리하지 않습니다. 효과가 중단되거나 아무것도 수행하지 않는 모든 프로퍼티 설정을 확인하는 편이 좋습니다. 이 예제에서 **IsActive()**는 GrayScale.shader를 찾을 수 있고 강도가 0보다 큰지 확인합니다.
injectionPoint 오버라이드를 사용하여 파이프라인에서 HDRP가 효과를 실행하는 위치를 지정할 수 있습니다. 현재 다음과 같이 세 가지 주입 지점이 있습니다.
AfterOpaqueAndSky
BeforeTAA
BeforePostProcess
AfterPostProcess
HDRP가 커스텀 포스트 프로세스 패스를 주입하는 위치에 대한 자세한 내용은 다음의 다이어그램을 참조하십시오.
현재 Setup, Render, Cleanup 함수가 있습니다. 이러한 함수는 여기에서 해당 효과에 필요한 리소스를 각각 할당하고 사용하고 릴리스합니다. 예제가 사용하는 유일한 리소스는 단일 머티리얼입니다. 예제는 Setup과 Cleanup에 머티리얼을 만들고 CoreUtils.Destroy()를 사용하여 머티리얼을 릴리스합니다. Render 함수에서 HDRP가 실행하는 작업을 대기열에 넣는 데 사용할 수 있는 CommandBuffer에 액세스할 수 있습니다. 여기에서 HDUtils.DrawFullScreen을 사용하여 전체 화면 사각형을 렌더링할 수 있습니다. 전달하는 CommandBuffer와 머티리얼을 사용한 다음 대상 RTHandle에 해당 결과를 blit합니다.
그레이스케일 셰이더
HDRP를 사용하여 버텍스와 프래그먼트 셰이더에 대해 완전히 제어할 수 있어서 필요에 맞게 둘 다 편집할 수 있습니다. 셰이더가 기본적으로 포함하는 Common.hlsl과 Color.hlsl에는 유틸리티 함수가 많이 있습니다. 즉 효과에서 이러한 유틸리티 함수에 액세스할 수 있다는 의미입니다. 예를 들어 그레이스케일 셰이더는 Luminance() 함수를 사용하여 리니어 RGB 값을 이에 해당하는 휘도로 전환합니다.
Shader "Hidden/Shader/GrayScale"
{
HLSLINCLUDE
#pragma target 4.5
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"
struct Attributes
{
uint vertexID : SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vert(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
return output;
}
// List of properties to control your post process effect
float _Intensity;
TEXTURE2D_X(_InputTexture);
float4 CustomPostProcess(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
uint2 positionSS = input.texcoord * _ScreenSize.xy;
float3 outColor = LOAD_TEXTURE2D_X(_InputTexture, positionSS).xyz;
// We do the blending manually instead of relying on the hardware blend
// It's necessary because the color buffer contains garbage from the previous post process effect.
return float4(lerp(outColor, Luminance(outColor).xxx, _Intensity), 1);
}
ENDHLSL
SubShader
{
Pass
{
Name "GrayScale"
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
#pragma fragment CustomPostProcess
#pragma vertex Vert
ENDHLSL
}
}
Fallback Off
}
씬이 셰이더를 레퍼런스하지 않는 경우 Unity는 셰이더를 빌드하지 않고 에디터 외부에서 애플리케이션을 실행할 때 해당 효과는 작동하지 않습니다. 이를 해결하려면 셰이더를 Resources 폴더에 추가하거나 Edit > Project Settings > Graphics로 이동하여 셰이더를 Always Included Shaders 리스트에 추가합니다.
:경고: HDRP가 포스트 프로세스 효과를 실행하면 렌더 타겟 풀링 시스템을 사용합니다. 즉 현재 컬러 버퍼에 무엇이 포함되어 있는지 알지 못하므로 이 컬러 버퍼를 표시할 수 있는 명령을 사용해선 안 됩니다. 셰이더에서 투명도나 블렌딩 모드, clip() 명령을 사용해선 안 됩니다. 사용할 경우 효과가 중단됩니다.
셰이더 입력
기본적으로 셰이더 템플릿은 다음의 입력을 제공합니다.
입력 | 설명 |
---|---|
positionCS | 픽셀의 클립 공간 포지션입니다. 이 값은 0과 현재 화면 크기 사이에 있습니다. |
texcoord | 전체 화면 UV 좌표입니다. 이 값은 0과 1 사이에 있습니다. |
_InputTexture | 소스 텍스처입니다. GrayScale C# 스크립트는 이 텍스처를 셰이더에 전달합니다. |
_Intensity | 효과의 강도입니다. 그레이스케일 C# 스크립트는 이것을 셰이더에 전달합니다. |
효과 순서
HDRP를 사용하여 각 주입 지점에 커스텀 포스트 프로세싱 효과 순서를 커스터마이즈할 수 있습니다. 효과에 순서를 지정하려면 다음 단계를 따르십시오.
Edit > Project Settings로 이동하여 HDRP Default Settings 탭을 선택합니다.
Custom Post Process Orders 섹션이 나올 때까지 스크롤을 내립니다. 이 섹션에는 각 주입 지점에 하나씩 세 가지 리스트가 포함되어 있습니다.
HDRP가 렌더링할 수 있도록 이러한 리스트에 커스텀 효과를 추가합니다.
HDRP는 리스트 상단에서 하단으로 효과를 처리하며 각 리스트에 대한 실행 순서는 다음과 같습니다.
Before Transparent.
Before TAA
Before Post Process.
After Post Process.
커스텀 에디터
기본적으로 Unity는 클래스에 대한 에디터를 자동으로 생성하지만 Unity가 특정 프로퍼티를 표시하는 방법을 더 많이 제어하려면 커스텀 에디터를 만들 수 있습니다. 커스텀 에디터 스크립트를 생성하는 경우 반드시 이름이 Editor인 폴더에 넣어야 합니다.
다음은 그레이스케일 효과에 대한 커스텀 에디터의 예제입니다.
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEditor;
[VolumeComponentEditor(typeof(GrayScale))]
sealed class GrayScaleEditor : VolumeComponentEditor
{
SerializedDataParameter m_Intensity;
public override bool hasAdvancedMode => false;
public override void OnEnable()
{
base.OnEnable();
var o = new PropertyFetcher<GrayScale>(serializedObject);
m_Intensity = Unpack(o.Find(x => x.intensity));
}
public override void OnInspectorGUI()
{
PropertyField(m_Intensity);
}
}
이 커스텀 에디터는 Unity가 만든 에디터와 동일한 결과를 생성할 만큼 무척 유용하지는 않습니다. Custom Volume 컴포넌트 에디터는 또한 더 많은 옵션 버튼도 지원합니다. 추가하려면 hasAdvancedMode 오버라이드를 true로 설정해야 합니다. 그런 다음 OnInspectorGUI 내부에서 isInAdvancedMode 부울을 사용하여 더 많은 프로퍼티를 표시할 수 있습니다.
문제 해결
효과가 올바르게 표시되지 않는 경우 다음 단계를 따르십시오.
프로젝트 설정에서 이 효과가 포스트 프로세스 순서 리스트 중 하나 아래에 나열되어 있는지 확인합니다(효과 순서 참조).
효과의 셰이더가 컴파일하고 포스트 프로세스 볼륨의 머티리얼에 대한 레퍼런스가 null아 아닌지 확인합니다.
포스트 프로세스가 포함된 볼륨에서 우선순위가 충분히 높고 카메라가 경계 안에 있는지 확인합니다.
셰이더에 clip() 명령이 포함되어 있지 않은지, 블렌딩 모드가 Off로 설정되어 있고 출력 알파가 항상 1인지 확인합니다.
알려진 문제 및 제한
- 커스텀 포스트 프로세스 클래스 이름과 파일 이름을 변경하면 HDRP 프로젝트 설정 리스트에서 제거되어 효과가 더 이상 렌더링되지 않습니다.