194 lines
8.2 KiB
C#
194 lines
8.2 KiB
C#
// SPDX-License-Identifier: (Not available for this version, you are only allowed to use this software if you have express permission from the copyright holder and agreed to the latest NiloToonURP EULA)
|
|
// Copyright (c) 2021 Kuroneko ShaderLab Limited
|
|
|
|
// Fur rendering pass — draws lilToon-style barycentric fur shells.
|
|
// Two ShaderTagIds: depth prepass first, then color pass.
|
|
// Standalone/Editor only, and only when the current graphics device supports geometry shaders.
|
|
// Renderer feature toggle defaults OFF.
|
|
|
|
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
#if UNITY_6000_0_OR_NEWER
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
#endif
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
namespace NiloToon.NiloToonURP
|
|
{
|
|
public class NiloToonFurPass : ScriptableRenderPass
|
|
{
|
|
[Serializable]
|
|
public class Settings
|
|
{
|
|
[Tooltip("Enable fur shell rendering for NiloToonCharacter materials that have Fur enabled.\n" +
|
|
"Standalone only. Has no effect on mobile platforms.\n\n" +
|
|
"Default: OFF")]
|
|
[OverrideDisplayName("Allow Render?")]
|
|
[Revertible]
|
|
public bool supportFur = false;
|
|
|
|
[Tooltip("Render fur shells into the prepass buffer so fur silhouette edges are included in bloom/tonemapping character area detection and face mask.\n" +
|
|
"Without this, fur edges may be excluded from NiloToon post-processing effects.\n\n" +
|
|
"Default: ON")]
|
|
[DisableIf("supportFur", false)]
|
|
[OverrideDisplayName(" Draw in Nilo Prepass")]
|
|
[Revertible]
|
|
public bool furPrepassBuffer = true;
|
|
}
|
|
|
|
static readonly ShaderTagId furDepthPrepassShaderTagId = new ShaderTagId("NiloToonFurDepthPrepass");
|
|
static readonly ShaderTagId furColorShaderTagId = new ShaderTagId("NiloToonFur");
|
|
|
|
NiloToonRendererFeatureSettings allSettings;
|
|
Settings settings;
|
|
ProfilingSampler m_ProfilingSamplerFur;
|
|
|
|
public NiloToonFurPass(NiloToonRendererFeatureSettings allSettings)
|
|
{
|
|
this.allSettings = allSettings;
|
|
this.settings = allSettings.furSettings;
|
|
m_ProfilingSamplerFur = new ProfilingSampler("NiloToonFurPass");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true when fur is active and fur prepass buffer rendering is enabled.
|
|
/// </summary>
|
|
public bool ShouldRenderFurPrepassBuffer()
|
|
{
|
|
return ShouldEnqueue() && settings.furPrepassBuffer;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true only on standalone/editor platforms when fur support is enabled
|
|
/// and the current graphics device supports geometry shaders.
|
|
/// </summary>
|
|
public bool ShouldEnqueue()
|
|
{
|
|
if (!settings.supportFur)
|
|
return false;
|
|
|
|
#if UNITY_STANDALONE || UNITY_EDITOR
|
|
return SystemInfo.supportsGeometryShaders;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
//=====================================================================
|
|
// Legacy (pre-RenderGraph) path
|
|
//=====================================================================
|
|
#if !UNITY_6000_4_OR_NEWER
|
|
#if UNITY_6000_0_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
if (!ShouldEnqueue())
|
|
return;
|
|
|
|
CommandBuffer cmd = CommandBufferPool.Get();
|
|
using (new ProfilingScope(cmd, m_ProfilingSamplerFur))
|
|
{
|
|
context.ExecuteCommandBuffer(cmd);
|
|
cmd.Clear();
|
|
|
|
// Draw fur depth prepass first
|
|
DrawingSettings drawingSettingsDepth = CreateDrawingSettings(furDepthPrepassShaderTagId, ref renderingData, SortingCriteria.CommonOpaque);
|
|
FilteringSettings filteringSettings = new FilteringSettings(RenderQueueRange.opaque);
|
|
NiloToonRenderingUtils.DrawRendererListOrRenderers(context, cmd, renderingData.cullResults, ref drawingSettingsDepth, ref filteringSettings);
|
|
|
|
// Execute depth prepass before color pass
|
|
context.ExecuteCommandBuffer(cmd);
|
|
cmd.Clear();
|
|
|
|
// Draw fur color pass
|
|
DrawingSettings drawingSettingsColor = CreateDrawingSettings(furColorShaderTagId, ref renderingData, SortingCriteria.CommonOpaque);
|
|
NiloToonRenderingUtils.DrawRendererListOrRenderers(context, cmd, renderingData.cullResults, ref drawingSettingsColor, ref filteringSettings);
|
|
}
|
|
|
|
context.ExecuteCommandBuffer(cmd);
|
|
cmd.Clear();
|
|
CommandBufferPool.Release(cmd);
|
|
}
|
|
#endif
|
|
|
|
public override void OnCameraCleanup(CommandBuffer cmd)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
//=====================================================================
|
|
// RenderGraph path (Unity 6+)
|
|
//=====================================================================
|
|
#if UNITY_6000_0_OR_NEWER
|
|
class PassData
|
|
{
|
|
public RendererListHandle depthPrepassRendererListHandle;
|
|
public RendererListHandle colorRendererListHandle;
|
|
public bool shouldRender;
|
|
}
|
|
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
|
{
|
|
string passName = "NiloToonFur(RG)";
|
|
|
|
using (var builder = renderGraph.AddRasterRenderPass<PassData>(passName, out var passData))
|
|
{
|
|
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
UniversalRenderingData renderingData = frameData.Get<UniversalRenderingData>();
|
|
UniversalLightData lightData = frameData.Get<UniversalLightData>();
|
|
|
|
SortingCriteria sortFlags = SortingCriteria.CommonOpaque;
|
|
FilteringSettings filterSettings = new FilteringSettings(RenderQueueRange.opaque, ~0);
|
|
|
|
// Depth prepass renderer list
|
|
DrawingSettings drawSettingsDepth = RenderingUtils.CreateDrawingSettings(furDepthPrepassShaderTagId, renderingData, cameraData, lightData, sortFlags);
|
|
var depthRendererListParams = new RendererListParams(renderingData.cullResults, drawSettingsDepth, filterSettings);
|
|
passData.depthPrepassRendererListHandle = renderGraph.CreateRendererList(depthRendererListParams);
|
|
|
|
// Color pass renderer list
|
|
DrawingSettings drawSettingsColor = RenderingUtils.CreateDrawingSettings(furColorShaderTagId, renderingData, cameraData, lightData, sortFlags);
|
|
var colorRendererListParams = new RendererListParams(renderingData.cullResults, drawSettingsColor, filterSettings);
|
|
passData.colorRendererListHandle = renderGraph.CreateRendererList(colorRendererListParams);
|
|
|
|
passData.shouldRender = ShouldEnqueue();
|
|
|
|
builder.UseRendererList(passData.depthPrepassRendererListHandle);
|
|
builder.UseRendererList(passData.colorRendererListHandle);
|
|
|
|
if (resourceData.activeColorTexture.IsValid())
|
|
builder.SetRenderAttachment(resourceData.activeColorTexture, 0);
|
|
if (resourceData.activeDepthTexture.IsValid())
|
|
builder.SetRenderAttachmentDepth(resourceData.activeDepthTexture, AccessFlags.Write);
|
|
|
|
builder.AllowGlobalStateModification(true);
|
|
|
|
builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePassRG(data, context));
|
|
}
|
|
}
|
|
|
|
static void ExecutePassRG(PassData data, RasterGraphContext context)
|
|
{
|
|
if (!data.shouldRender)
|
|
return;
|
|
|
|
var cmd = context.cmd;
|
|
|
|
// Draw depth prepass first, then color pass
|
|
cmd.DrawRendererList(data.depthPrepassRendererListHandle);
|
|
cmd.DrawRendererList(data.colorRendererListHandle);
|
|
}
|
|
#endif
|
|
}
|
|
}
|