- NiloToonURP 외부 에셋 업데이트 - 배경 씬 썸네일 16:9 해상도로 갱신 - 렌더 파이프라인 설정 업데이트 - 외부 셰이더 그래프 업데이트 (LEDScreen, PIDI Planar Reflections) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
257 lines
13 KiB
C#
257 lines
13 KiB
C#
// very similar to URP's DepthNormalOnlyPass.cs, but only draw NiloToon character shader's "LightMode" = "NiloToonPrepassBuffer" pass.("LightMode"= ShaderTagId in C#)
|
|
// this pass's on/off is handled by NiloToonAllInOneRendererFeature.cs's AddRenderPasses() function
|
|
|
|
// *see DBufferRenderPass.cs to learn how to "ReAllocateIfNeeded" & "Dispose" RTHandle correctly
|
|
|
|
/*
|
|
_NiloToonPrepassBufferRT is storing the following data
|
|
-r: face
|
|
-g: character visible area (for NiloToon Bloom / NiloToon Tonemapping)
|
|
-b: unused
|
|
-a: unused
|
|
|
|
* We may draw IsFace,IsSkin,RimArea into this RT in future versions
|
|
*/
|
|
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.RendererUtils;
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
#endif
|
|
|
|
namespace NiloToon.NiloToonURP
|
|
{
|
|
public class NiloToonPrepassBufferRTPass : ScriptableRenderPass
|
|
{
|
|
NiloToonRendererFeatureSettings allSettings;
|
|
|
|
#if UNITY_2022_2_OR_NEWER
|
|
RTHandle prepassBufferRTHColor;
|
|
RTHandle prepassBufferRTHDepth;
|
|
#else
|
|
RenderTargetHandle prepassBufferRTH;
|
|
#endif
|
|
|
|
// Constants
|
|
static readonly ShaderTagId shaderTagId = new ShaderTagId("NiloToonPrepassBuffer");
|
|
|
|
// Constructor(will not call every frame)
|
|
public NiloToonPrepassBufferRTPass(NiloToonRendererFeatureSettings allSettings)
|
|
{
|
|
this.allSettings = allSettings;
|
|
|
|
#if !UNITY_2022_2_OR_NEWER
|
|
prepassBufferRTH.Init("_NiloToonPrepassBufferRT"); // this is RT's name, different to the texture name used in shader
|
|
#endif
|
|
|
|
base.profilingSampler = new ProfilingSampler(nameof(NiloToonPrepassBufferRTPass));
|
|
}
|
|
#if !UNITY_6000_4_OR_NEWER
|
|
// This method is called before executing the render pass.
|
|
// It can be used to configure render targets and their clear state. Also to create temporary render target textures.
|
|
// When empty this render pass will render to the active camera render target.
|
|
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
|
|
// The render pipeline will ensure target setup and clearing happens in a performant manner.
|
|
#if UNITY_6000_0_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
// When doing prepass rendering, the RT's depth format(depth bit/depthStencilFormat/MSAA) need to be exactly matching formats from _CameraDepthTexture, else when rejecting blocked character pixels(using _CameraDepthTexture) will fail
|
|
RenderTextureDescriptor renderTextureDescriptor = renderingData.cameraData.cameraTargetDescriptor;
|
|
var cameraData = renderingData.cameraData;
|
|
|
|
// In URP12's DepthNormalOnlyPass.cs->Setup(...)
|
|
// or
|
|
// In URP14's UniversalRenderer.cs->Setup(...)
|
|
// depthHandle's msaaSamples is forcibly set to 1(No MSAA),
|
|
// so we need to follow it to make both _NiloToonPrepassBufferTex and _CameraDepthTexture's depthStencilFormat and MSAA 100% match,
|
|
// so that the depth comparision in prepass buffer shader is 100% correct
|
|
// TODO: if we use DBufferRenderPass as reference, we should "ReAllocateIfNeeded" all RTHandle inside a SetUp() method, and let NiloToonAllInOneRendererFeature's SetupRenderPasses() to call it
|
|
#if UNITY_2022_2_OR_NEWER
|
|
// see URP14 DBufferRenderPass.cs->Setup(...) for reference about how to set up color and depth Descriptor and RenderingUtils.ReAllocateIfNeeded() RTHandle
|
|
|
|
// [color RTHandle's Descriptor]
|
|
var colorDesc = cameraData.cameraTargetDescriptor;
|
|
colorDesc.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm; // we don't need HDR color, since this RT's color is just a mask, so we change colorFormat to R8G8B8A8_UNorm
|
|
colorDesc.depthBufferBits = 0;
|
|
colorDesc.msaaSamples = 1;
|
|
|
|
// [depth RTHandle's Descriptor]
|
|
var depthDesc = cameraData.cameraTargetDescriptor;
|
|
depthDesc.graphicsFormat = GraphicsFormat.None; //Depth only rendering
|
|
depthDesc.depthStencilFormat = cameraData.cameraTargetDescriptor.depthStencilFormat;
|
|
depthDesc.msaaSamples = 1;
|
|
#else
|
|
renderTextureDescriptor.colorFormat = RenderTextureFormat.ARGB32;
|
|
renderTextureDescriptor.depthStencilFormat = cameraData.cameraTargetDescriptor.depthStencilFormat;
|
|
renderTextureDescriptor.msaaSamples = 1;
|
|
#endif
|
|
|
|
#if UNITY_2022_2_OR_NEWER
|
|
RenderingUtils.ReAllocateIfNeeded(ref prepassBufferRTHColor, colorDesc, name: "_NiloToonPrepassBufferColor");
|
|
RenderingUtils.ReAllocateIfNeeded(ref prepassBufferRTHDepth, depthDesc, name: "_NiloToonPrepassBufferDepth");
|
|
|
|
//set global RT
|
|
cmd.SetGlobalTexture("_NiloToonPrepassBufferTex", prepassBufferRTHColor);
|
|
cmd.SetGlobalTexture("_NiloToonPrepassBufferDepthTex", prepassBufferRTHDepth);
|
|
#else
|
|
cmd.GetTemporaryRT(prepassBufferRTH.id, renderTextureDescriptor);
|
|
|
|
//set global RT
|
|
cmd.SetGlobalTexture("_NiloToonPrepassBufferTex", prepassBufferRTH.Identifier());
|
|
#endif
|
|
|
|
|
|
#if UNITY_2022_2_OR_NEWER
|
|
ConfigureTarget(prepassBufferRTHColor,prepassBufferRTHDepth);
|
|
#else
|
|
ConfigureTarget(new RenderTargetIdentifier(prepassBufferRTH.Identifier(),0, CubemapFace.Unknown, -1));
|
|
#endif
|
|
|
|
ConfigureClear(ClearFlag.All, Color.black);
|
|
}
|
|
|
|
// Here you can implement the rendering logic.
|
|
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
|
|
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
|
|
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
|
|
#if UNITY_6000_0_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
// since this pass is only enqueued when conditions are met in NiloToonAllInOneRendererFeature's AddRenderPasses method.
|
|
// we don't need to do any "Should render?" check in this pass
|
|
|
|
// Never draw in Preview
|
|
Camera camera = renderingData.cameraData.camera;
|
|
if (camera.cameraType == CameraType.Preview)
|
|
return;
|
|
|
|
// NOTE: Do NOT mix ProfilingScope with named CommandBuffers i.e. CommandBufferPool.Get("name").
|
|
// Currently there's an issue which results in mismatched markers.
|
|
var cmd = CommandBufferPool.Get();
|
|
using (new ProfilingScope(cmd, base.profilingSampler))
|
|
{
|
|
/*
|
|
Note : should always ExecuteCommandBuffer at least once before using
|
|
ScriptableRenderContext functions (e.g. DrawRenderers) even if you
|
|
don't queue any commands! This makes sure the frame debugger displays
|
|
everything under the correct title.
|
|
*/
|
|
// https://www.cyanilux.com/tutorials/custom-renderer-features/?fbclid=IwAR27j2f3VVo0IIYDa32Dh76G9KPYzwb8j1J5LllpSnLXJiGf_UHrQ_lDtKg
|
|
context.ExecuteCommandBuffer(cmd);
|
|
cmd.Clear();
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// draw all nilotoon character renderer's "NiloToonPrepassBuffer" pass using SRP batching
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
var filterSetting = new FilteringSettings(RenderQueueRange.opaque); //TODO: should include transparent also?
|
|
|
|
var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
|
|
var drawSettings = CreateDrawingSettings(shaderTagId, ref renderingData, sortFlags);
|
|
drawSettings.perObjectData = PerObjectData.None;
|
|
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSetting);
|
|
}
|
|
|
|
// must write these line after using{} finished, to ensure profiler and frame debugger display correctness
|
|
context.ExecuteCommandBuffer(cmd);
|
|
cmd.Clear();
|
|
CommandBufferPool.Release(cmd);
|
|
}
|
|
#endif
|
|
// Cleanup any allocated resources that were created during the execution of this render pass.
|
|
public override void OnCameraCleanup(CommandBuffer cmd)
|
|
{
|
|
// To Release a RTHandle, do it in ScriptableRendererFeature's Dispose(), don't do it in OnCameraCleanup(...)
|
|
//https://www.cyanilux.com/tutorials/custom-renderer-features/#oncameracleanup
|
|
|
|
#if !UNITY_2022_2_OR_NEWER
|
|
cmd.ReleaseTemporaryRT(prepassBufferRTH.id);
|
|
#endif
|
|
}
|
|
|
|
#if UNITY_2022_2_OR_NEWER
|
|
public void Dispose()
|
|
{
|
|
prepassBufferRTHColor?.Release();
|
|
prepassBufferRTHDepth?.Release();
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// RG support
|
|
/////////////////////////////////////////////////////////////////////
|
|
#if UNITY_6000_0_OR_NEWER
|
|
private class PrepassBufferPassData
|
|
{
|
|
public UniversalCameraData cameraData;
|
|
public TextureHandle colorTarget;
|
|
public TextureHandle depthTarget;
|
|
public RendererListHandle rendererList;
|
|
}
|
|
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
|
|
{
|
|
var cameraData = frameContext.Get<UniversalCameraData>();
|
|
var resourceData = frameContext.Get<UniversalResourceData>();
|
|
var renderingData = frameContext.Get<UniversalRenderingData>();
|
|
|
|
// Skip Preview cameras - same check as Execute
|
|
if (cameraData.camera.cameraType == CameraType.Preview)
|
|
return;
|
|
|
|
using (var builder = renderGraph.AddRasterRenderPass<PrepassBufferPassData>("NiloToon Prepass Buffer", out var passData, base.profilingSampler))
|
|
{
|
|
passData.cameraData = cameraData;
|
|
|
|
// Create render textures for RG - EXACT same descriptors as OnCameraSetup
|
|
var colorDesc = cameraData.cameraTargetDescriptor;
|
|
colorDesc.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm; // Match: we don't need HDR color, since this RT's color is just a mask
|
|
colorDesc.depthBufferBits = 0;
|
|
colorDesc.msaaSamples = 1;
|
|
|
|
var depthDesc = cameraData.cameraTargetDescriptor;
|
|
depthDesc.graphicsFormat = GraphicsFormat.None; // Match: Depth only rendering
|
|
depthDesc.depthStencilFormat = cameraData.cameraTargetDescriptor.depthStencilFormat;
|
|
depthDesc.msaaSamples = 1;
|
|
|
|
passData.colorTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorDesc, "_NiloToonPrepassBufferColor", false);
|
|
passData.depthTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDesc, "_NiloToonPrepassBufferDepth", false);
|
|
|
|
// Create renderer list - EXACT same settings as Execute
|
|
var renderListDesc = new RendererListDesc(shaderTagId, renderingData.cullResults, cameraData.camera)
|
|
{
|
|
sortingCriteria = cameraData.defaultOpaqueSortFlags, // Match: var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
|
|
renderQueueRange = RenderQueueRange.opaque, // Match: var filterSetting = new FilteringSettings(RenderQueueRange.opaque);
|
|
};
|
|
passData.rendererList = renderGraph.CreateRendererList(renderListDesc);
|
|
|
|
// Set up render targets - Match ConfigureTarget behavior
|
|
builder.SetRenderAttachment(passData.colorTarget, 0, AccessFlags.Write);
|
|
builder.SetRenderAttachmentDepth(passData.depthTarget, AccessFlags.Write);
|
|
|
|
builder.UseRendererList(passData.rendererList);
|
|
|
|
// Set global textures - Match cmd.SetGlobalTexture behavior
|
|
builder.SetGlobalTextureAfterPass(passData.colorTarget, Shader.PropertyToID("_NiloToonPrepassBufferTex"));
|
|
builder.SetGlobalTextureAfterPass(passData.depthTarget, Shader.PropertyToID("_NiloToonPrepassBufferDepthTex"));
|
|
|
|
builder.SetRenderFunc((PrepassBufferPassData data, RasterGraphContext context) =>
|
|
{
|
|
// Match ConfigureClear(ClearFlag.All, Color.black) behavior
|
|
context.cmd.ClearRenderTarget(RTClearFlags.All, Color.black, 1.0f, 0);
|
|
|
|
// Match context.DrawRenderers behavior
|
|
context.cmd.DrawRendererList(data.rendererList);
|
|
});
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
} |