이 페이지에서는 다음을 수행하는 스크립터블 렌더러 기능을 만드는 방법을 설명합니다.
여기에는 프레임 순서에 따라 오버레이에 톤 매핑을 적용하는 셰이더가 포함됩니다.
자세한 내용은 스크립터블 렌더러 기능 소개와 스크립터블 렌더 패스 소개를 참고하십시오.
이 예시는 다음 섹션으로 구성됩니다.
이 예시에서는 다음을 전제합니다.
예시가 올바르게 작동하려면 먼저 다음 지침에 따라 샘플 씬을 설정해야 합니다.
큐브 게임 오브젝트를 생성하고 그 위치를 씬의 원점(X: 0, Y: 0, Z: 0)으로 설정합니다.
큐브가 잘 보이도록 Main Camera를 정렬합니다.
새 카메라를 만들고 Overlay Camera라고 부릅니다.
오버레이 카메라를 Main Camera 오른쪽에 배치하고 큐브가 잘 보이도록 정렬합니다.
인스펙터 창에서 오버레이 카메라 Background Type 프로퍼티를 Solid Color로 설정합니다.
0, 0, 0, 0의 RGBA 값을 사용해 오버레이 카메라 배경의 컬러를 완전한 검정색으로 설정합니다.
렌더 텍스처를 생성하고 OverlayRenderTexture라고 명명합니다. 렌더 텍스처를 만들려면 Assets > Create > Rendering > Render Texture로 이동합니다.
참고: HDR의 정밀도를 높이려면 렌더 텍스처 포맷을 부호가 있는 플로트 포맷으로 지정하십시오. 이를 위해서는 렌더 텍스처를 선택한 다음 인스펙터 창에서 Color Format을
_SFLOAT접미사가 붙은 포맷으로 변경하면 됩니다.
오버레이 카메라의 Output Texture 프로퍼티에 오버레이 렌더 텍스처를 할당합니다. 이를 위해서는 인스펙터에서 Overlay Camera를 열고 Output > Output Texture로 이동하여 에셋 목록에서 OverlayRenderTexture를 선택하면 됩니다.
오버레이 카메라에 대해 새로운 유니버설 렌더러 에셋을 생성하고 OverlayRenderer라고 명명합니다. 이렇게 하려면 Assets > Create > Rendering > URP Universal Renderer로 이동합니다.
활성 URP 에셋을 선택한 다음 인스펙터 창에서 Rendering > Renderer List > +로 이동합니다. OverlayRenderer를 선택합니다. 그러면 오버레이 렌더러가 렌더러 목록에 추가됩니다.
오버레이 카메라를 선택한 다음 인스펙터 창에서 Rendering > Renderer로 이동합니다. OverlayRenderer를 선택합니다. 그러면 오버레이 카메라가 오버레이 렌더러를 사용하도록 설정됩니다.
이제 씬이 스크립터블 렌더러 기능을 사용하여 커스텀 오버레이를 생성할 수 있습니다.
HDR 출력과 호환되는 커스텀 오버레이를 생성하려면 반드시 스크립터블 렌더 패스를 사용하여 오버레이를 생성해야 합니다. HDR 출력은 포스트 프로세싱 시 메인 카메라의 출력에 톤 매핑을 적용합니다. 그 결과 메인 카메라의 출력과 오버레이 카메라의 톤 매핑이 달라집니다. 이후 해당 렌더 패스는 포스트 프로세싱 후에 진행되어 톤 매핑을 오버레이 카메라의 출력에 적용합니다.
이 예시에 대한 렌더 패스를 생성하려면 다음 과정을 따르십시오.
C# 스크립트를 만들어 CustomOverlayRenderPass라고 명명합니다.
스크립트에서 Unity가 CustomOverlayRenderPass 클래스에 삽입한 코드를 제거합니다.
다음 using 지시문을 추가합니다.
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
ScriptableRenderPass 클래스를 상속하고 [SupportedOnRenderer(typeof(UniversalRendererData) --> 속성을 갖는 새 CustomOverlayRenderPass 클래스를 생성합니다.
[SupportedOnRenderer(typeof(UniversalRendererData))] -->
public class CustomOverlayRenderPass : ScriptableRenderPass
{
}
아래와 같이 렌더 패스에 프로퍼티 Material passMaterial 및 RTHandle passOverlayTexture를 추가합니다.
[SupportedOnRenderer(typeof(UniversalRendererData))] -->
public class CustomOverlayRenderPass : ScriptableRenderPass
{
Material passMaterial;
RTHandle overlayTextureHandle;
}
머티리얼을 파라미터로 사용하여 passMaterial에 할당하는 생성자 메서드를 생성합니다. 이 메서드는 또한 렌더 패스에 대한 프로파일링 샘플러를 생성하고 AfterRenderingPostProcessing 이벤트에서 실행되도록 설정합니다.
public CustomOverlayRenderPass(Material material)
{
passMaterial = material;
profilingSampler = new ProfilingSampler(nameof(CustomOverlayRenderPass));
renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
}
렌더 패스에 대한 Setup 메서드를 추가합니다. 아래와 같이 이 메서드와 파라미터를 사용하여 오버레이 텍스처에서 RTHandle를 생성합니다. RTHandle를 사용하면 RenderPass API가 오버레이 렌더 텍스처와 상호작용할 수 있게 됩니다.
public void Setup(Texture overlayTex)
{
if (overlayTextureHandle != overlayTex)
{
overlayTextureHandle?.Release();
overlayTextureHandle = RTHandles.Alloc(overlayTex);
}
}
Dispose 메서드를 구현하여 렌더 패스가 파괴될 때 오버레이 텍스처를 해제합니다.
public void Dispose()
{
overlayTextureHandle?.Release();
}
아래에 표시된 프로퍼티를 포함하는 두 개의 구조체(하나의 이름은 CopyData, 다른 하나의 이름은 PassData)를 만듭니다. 이 구조체들은 URP가 렌더 패스를 구현하는 데 필요한 주요 프로퍼티를 포함합니다.
struct CopyData
{
public TextureHandle source;
}
struct PassData
{
public TextureHandle source;
public TextureHandle overlayTexture;
public TextureHandle internalLut;
public Vector4 lutParams;
public Material material;
}
아래와 같이 RecordRenderGraph 메서드를 추가합니다.
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
}
다음 단계의 코드를 CustomOverlayRenderPass 클래스의 RecordRenderGraph 메서드에 추가합니다.
프레임 데이터에서 포스트 프로세싱, 리소스, 카메라 데이터를 가져옵니다.
UniversalPostProcessingData postProcessingData = frameData.Get<UniversalPostProcessingData>();
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
리소스 데이터에서 활성 컬러 텍스처를 가져옵니다.
TextureHandle activeCameraColor = resourceData.activeColorTexture;
활성 카메라 컬러 타겟을 저장할 텍스처를 생성합니다.
RenderTextureDescriptor colorCopyDescriptor = cameraData.cameraTargetDescriptor;
colorCopyDescriptor.depthBufferBits = (int) DepthBits.None;
TextureHandle copiedColor = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorCopyDescriptor, "_CustomCameraColorCopy", false);
RasterRenderPass를 생성해 활성 카메라 컬러 타겟을 텍스처에 복사합니다. 사본은 블렌딩을 처리하는 데 사용됩니다.
using (var builder = renderGraph.AddRasterRenderPass<CopyData>("Custom Overlay Render Pass - Copy Camera", out var passData))
{
passData.source = activeCameraColor;
builder.UseTexture(passData.source, AccessFlags.Read);
builder.SetRenderAttachment(copiedColor, 0, AccessFlags.WriteAll);
builder.SetRenderFunc((CopyData data, RasterGraphContext context) =>
{
Blitter.BlitTexture(context.cmd, data.source, new Vector4(1, 1, 0, 0), 0.0f, false);
});
}
다른 RasterRenderPass를 생성하여 커스텀 머티리얼을 사용해 오버레이 텍스처를 활성 카메라 컬러 타겟에 복사합니다. 이는 본 가이드의 이 섹션에서 추가한 나머지 코드의 컨테이너입니다.
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Custom Overlay Render Pass - Blit Overlay", out var passData))
{
}
아래와 같이 렌더 패스가 오버레이 텍스처를 blit하는 데 필요한 프로퍼티들을설정합니다.
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Custom Overlay Render Pass - Blit Overlay", out var passData))
{
passData.material = passMaterial;
builder.SetRenderAttachment(activeCameraColor, 0, AccessFlags.Write);
passData.source = copiedColor;
builder.UseTexture(passData.source, AccessFlags.Read);
}
텍스처를 렌더 그래프 시스템으로 임포트한 다음 텍스처를 입력으로 설정합니다.
passData.overlayTexture = renderGraph.ImportTexture(passOverlayTexture);
builder.UseTexture(passData.overlayTexture, AccessFlags.Read);
포스트 프로세싱 및 HDR 컬러 분류를 확인합니다. HDR 출력에 대한 설정이 올바른 경우, HDR 입력으로 사용하는 내부 컬러 룩업 테이블 텍스처를 설정하고 해당 파라미터를 셰이더에 전달합니다.
if (postProcessingData.gradingMode == ColorGradingMode.HighDynamicRange && cameraData.postProcessEnabled)
{
passData.internalLut = resourceData.internalColorLut;
builder.UseTexture(passData.internalLut, AccessFlags.Read);
int lutHeight = postProcessingData.lutSize;
int lutWidth = lutHeight * lutHeight;
float postExposure = 1.0f;
ColorAdjustments colorAdjustments = VolumeManager.instance.stack.GetComponent<ColorAdjustments>();
if (colorAdjustments != null)
{
postExposure = Mathf.Pow(2.0f, colorAdjustments.postExposure.value);
}
passData.lutParams = new Vector4(1f / lutWidth, 1f / lutHeight, lutHeight - 1f, postExposure);
}
참고: 포스트 프로세싱이 비활성화된 경우, HDR 컬러 변환이 이 렌더 패스 후에 적용되며 카메라 출력의 예상 색 공간은 기본 Rec709입니다. 본 예시의 코드는 여기서
if문을 사용하여 HDR이 적용되기 전에 이 렌더 패스가 오버레이 카메라의 출력을 변경하지 못하게 합니다.
셰이더에서 키워드를 설정하여 톤 매핑을 활성화하고, 오버레이 텍스처를 활성 카메라 컬러 타겟에 blit하는 커맨드를 추가합니다.
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
{
data.material.SetTexture("_OverlayTexture", data.overlayTexture);
bool tonemappingActive = data.internalLut.IsValid();
CoreUtils.SetKeyword(data.material, "TONEMAPPING", tonemappingActive);
if (tonemappingActive)
{
data.material.SetTexture("_InternalLut", data.internalLut);
data.material.SetVector("_InternalLut_Params", data.lutParams);
}
Blitter.BlitTexture(context.cmd, data.source, new Vector4(1, 1, 0, 0), data.material, 0);
});
그러면 CustomOverlayRenderPass 스크립트가 완성되어 스크립터블 렌더러 기능이 해당 스크립트를 렌더러에 추가할 수 있게 됩니다.
이 섹션의 전체 코드는 커스텀 오버레이 렌더 패스 코드를 참조하십시오.
렌더러에 CustomOverlayRenderPass를 추가하려면 다음 과정을 따라 스크립터블 렌더러 기능을 만들어야 합니다.
C# 스크립트를 만들어 CustomOverlayRendererFeature라고 명명합니다.
스크립트에서 Unity가 CustomOverlayRendererFeature 클래스에 삽입한 코드를 제거합니다.
다음 using 지시문을 추가합니다.
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
ScriptableRendererFeature 클래스에서 상속하는 새 CustomOverlayRendererFeature 클래스를 설정합니다.
public class CustomOverlayRendererFeature : ScriptableRendererFeature
{
}
다음 프로퍼티를 추가하여 렌더 패스에 필요한 에셋과 데이터를 포함합니다.
public class CustomOverlayRendererFeature : ScriptableRendererFeature
{
public Shader hdrShader;
public RenderTexture passOverlayTexture;
Material passMaterial;
CustomOverlayRenderPass overlayRenderPass = null;
}
AddRenderPasses 메서드를 생성하고 이를 사용해 게임 뷰와 카메라 스택의 마지막 카메라에만 오버레이를 적용합니다.
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (renderingData.cameraData.cameraType != CameraType.Game || !renderingData.cameraData.resolveFinalTarget)
return;
}
if 문 뒤에서 오브레이 텍스처를 오버레이 렌더 패스에 전달하고 렌더 패스를 대기열에 추가합니다.
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (renderingData.cameraData.cameraType != CameraType.Game || !renderingData.cameraData.resolveFinalTarget)
return;
overlayRenderPass.Setup(passOverlayTexture);
renderer.EnqueuePass(overlayRenderPass);
}
Create 메서드를 추가하고 hdrShader를 사용하는 새 머티리얼로 CustomOverlayRenderPass의 인스턴스를 만듭니다.
public override void Create()
{
passMaterial = CoreUtils.CreateEngineMaterial(hdrShader);
overlayRenderPass = new CustomOverlayRenderPass(passMaterial);
}
Dispose 메서드를 구현하여 렌더러 기능이 렌더 패스를 적용한 이후에 생성하는 리소스를 해제합니다.
protected override void Dispose(bool disposing)
{
CoreUtils.Destroy(passMaterial);
overlayRenderPass.Dispose();
}
이 섹션의 전체 코드는 커스텀 오버레이 스크립터블 렌더러 기능 코드를 참조하십시오.
CustomOverlayRendererFeature가 생성하는 머티리얼에는 오버레이와 HDR 출력 변경 사항을 처리하기 위한 커스텀 셰이더가 필요합니다. 이를 처리할 수 있는 셰이더를 만드는 방법은 아래와 같습니다.
새로운 셰이더를 만들고 CustomOverlayBlit로 명명합니다.
Unity가 자동으로 생성하는 셰이더 코드를 삭제하고 셰이더의 아웃라인을 아래와 같이 설정합니다.
Shader "Custom/CustomOverlayBlit"
{
SubShader
{
Tags{ "RenderPipeline" = "UniversalPipeline" }
Pass
{
ZWrite Off ZTest Always Blend Off Cull Off
HLSLPROGRAM
#pragma target 2.0
#pragma editor_sync_compilation
#pragma vertex Vert
#pragma fragment Frag
#pragma multi_compile_local_fragment _ TONEMAPPING
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
TEXTURE2D(_InternalLut);
TEXTURE2D_X(_OverlayTexture);
float4 _InternalLut_Params;
#define LutParams _InternalLut_Params.xyz
#define PostExposure _InternalLut_Params.w
ENDHLSL
}
}
}
이름이 ApplyTonemapping이고 반환 유형이 half3인 메서드를 생성합니다. 이 메서드에는 파라미터 half3 input, TEXTURE2D_PARAM(lutTex, lutSampler), float3 lutParams, float exposure가 있어야 합니다.
ApplyTonemapping 메서드에서 input에 exposure 값을 곱한 다음 수정된 input을 saturate합니다.
half3 ApplyTonemapping(half3 input, TEXTURE2D_PARAM(lutTex, lutSampler), float3 lutParams, float exposure)
{
input *= exposure;
float3 inputLutSpace = saturate(LinearToLogC(input));
}
ApplyLut2D로 톤 매핑 변경 사항을 적용하고 결과를 반환합니다.
half3 ApplyTonemapping(half3 input, TEXTURE2D_PARAM(lutTex, lutSampler), float3 lutParams, float exposure)
{
input *= exposure;
float3 inputLutSpace = saturate(LinearToLogC(input));
return ApplyLut2D(TEXTURE2D_ARGS(lutTex, lutSampler), inputLutSpace, lutParams);
}
아래와 같이 표준 Frag 메서드를 생성합니다. 이 메서드는 HLSLPROGRAM 내부, ApplyTonemapping 메서드 이후에 배치합니다.
half4 Frag(Varyings input) : SV_Target
{
}
Frag 메서드에서 원본 카메라 컬러와 오버레이 컬러를 찾습니다.
half4 Frag(Varyings input) : SV_Target
{
half4 color = FragBlit(input, sampler_LinearClamp);
half4 overlay = SAMPLE_TEXTURE2D_X(_OverlayTexture, sampler_LinearClamp, input.texcoord);
}
if 문을 생성하여 셰이더가 톤 매핑을 적용해야 하는지 확인합니다. 셰이더가 톤 매핑을 적용해야 하는 경우 ApplyTonemapping 메서드를 사용하여 톤 매핑을 오버레이에 적용합니다.
half4 Frag(Varyings input) : SV_Target
{
half4 color = FragBlit(input, sampler_LinearClamp);
half4 overlay = SAMPLE_TEXTURE2D_X(_OverlayTexture, sampler_LinearClamp, input.texcoord);
#if TONEMAPPING
overlay.rgb = ApplyTonemapping(overlay.rgb, TEXTURE2D_ARGS(_InternalLut, sampler_LinearClamp), LutParams, PostExposure);
#endif
}
오버레이를 원본 카메라 컬러와 블렌딩하고 결과를 반환합니다.
half4 Frag(Varyings input) : SV_Target
{
half4 color = FragBlit(input, sampler_LinearClamp);
half4 overlay = SAMPLE_TEXTURE2D_X(_OverlayTexture, sampler_LinearClamp, input.texcoord);
#if TONEMAPPING
overlay.rgb = ApplyTonemapping(overlay.rgb, TEXTURE2D_ARGS(_InternalLut, sampler_LinearClamp), LutParams, PostExposure);
#endif
color.rgb = color.rgb * (1.0 - overlay.a) + overlay.rgb * overlay.a;
return color;
}
이제 셰이더가 완성되어 CustomOverlayRenderPass 및 CustomOverlayRendererFeature 스크립트에서 사용할 수 있게 되었습니다.
이 섹션의 전체 코드를 보려면 커스텀 오버레이 셰이더 코드를 참조하십시오.
커스텀 오버레이를 완성하려면 생성한 스크립트를 설정하여 그 효과를 씬의 렌더러에 적용해야 합니다. 그 과정은 다음과 같습니다.
CustomOverlayRendererFeature 스크립트를 추가합니다.CustomOverlayBlit 셰이더를 커스텀 오버레이 스크립터블 렌더러 기능의 Shader 프로퍼티에 할당합니다.OverlayRenderTexture를 할당합니다.이제 커스텀 오버레이가 완성되었으며 플레이 모드에서 메인 카메라 출력 위에 나타날 것입니다. 해당 오버레이는 메인 카메라 출력과 동일한 방식으로 톤 매핑되어야 하며 가시적인 차이가 없을 것입니다. 그 결과는 아래의 스크린샷과 유사해야 합니다.

