이전 CustomRenderFeature 간단 예제 코드 포스팅에 이어서, RenderFeature에서 2Pass처리하는 예제 프로젝트입니다.
https://github.com/CatDarkGame/CustomRenderFeatureExample/releases/tag/2PassRenderFeature
핵심 코드
1. 간단한 2 Pass 쉐이더
Shader "Hidden/CustomRenderFeature/TwoPass"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
HLSLINCLUDE
#pragma exclude_renderers gles
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"
sampler2D _MainTex;
sampler2D _Buffer1Tex;
float4 TwoPassFragment_1 (Varyings i) : SV_TARGET
{
float4 col = tex2D(_MainTex, i.uv) * float4(0, 0, 1, 1);
return col;
}
float4 TwoPassFragment_2 (Varyings i) : SV_TARGET
{
float4 col = tex2D(_MainTex, i.uv);
float4 buffer1 = tex2D(_Buffer1Tex, i.uv);
return col + buffer1;
}
ENDHLSL
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
ZTest Always ZWrite Off Cull Off
Pass
{
Name "TwoPass_1"
HLSLPROGRAM
#pragma vertex FullscreenVert
#pragma fragment TwoPassFragment_1
ENDHLSL
}
Pass
{
Name "TwoPass_2"
HLSLPROGRAM
#pragma vertex FullscreenVert
#pragma fragment TwoPassFragment_2
ENDHLSL
}
}
한개의 쉐이더 파일에 2개의 Pass가 작성되어 있습니다.
1번 패스에서는 화면에 푸른색을 입히고, 2번 패스에서는 원본 화면과 푸른화면을 섞는 코드가 작성되어 있습니다.
이후 RenderPass에서 2개의 Pass를 골라서 렌더링하겠습니다.
2. RenderPass 작성 - 2개의 임시 렌더 텍스처
public class TwoPassRenderPass : ScriptableRenderPass
{
private static readonly string PASS_TAG = "TwoPassRenderPass";
private static readonly int PROPERTY_BUFFER1_TEX = Shader.PropertyToID("_Buffer1Tex"); // 버퍼1 sampler2D 변수명
private static readonly int PROPERTY_TEMPBUFFER_1 = Shader.PropertyToID("_TempBuffer_1"); // 임시렌더텍스처 변수명
private static readonly int PROPERTY_TEMPBUFFER_2 = Shader.PropertyToID("_TempBuffer_2");
private Material _material;
private RenderTargetIdentifier _destination; // 화면렌더텍스처(카메라)
private RenderTargetIdentifier _tempBuffer_1 = new RenderTargetIdentifier(PROPERTY_TEMPBUFFER_1); // 임시렌더텍스처
private RenderTargetIdentifier _tempBuffer_2 = new RenderTargetIdentifier(PROPERTY_TEMPBUFFER_2); // 임시렌더텍스처
전체적인 맥락은 이전 프로젝트와 비슷하지만, 1개의 Pass에서 2번 그리기 위해서는 2개의 임시버퍼가 필요합니다.
3. 2번씩 렌더링
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(PASS_TAG);
// 임시렌더텍스처 생성
CameraData cameraData = renderingData.cameraData;
RenderTextureDescriptor descriptor = new RenderTextureDescriptor(cameraData.camera.scaledPixelWidth, cameraData.camera.scaledPixelHeight);
cmd.GetTemporaryRT(PROPERTY_TEMPBUFFER_1, descriptor, FilterMode.Bilinear);
cmd.GetTemporaryRT(PROPERTY_TEMPBUFFER_2, descriptor, FilterMode.Bilinear);
// 현재 화면 데이터를 Material 효과를 적용하며 임시렌더텍스처에 복사 (Pass 0)
cmd.Blit(_destination, _tempBuffer_1, _material, 0);
// 현재 화면 데이터를 Material 효과를 적용하며 임시렌더텍스처에 복사 (Pass 1)
cmd.Blit(_destination, _tempBuffer_2, _material, 1);
// 임시렌더텍스처를 화면렌더텍스처에 복사
cmd.Blit(_tempBuffer_2, _destination);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
1 Pass 방식과 비슷하지만 2개의 임시 렌더텍스처를 생성하고, 2번 복사하는 작업을 합니다.
특이 사항은 Blit함수 마지막에 Material내부의 쉐이더의 Pass를 골라서 호출 가능한데,
이렇게 2개의 Pass를 렌더링했습니다.
4. 1번 pass의 화면 정보를 2번 Pass에서 사용하기
private static readonly int PROPERTY_BUFFER1_TEX = Shader.PropertyToID("_Buffer1Tex"); // 버퍼1 sampler2D 변수명
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
...
// 버퍼1을 별도 sampler2D Property로 접근 가능하세 세팅
cmd.SetGlobalTexture(PROPERTY_BUFFER1_TEX, _tempBuffer_1);
...
2번 Pass에서는 1번 Pass에서 파랗게 수정된 텍스처 정보를 받야아합니다.
먼저 SetGlobalTexture를 통해 1번 임시 버퍼 정보를 "_Buffer1Tex"글로벌 변수로 지정하고
2번 패스 쉐이더에서 에서 해당 변수를 참조하여 사용 할 수 있습니다.
결과물
추가 응용) 가우시안 블러 구현
2개의 버퍼를 이용하는 기술을 응용해 가우시안블러를 구현했습니다.
가우시안블러는 블러 연산 중에 가벼우면서 부드러운 효과를 낼 수 있어, Bloom 등 다양한 효과에 사용됩니다.
아래 참고 자료를 보고 구현했으며, 블러에 대해서는 추후 자세하게 다루겠습니다.
https://catlikecoding.com/unity/tutorials/custom-srp/post-processing/
// 2 Pass 가우스안블러 렌더링
cmd.Blit(_destination, _tempBuffer_1, _material, 0); // Horizontal
cmd.Blit(_tempBuffer_1, _tempBuffer_2, _material, 1); // Vertical
for (int i = 1; i < blurStep; i++)
{
cmd.Blit(_tempBuffer_2, _tempBuffer_1, _material, 0);
cmd.Blit(_tempBuffer_1, _tempBuffer_2, _material, 1);
}
// 임시렌더텍스처를 화면렌더텍스처에 복사
cmd.Blit(_tempBuffer_2, _destination);
가우시안 블러도 2개의 버퍼를 사용한다는점에서 이전에 소개한 코드와 비슷하지만
블러 연산을 일정 이상 반복해야 하기 때문에 더블 버퍼링 코드가 추가되었습니다.
'Unity > TA' 카테고리의 다른 글
[URP] 반투명 알파소팅 이슈 해결 쉐이더 (2pass) (0) | 2022.06.06 |
---|---|
URP CustomRenderFeature - 블러 구현 & 분석 (1) | 2022.04.20 |
URP CustomRenderFeature - 간단 예제 코드 (0) | 2022.04.12 |
URP 커스텀 포스트프로세싱 - 2 개선판 (0) | 2022.04.04 |
URP 커스텀 포스트프로세싱 - 1 (0) | 2022.03.29 |
WRITTEN BY
- CatDarkGame
Technical Artist dhwlgn12@gmail.com