게임 뷰의 중간에 있는 큐브와 다른 각도에서 본 큐브가 오버레이로 표시되며 HDR 출력과 일치하도록 톤 매핑되었습니다.
참고: 최종 결과는 오버레이 카메라의 배치에 따라 달라질 수 있습니다.
다음은 예시에 제시된 스크립터블 렌더 패스에 대한 전체 코드 샘플입니다.
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
[SupportedOnRenderer(typeof(UniversalRendererData))] -->
public class CustomOverlayRenderPass : ScriptableRenderPass
{
Material passMaterial;
RTHandle overlayTextureHandle;
public CustomOverlayRenderPass(Material material)
{
passMaterial = material;
profilingSampler = new ProfilingSampler(nameof(CustomOverlayRenderPass));
// The render pass is executed after post processing, so the main camera target has been tonemapped but not the overlay texture
renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
}
public void Setup(Texture overlayTex)
{
//Create an RTHandle from the overlay texture, to import it into the render graph system
if (overlayTextureHandle != overlayTex)
{
overlayTextureHandle?.Release();
overlayTextureHandle = RTHandles.Alloc(overlayTex);
}
}
public void Dispose()
{
overlayTextureHandle?.Release();
}
class CopyData
{
public TextureHandle source;
}
class PassData
{
public TextureHandle source;
public TextureHandle overlayTexture;
public TextureHandle internalLut;
public Vector4 lutParams;
public Material material;
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
UniversalPostProcessingData postProcessingData = frameData.Get<UniversalPostProcessingData>();
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
TextureHandle activeCameraColor = resourceData.activeColorTexture;
// Create a texture to copy the active camera color target into
RenderTextureDescriptor colorCopyDescriptor = cameraData.cameraTargetDescriptor;
colorCopyDescriptor.depthBufferBits = (int) DepthBits.None;
TextureHandle copiedColor = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorCopyDescriptor, "_CustomCameraColorCopy", false);
// Copy the active camera color target into the texture
using (var builder = renderGraph.AddRasterRenderPass<CopyData>("Custom Overlay Render Pass - Copy Camera", out var passData))
{
passData.source = activeCameraColor;
builder.UseTexture(passData.source, AccessFlags.Read);
builder.SetRenderAttachment(copiedColor, 0, AccessFlags.WriteAll);
builder.SetRenderFunc((CopyData data, RasterGraphContext context) =>
{
Blitter.BlitTexture(context.cmd, data.source, new Vector4(1, 1, 0, 0), 0.0f, false);
});
}
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Custom Overlay Render Pass - Blit Overlay", out var passData))
{
passData.material = passMaterial;
builder.SetRenderAttachment(activeCameraColor, 0, AccessFlags.Write);
passData.source = copiedColor;
builder.UseTexture(passData.source, AccessFlags.Read);
// Import the overlay texture that will be copied onto the camera color, and set it as an input
passData.overlayTexture = renderGraph.ImportTexture(overlayTextureHandle);
builder.UseTexture(passData.overlayTexture, AccessFlags.Read);
// If post-processing is enabled on the main camera, apply the tonemapping to the overlay texture as well
// If post processing is disabled, the HDR color conversion will be applied after this render pass and the expected colorspace for the cameras output is the default Rec709
if (postProcessingData.gradingMode == ColorGradingMode.HighDynamicRange && cameraData.postProcessEnabled)
{
// Import the internal color LUT texture used for HDR color grading and tonemapping
// This includes any HDR color conversion URP needs for the display, so the output of the camera is in the display's color gamut
passData.internalLut = resourceData.internalColorLut;
builder.UseTexture(passData.internalLut, AccessFlags.Read);
// Pass LUT parameters to the shader
int lutHeight = postProcessingData.lutSize;
int lutWidth = lutHeight * lutHeight;
float postExposure = 1.0f;
ColorAdjustments colorAdjustments = VolumeManager.instance.stack.GetComponent<ColorAdjustments>();
if (colorAdjustments != null)
{
postExposure = Mathf.Pow(2.0f, colorAdjustments.postExposure.value);
}
passData.lutParams = new Vector4(1f / lutWidth, 1f / lutHeight, lutHeight - 1f, postExposure);
}
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
{
// Pass parameters to the shader
data.material.SetTexture("_OverlayTexture", data.overlayTexture);
// Set a keyword on the shader to enable tonemapping
bool tonemappingActive = data.internalLut.IsValid();
CoreUtils.SetKeyword(data.material, "TONEMAPPING", tonemappingActive);
if (tonemappingActive)
{
data.material.SetTexture("_InternalLut", data.internalLut);
data.material.SetVector("_InternalLut_Params", data.lutParams);
}
// Blit the overlay texture onto the camera color
Blitter.BlitTexture(context.cmd, data.source, new Vector4(1, 1, 0, 0), data.material, 0);
});
}
}
}
다음은 예시에 제시된 스크립터블 렌더러 기능에 대한 전체 코드 샘플입니다.
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class CustomOverlayRendererFeature : ScriptableRendererFeature
{
public Shader hdrShader;
public RenderTexture passOverlayTexture;
Material passMaterial;
CustomOverlayRenderPass overlayRenderPass = null;
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
// Render the overlay onto the main camera during Game view rendering only, for the last camera in the camera stack
if (renderingData.cameraData.cameraType != CameraType.Game || !renderingData.cameraData.resolveFinalTarget)
return;
// Pass the overlay texture at runtime in case it changes
overlayRenderPass.Setup(passOverlayTexture);
// Enqueue the render pass to be executed
renderer.EnqueuePass(overlayRenderPass);
}
public override void Create()
{
// Create a blit material from the given shader
passMaterial = CoreUtils.CreateEngineMaterial(hdrShader);
// Create the render pass
overlayRenderPass = new CustomOverlayRenderPass(passMaterial);
}
protected override void Dispose(bool disposing)
{
// Destroy the render pass resources
CoreUtils.Destroy(passMaterial);
overlayRenderPass.Dispose();
}
}
다음은 예시에 제시된 셰이더에 대한 전체 코드 샘플입니다.
Shader "Custom/CustomOverlayBlit"
{
SubShader
{
Tags{ "RenderPipeline" = "UniversalPipeline" }
Pass
{
ZWrite Off ZTest Always Blend Off Cull Off
HLSLPROGRAM
#pragma target 2.0
#pragma editor_sync_compilation
#pragma vertex Vert
#pragma fragment Frag
#pragma multi_compile_local_fragment _ TONEMAPPING
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
TEXTURE2D(_InternalLut);
TEXTURE2D_X(_OverlayTexture);
float4 _InternalLut_Params;
#define LutParams _InternalLut_Params.xyz
#define PostExposure _InternalLut_Params.w
half3 ApplyTonemapping(half3 input, TEXTURE2D_PARAM(lutTex, lutSampler), float3 lutParams, float exposure)
{
input *= exposure;
float3 inputLutSpace = saturate(LinearToLogC(input)); // LUT space is in LogC
return ApplyLut2D(TEXTURE2D_ARGS(lutTex, lutSampler), inputLutSpace, lutParams);
}
half4 Frag(Varyings input) : SV_Target
{
// Get the original camera color
half4 color = FragBlit(input, sampler_LinearClamp);
// Get the overlay color
half4 overlay = SAMPLE_TEXTURE2D_X(_OverlayTexture, sampler_LinearClamp, input.texcoord);
// Tonemap the overlay
#if TONEMAPPING
overlay.rgb = ApplyTonemapping(overlay.rgb, TEXTURE2D_ARGS(_InternalLut, sampler_LinearClamp), LutParams, PostExposure);
#endif
// Blend overlay and color
color.rgb = color.rgb * (1.0 - overlay.a) + overlay.rgb * overlay.a;
return color;
}
ENDHLSL
}
}
}