- 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>
1658 lines
88 KiB
C#
1658 lines
88 KiB
C#
// It is impossible to do correct custom tonemapping for URP via renderer feature.
|
|
// - If we do it @ RenderPassEvent.BeforeRenderingPostProcessing, URP's {CHROMATIC_ABERRATION,BLOOM,Vignette} will have a clamped input
|
|
// - If we do it @ RenderPassEvent.AfterRenderingPostProcessing, our tonemapping's input is clamped, it is wrong
|
|
|
|
// URP' official bloom's logic note
|
|
/*
|
|
// RT note (all RT = B10G11R11_UFloatPack32)
|
|
_CameraColorTexture = full resolution
|
|
_BloomMipDown0 = 1/2 resolution
|
|
_BloomMipUp1 = 1/4 resolution
|
|
_BloomMipDown1 = 1/4 resolution
|
|
_BloomMipUp2 = 1/8 resolution
|
|
_BloomMipDown2 = 1/8 resolution
|
|
...
|
|
|
|
// pass note
|
|
Bloom.shader - Bloom Prefilter = sample _CameraColorTexture(HQ = get more near samples, average) -> user clamp(min()) -> threshold -> EncodeHDR() -> return
|
|
Bloom.shader - Bloom Blur Horizontal = sample 9 taps gaussin blur -> EncodeHDR() -> return
|
|
Bloom.shader - Bloom Blur Vertical = sample 5 taps gaussin blur -> EncodeHDR() -> return
|
|
Bloom.shader - Bloom Upsample = sample _SourceTex and _SourceTexLowMip, then combine them by lerp(a,b,t) -> return
|
|
|
|
// render step
|
|
1.RT _CameraColorTexture render done, resolve
|
|
----------------------------------------
|
|
2.render RT _BloomMipDown0 (set _CameraColorTexture as _SourceTex)(Bloom.shader - Bloom Prefilter)
|
|
----------------------------------------
|
|
3.render RT _BloomMipUp1 (set _BloomMipDown0 as _SourceTex)(Bloom.shader - Bloom Blur Horizontal)
|
|
4.render RT _BloomMipDown1 (set _BloomMipUp1 as _SourceTex)(Bloom.shader - Bloom Blur Vertical)
|
|
5.render RT _BloomMipUp2 (set _BloomMipDown1 as _SourceTex)(Bloom.shader - Bloom Blur Horizontal)
|
|
6.render RT _BloomMipDown2 (set _BloomMipUp2 as _SourceTex)(Bloom.shader - Bloom Blur Vertical)
|
|
....
|
|
7.render RT _BloomMipUp8 (set _BloomMipDown7 as _SourceTex)(Bloom.shader - Bloom Blur Horizontal)
|
|
8.render RT _BloomMipDown8 (set _BloomMipUp8 as _SourceTex)(Bloom.shader - Bloom Blur Vertical)
|
|
----------------------------------------
|
|
9.render RT _BloomMipUp7 (set _BloomMipDown7 as _SourceTex, _BloomMipDown8 as _SourceTexLowMip)(Bloom.shader - Bloom Upsample)
|
|
----------------------------------------
|
|
10.render RT _BloomMipUp6 (set _BloomMipDown6 as _SourceTex, _BloomMipUp7 as _SourceTexLowMip)(Bloom.shader - Bloom Upsample)
|
|
11.render RT _BloomMipUp5 (set _BloomMipDown5 as _SourceTex, _BloomMipUp6 as _SourceTexLowMip)(Bloom.shader - Bloom Upsample)
|
|
12.render RT _BloomMipUp4 (set _BloomMipDown4 as _SourceTex, _BloomMipUp5 as _SourceTexLowMip)(Bloom.shader - Bloom Upsample)
|
|
...
|
|
13.render RT _BloomMipUp0 (set _BloomMipDown0 as _SourceTex, _BloomMipUp1 as _SourceTexLowMip)(Bloom.shader - Bloom Upsample)
|
|
----------------------------------------
|
|
14.render to <No name> (set _CameraColorTex as _SourceTex, _BloomMipUp0 as _BloomTexture, do LUT) (UberPost.shader - UberPost) (keyword = _BLOOM_LQ only)
|
|
(do ApplyColorGrading(_CameraColorTex + _BloomMipUp0 * BloomTint * BloomIntensity))
|
|
(so custom postprocess ping pong +bloom result, is correct)
|
|
*/
|
|
|
|
using System;
|
|
using System.Runtime.Serialization.Formatters;
|
|
using UnityEngine;
|
|
using UnityEngine.Assertions;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Profiling;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
using UnityEngine.XR;
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
#endif
|
|
|
|
#if UNITY_2021 || UNITY_2022
|
|
// On old Unity versions, alias our code's GraphicsFormatUsage to FormatUsage
|
|
using GraphicsFormatUsage = UnityEngine.Experimental.Rendering.FormatUsage;
|
|
#else
|
|
using GraphicsFormatUsage = UnityEngine.Experimental.Rendering.GraphicsFormatUsage;
|
|
#endif
|
|
|
|
namespace NiloToon.NiloToonURP
|
|
{
|
|
#if UNITY_2022_2_OR_NEWER
|
|
public class NiloToonUberPostProcessPass : ScriptableRenderPass
|
|
{
|
|
#region Singleton
|
|
public static NiloToonUberPostProcessPass Instance
|
|
{
|
|
get => _instance;
|
|
}
|
|
static NiloToonUberPostProcessPass _instance;
|
|
#endregion
|
|
|
|
[Serializable]
|
|
public class Settings
|
|
{
|
|
[Header("Render Timing")]
|
|
[Tooltip("The default value is BeforeRenderingPostProcess + 0, you can edit it to make NiloToon work with other renderer features")]
|
|
[OverrideDisplayName("Renderer Feature Order Offset")]
|
|
[Revertible]
|
|
public int renderPassEventTimingOffset = 0;
|
|
|
|
[Header("Bloom")]
|
|
[Tooltip("Can turn off to prevent rendering NiloToonBloomVolume, which will improve performance for low quality graphics setting renderer")]
|
|
[OverrideDisplayName("Allow render Bloom?")]
|
|
[Revertible]
|
|
public bool allowRenderNiloToonBloom = true;
|
|
}
|
|
public Settings settings { get; }
|
|
|
|
NiloToonRendererFeatureSettings allSettings;
|
|
|
|
ProfilingSampler niloToonBloomProfileSampler;
|
|
ProfilingSampler niloToonUberProfileSampler;
|
|
const string k_RenderPostProcessingTag = "Render NiloToon PostProcessing Effects"; // edited string value, original is "Render PostProcessing Effects"
|
|
NiloToonBloomVolume m_Bloom; // edited type, original is Bloom
|
|
ColorLookup m_ColorLookup;
|
|
ColorAdjustments m_ColorAdjustments;
|
|
NiloToonTonemappingVolume m_Tonemapping; // edited type, original is Tonemapping
|
|
|
|
RenderTextureDescriptor m_Descriptor;
|
|
//RTHandle m_Source; // disabled for "Not calling renderer.cameraColorTargetHandle in renderer feature"
|
|
|
|
RTHandle[] m_BloomMipDown;
|
|
RTHandle[] m_BloomMipUp;
|
|
RTHandle NiloTempRTH;
|
|
|
|
private static readonly ProfilingSampler m_ProfilingRenderPostProcessing = new ProfilingSampler(k_RenderPostProcessingTag);
|
|
|
|
MaterialLibrary m_Materials;
|
|
|
|
// Misc
|
|
const int k_MaxPyramidSize = 16;
|
|
readonly GraphicsFormat m_DefaultHDRFormat;
|
|
bool m_UseRGBM;
|
|
|
|
// this renderer feature/pass is NOT using swapbuffer system
|
|
const bool m_UseSwapBuffer = true;
|
|
|
|
public NiloToonUberPostProcessPass(NiloToonRendererFeatureSettings allSettings)
|
|
{
|
|
this.allSettings = allSettings;
|
|
settings = allSettings.uberPostProcessSettings;
|
|
_instance = this;
|
|
|
|
// name displayed in Frame debugger
|
|
niloToonBloomProfileSampler = new ProfilingSampler("Bloom");
|
|
niloToonUberProfileSampler = new ProfilingSampler("UberPostProcess");
|
|
|
|
Shader bloomShader = Shader.Find("Hidden/Universal Render Pipeline/NiloToonBloom");
|
|
Shader uberShader = Shader.Find("Hidden/Universal Render Pipeline/NiloToonUberPost");
|
|
Shader blitShader = Shader.Find("Hidden/Universal/CoreBlit");
|
|
|
|
base.profilingSampler = new ProfilingSampler(nameof(NiloToonUberPostProcessPass)); // edited type, original is PostProcessPass
|
|
m_Materials = new MaterialLibrary(bloomShader, uberShader, blitShader); // edited input param, original is a PostProcessData class instance
|
|
|
|
// Bloom pyramid shader ids - can't use a simple stackalloc in the bloom function as we
|
|
// unfortunately need to allocate strings
|
|
ShaderConstants._BloomMipUp = new int[k_MaxPyramidSize];
|
|
ShaderConstants._BloomMipDown = new int[k_MaxPyramidSize];
|
|
m_BloomMipUp = new RTHandle[k_MaxPyramidSize];
|
|
m_BloomMipDown = new RTHandle[k_MaxPyramidSize];
|
|
|
|
for (int i = 0; i < k_MaxPyramidSize; i++)
|
|
{
|
|
ShaderConstants._BloomMipUp[i] = Shader.PropertyToID("_NiloToonBloomMipUp" + i);
|
|
ShaderConstants._BloomMipDown[i] = Shader.PropertyToID("_NiloToonBloomMipDown" + i);
|
|
// Get name, will get Allocated with descriptor later
|
|
m_BloomMipUp[i] = RTHandles.Alloc(ShaderConstants._BloomMipUp[i], name: "_NiloToonBloomMipUp" + i); // edited string name, original is _BloomMipUp
|
|
m_BloomMipDown[i] = RTHandles.Alloc(ShaderConstants._BloomMipDown[i], name: "_NiloToonBloomMipDown" + i); // edited string name, original is _BloomMipDown
|
|
}
|
|
for (int i = 0; i < k_MaxPyramidSize; i++)
|
|
{
|
|
ShaderConstants._BloomMipUp[i] = Shader.PropertyToID("_NiloToonBloomMipUp" + i);
|
|
ShaderConstants._BloomMipDown[i] = Shader.PropertyToID("_NiloToonBloomMipDown" + i);
|
|
}
|
|
|
|
// [Copy from Unity6000.2.6f2 > PostProcessPass.cs]
|
|
// Texture format pre-lookup
|
|
// UUM-41070: We require `Linear | Render` but with the deprecated FormatUsage this was checking `Blend`
|
|
// For now, we keep checking for `Blend` until the performance hit of doing the correct checks is evaluated
|
|
|
|
//const FormatUsage usage = FormatUsage.Linear | FormatUsage.Render; // old, but still correct, don't use it anymore due to warning of FormatUsage obsolete API
|
|
//const GraphicsFormatUsage usage = GraphicsFormatUsage.Linear | GraphicsFormatUsage.Render; // naive change FormatUsage->GraphicsFormatUsage = wrong! fk unity why? don't use it!
|
|
const GraphicsFormatUsage usage = GraphicsFormatUsage.Blend; // correct, matching Unity6000.2.6f2 URP PostProcessPass.cs code
|
|
|
|
if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, usage)) // HDR fallback
|
|
{
|
|
m_DefaultHDRFormat = GraphicsFormat.B10G11R11_UFloatPack32;
|
|
m_UseRGBM = false;
|
|
}
|
|
else
|
|
{
|
|
m_DefaultHDRFormat = QualitySettings.activeColorSpace == ColorSpace.Linear
|
|
? GraphicsFormat.R8G8B8A8_SRGB
|
|
: GraphicsFormat.R8G8B8A8_UNorm;
|
|
m_UseRGBM = true;
|
|
}
|
|
}
|
|
|
|
public void Cleanup() => m_Materials.Cleanup();
|
|
|
|
public void Dispose()
|
|
{
|
|
foreach (var handle in m_BloomMipDown)
|
|
handle?.Release();
|
|
foreach (var handle in m_BloomMipUp)
|
|
handle?.Release();
|
|
|
|
NiloTempRTH?.Release();
|
|
}
|
|
public void Setup(in RenderTextureDescriptor baseDescriptor)
|
|
{
|
|
m_Descriptor = baseDescriptor;
|
|
m_Descriptor.useMipMap = false;
|
|
m_Descriptor.autoGenerateMips = false;
|
|
//m_Source = source;
|
|
}
|
|
#if !UNITY_6000_4_OR_NEWER
|
|
#if UNITY_6000_0_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
//overrideCameraTarget = true;
|
|
}
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
// [NiloToon added]
|
|
// re-init m_Materials if needed, usually m_Materials's materials are null on project's first-time startup (right after rebuild library folder)
|
|
if (m_Materials == null ||
|
|
m_Materials.blit == null ||
|
|
m_Materials.bloom == null ||
|
|
m_Materials.uber == null)
|
|
{
|
|
Shader bloomShader = Shader.Find("Hidden/Universal Render Pipeline/NiloToonBloom");
|
|
Shader uberShader = Shader.Find("Hidden/Universal Render Pipeline/NiloToonUberPost");
|
|
Shader blitShader = Shader.Find("Hidden/Universal/CoreBlit");
|
|
m_Materials = new MaterialLibrary(bloomShader, uberShader, blitShader);
|
|
}
|
|
|
|
// Start by pre-fetching all builtin effect settings we need
|
|
var stack = VolumeManager.instance.stack;
|
|
m_Bloom = stack.GetComponent<NiloToonBloomVolume>();
|
|
m_ColorLookup = stack.GetComponent<ColorLookup>();
|
|
m_ColorAdjustments = stack.GetComponent<ColorAdjustments>();
|
|
m_Tonemapping = stack.GetComponent<NiloToonTonemappingVolume>(); // edited type, original is Tonemapping
|
|
|
|
var cmd = CommandBufferPool.Get();
|
|
// Regular render path (not on-tile) - we do everything in a single command buffer as it
|
|
// makes it easier to manage temporary targets' lifetime
|
|
using (new ProfilingScope(cmd, m_ProfilingRenderPostProcessing))
|
|
{
|
|
/*
|
|
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();
|
|
|
|
Render(cmd, ref renderingData);
|
|
}
|
|
|
|
// must write these line after using{} finished, to ensure profiler and frame debugger display correctness
|
|
context.ExecuteCommandBuffer(cmd);
|
|
cmd.Clear();
|
|
CommandBufferPool.Release(cmd);
|
|
}
|
|
#endif
|
|
RenderTextureDescriptor GetCompatibleDescriptor()
|
|
=> GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_Descriptor.graphicsFormat);
|
|
|
|
RenderTextureDescriptor GetCompatibleDescriptor(int width, int height, GraphicsFormat format, DepthBits depthBufferBits = DepthBits.None)
|
|
=> GetCompatibleDescriptor(m_Descriptor, width, height, format, depthBufferBits);
|
|
|
|
internal static RenderTextureDescriptor GetCompatibleDescriptor(RenderTextureDescriptor desc, int width, int height, GraphicsFormat format, DepthBits depthBufferBits = DepthBits.None)
|
|
{
|
|
desc.depthBufferBits = (int)depthBufferBits;
|
|
desc.msaaSamples = 1;
|
|
desc.width = width;
|
|
desc.height = height;
|
|
desc.graphicsFormat = format;
|
|
return desc;
|
|
}
|
|
#if !UNITY_6000_4_OR_NEWER
|
|
#if UNITY_6000_0_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
void Render(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
ref var cameraData = ref renderingData.cameraData;
|
|
ref ScriptableRenderer renderer = ref cameraData.renderer;
|
|
|
|
// Don't use these directly unless you have a good reason to, use GetSource() and
|
|
// GetDestination() instead
|
|
RTHandle source = renderer.cameraColorTargetHandle; // call renderer.cameraColorTargetHandle here directly, for "Not calling renderer.cameraColorTargetHandle in renderer feature"
|
|
|
|
RTHandle GetSource() => source;
|
|
|
|
// Setup projection matrix for cmd.DrawMesh()
|
|
cmd.SetGlobalMatrix(ShaderConstants._FullscreenProjMat, GL.GetGPUProjectionMatrix(Matrix4x4.identity, true));
|
|
|
|
// Combined post-processing stack
|
|
using (new ProfilingScope(cmd, niloToonUberProfileSampler)) // NiloToon edit: original = ProfilingSampler.Get(URPProfileId.UberPostProcess)
|
|
{
|
|
// Reset uber keywords
|
|
m_Materials.uber.shaderKeywords = null;
|
|
|
|
// Bloom goes first
|
|
bool bloomActive = m_Bloom.IsActive();
|
|
bloomActive &= settings.allowRenderNiloToonBloom && cameraData.postProcessEnabled; // NiloToon edit: added && allowRenderNiloToonBloom && postProcessEnabled
|
|
if (bloomActive)
|
|
{
|
|
using (new ProfilingScope(cmd, niloToonBloomProfileSampler)) // NiloToon edit: ProfilingSampler.Get(URPProfileId.Bloom)
|
|
SetupBloom(cmd, GetSource(), m_Materials.uber);
|
|
}
|
|
|
|
// Setup other effects constants
|
|
bool tonemappingActive = m_Tonemapping.IsActive() && cameraData.postProcessEnabled;
|
|
|
|
// no need if check, always run
|
|
{
|
|
SetupColorGrading(cmd, ref renderingData, m_Materials.uber);
|
|
}
|
|
|
|
bool uberNeeded = bloomActive || tonemappingActive;
|
|
|
|
if (uberNeeded)
|
|
{
|
|
RenderTextureDescriptor rtdTempRT = renderingData.cameraData.cameraTargetDescriptor;
|
|
rtdTempRT.depthBufferBits = 0;
|
|
rtdTempRT.depthStencilFormat = GraphicsFormat.None;
|
|
rtdTempRT.msaaSamples = 1; // no need MSAA for just a blit
|
|
RenderingUtils.ReAllocateIfNeeded(ref NiloTempRTH, rtdTempRT, name: "_NiloToonUberTempRT");
|
|
|
|
// 1.Blit direct copy _CameraColorTexture to _NiloToonUberTempRT
|
|
Blitter.BlitCameraTexture(cmd, GetSource(), NiloTempRTH, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, m_Materials.blit, 0);
|
|
// 2.Blit _NiloToonUberTempRT to _CameraColorTexture, do uber postprocess
|
|
Blitter.BlitCameraTexture(cmd, NiloTempRTH, GetSource(), RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, m_Materials.uber, 0);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
[Obsolete]
|
|
#endif
|
|
void SetupBloom(CommandBuffer cmd, RTHandle source, Material uberMaterial)
|
|
{
|
|
// [NiloToon edited]
|
|
//===========================================================================================================
|
|
// URP's official bloom will have very different bloom result depending on game window size(height), because blur is applied to constant count of pixels(4+1+4).
|
|
// NiloToon's bloom can override to use a fixed size height instead of URP's "Start at half-res", to make all screen resolution's bloom result consistant.
|
|
|
|
int th;
|
|
int tw;
|
|
if (m_Bloom.renderTextureOverridedToFixedHeight.overrideState)
|
|
{
|
|
// NiloToon's bloom resolution override code
|
|
th = m_Bloom.renderTextureOverridedToFixedHeight.value;
|
|
tw = (int)Mathf.Min(SystemInfo.maxTextureSize,th * ((float)m_Descriptor.width / (float)m_Descriptor.height));
|
|
}
|
|
else
|
|
{
|
|
// URP's official bloom code
|
|
tw = m_Descriptor.width >> 1;
|
|
th = m_Descriptor.height >> 1;
|
|
}
|
|
//===========================================================================================================
|
|
|
|
// Determine the iteration count
|
|
int maxSize = Mathf.Max(tw, th);
|
|
int iterations = Mathf.FloorToInt(Mathf.Log(maxSize, 2f) - 1);
|
|
int mipCount = Mathf.Clamp(iterations, 1, m_Bloom.maxIterations.value);
|
|
|
|
// Pre-filtering parameters
|
|
float clamp = m_Bloom.clamp.value;
|
|
float threshold = Mathf.GammaToLinearSpace(m_Bloom.threshold.value);
|
|
float thresholdKnee = threshold * 0.5f; // Hardcoded soft knee
|
|
|
|
// Material setup
|
|
float scatter = Mathf.Lerp(0.05f, 0.95f, m_Bloom.scatter.value);
|
|
var bloomMaterial = m_Materials.bloom;
|
|
bloomMaterial.SetVector(ShaderConstants._Params, new Vector4(scatter, clamp, threshold, thresholdKnee));
|
|
CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.BloomHQ, m_Bloom.highQualityFiltering.value);
|
|
//CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.UseRGBM, m_UseRGBM); // disabled due to Unity6000.0.23f1 release on 2024/10/17
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
// if not overridden, use generic threshold.
|
|
// if overridden, use characterAreaOverridedThreshold.
|
|
float finalThreshold = Mathf.GammaToLinearSpace(m_Bloom.characterAreaOverridedThreshold.overrideState ? m_Bloom.characterAreaOverridedThreshold.value : m_Bloom.threshold.value);
|
|
float finalThresholdKnee = finalThreshold * 0.5f; // Hardcoded soft knee
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaThreshold", finalThreshold);
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaThresholdKnee", finalThresholdKnee);
|
|
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaBloomEmitMultiplier", m_Bloom.characterAreaBloomEmitMultiplier.value);
|
|
|
|
Vector4 HSV_applyToCharAreaOnly;
|
|
HSV_applyToCharAreaOnly.x = m_Bloom.HueOffset.value;
|
|
HSV_applyToCharAreaOnly.y = m_Bloom.SaturationBoost.value;
|
|
HSV_applyToCharAreaOnly.z = m_Bloom.ValueMultiply.value;
|
|
HSV_applyToCharAreaOnly.w = m_Bloom.ApplyHSVToCharAreaOnly.value;
|
|
bloomMaterial.SetVector("_NiloToonBloomHSVModifier", HSV_applyToCharAreaOnly);
|
|
//====================================================================================
|
|
|
|
// Prefilter
|
|
var desc = GetCompatibleDescriptor(tw, th, m_DefaultHDRFormat);
|
|
for (int i = 0; i < mipCount; i++)
|
|
{
|
|
RenderingUtils.ReAllocateIfNeeded(ref m_BloomMipUp[i], desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: m_BloomMipUp[i].name);
|
|
RenderingUtils.ReAllocateIfNeeded(ref m_BloomMipDown[i], desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: m_BloomMipDown[i].name);
|
|
desc.width = Mathf.Max(1, desc.width >> 1);
|
|
desc.height = Mathf.Max(1, desc.height >> 1);
|
|
}
|
|
|
|
Blitter.BlitCameraTexture(cmd, source, m_BloomMipDown[0], RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 0);
|
|
|
|
// Downsample - gaussian pyramid
|
|
var lastDown = m_BloomMipDown[0];
|
|
for (int i = 1; i < mipCount; i++)
|
|
{
|
|
// Classic two pass gaussian blur - use mipUp as a temporary target
|
|
// First pass does 2x downsampling + 9-tap gaussian
|
|
// Second pass does 9-tap gaussian using a 5-tap filter + bilinear filtering
|
|
Blitter.BlitCameraTexture(cmd, lastDown, m_BloomMipUp[i], RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 1);
|
|
Blitter.BlitCameraTexture(cmd, m_BloomMipUp[i], m_BloomMipDown[i], RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 2);
|
|
|
|
lastDown = m_BloomMipDown[i];
|
|
}
|
|
|
|
// Upsample (bilinear by default, HQ filtering does bicubic instead
|
|
for (int i = mipCount - 2; i >= 0; i--)
|
|
{
|
|
var lowMip = (i == mipCount - 2) ? m_BloomMipDown[i + 1] : m_BloomMipUp[i + 1];
|
|
var highMip = m_BloomMipDown[i];
|
|
var dst = m_BloomMipUp[i];
|
|
|
|
cmd.SetGlobalTexture(ShaderConstants._SourceTexLowMip, lowMip);
|
|
Blitter.BlitCameraTexture(cmd, highMip, dst, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 3);
|
|
}
|
|
|
|
// Setup bloom on uber
|
|
var tint = m_Bloom.tint.value.linear;
|
|
var luma = ColorUtils.Luminance(tint);
|
|
tint = luma > 0f ? tint * (1f / luma) : Color.white;
|
|
|
|
var bloomParams = new Vector4(m_Bloom.intensity.value, tint.r, tint.g, tint.b);
|
|
uberMaterial.SetVector(ShaderConstants._Bloom_Params, bloomParams);
|
|
uberMaterial.SetFloat(ShaderConstants._Bloom_RGBM, m_UseRGBM ? 1f : 0f);
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
// if not overridden, use generic intensity.
|
|
// if overridden, use characterAreaOverridedIntensity.
|
|
uberMaterial.SetFloat("_NiloToonBloomCharacterAreaIntensity", m_Bloom.characterAreaOverridedIntensity.overrideState ? m_Bloom.characterAreaOverridedIntensity.value : m_Bloom.intensity.value);
|
|
//====================================================================================
|
|
|
|
cmd.SetGlobalTexture(ShaderConstants._Bloom_Texture, m_BloomMipUp[0]);
|
|
|
|
// Setup lens dirtiness on uber
|
|
// Keep the aspect ratio correct & center the dirt texture, we don't want it to be
|
|
// stretched or squashed
|
|
var dirtTexture = m_Bloom.dirtTexture.value == null ? Texture2D.blackTexture : m_Bloom.dirtTexture.value;
|
|
float dirtRatio = dirtTexture.width / (float)dirtTexture.height;
|
|
float screenRatio = m_Descriptor.width / (float)m_Descriptor.height;
|
|
var dirtScaleOffset = new Vector4(1f, 1f, 0f, 0f);
|
|
float dirtIntensity = m_Bloom.dirtIntensity.value;
|
|
|
|
if (dirtRatio > screenRatio)
|
|
{
|
|
dirtScaleOffset.x = screenRatio / dirtRatio;
|
|
dirtScaleOffset.z = (1f - dirtScaleOffset.x) * 0.5f;
|
|
}
|
|
else if (screenRatio > dirtRatio)
|
|
{
|
|
dirtScaleOffset.y = dirtRatio / screenRatio;
|
|
dirtScaleOffset.w = (1f - dirtScaleOffset.y) * 0.5f;
|
|
}
|
|
|
|
uberMaterial.SetVector(ShaderConstants._LensDirt_Params, dirtScaleOffset);
|
|
uberMaterial.SetFloat(ShaderConstants._LensDirt_Intensity, dirtIntensity);
|
|
uberMaterial.SetTexture(ShaderConstants._LensDirt_Texture, dirtTexture);
|
|
|
|
// Keyword setup - a bit convoluted as we're trying to save some variants in Uber...
|
|
if (m_Bloom.highQualityFiltering.value)
|
|
uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomHQDirt : ShaderKeywordStrings.BloomHQ);
|
|
else
|
|
uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomLQDirt : ShaderKeywordStrings.BloomLQ);
|
|
}
|
|
|
|
void SetupColorGrading(CommandBuffer cmd, ref RenderingData renderingData, Material material)
|
|
{
|
|
ref var postProcessingData = ref renderingData.postProcessingData;
|
|
bool hdr = postProcessingData.gradingMode == ColorGradingMode.HighDynamicRange;
|
|
int lutHeight = postProcessingData.lutSize;
|
|
int lutWidth = lutHeight * lutHeight;
|
|
|
|
// Source material setup
|
|
float postExposureLinear = Mathf.Pow(2f, m_ColorAdjustments.postExposure.value);
|
|
//cmd.SetGlobalTexture(ShaderConstants._InternalLut, m_InternalLut.nameID); // [NiloToon edit] temp disabled since we don't have m_InternalLut here
|
|
material.SetVector(ShaderConstants._Lut_Params, new Vector4(1f / lutWidth, 1f / lutHeight, lutHeight - 1f, postExposureLinear));
|
|
material.SetTexture(ShaderConstants._UserLut, m_ColorLookup.texture.value);
|
|
material.SetVector(ShaderConstants._UserLut_Params, !m_ColorLookup.IsActive()
|
|
? Vector4.zero
|
|
: new Vector4(1f / m_ColorLookup.texture.value.width,
|
|
1f / m_ColorLookup.texture.value.height,
|
|
m_ColorLookup.texture.value.height - 1f,
|
|
m_ColorLookup.contribution.value)
|
|
);
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
// NiloToon can't support HDR Grading Mode due to URP's design,
|
|
// so we just enable the same NiloToon tonemapping code for both ldr and hdr Color Grading Mode
|
|
hdr = false;
|
|
//====================================================================================
|
|
|
|
if (hdr)
|
|
{
|
|
material.EnableKeyword(ShaderKeywordStrings.HDRGrading);
|
|
}
|
|
else
|
|
{
|
|
switch (m_Tonemapping.mode.value)
|
|
{
|
|
case TonemappingMode.Neutral: material.EnableKeyword(ShaderKeywordStrings.TonemapNeutral); break;
|
|
case TonemappingMode.ACES: material.EnableKeyword(ShaderKeywordStrings.TonemapACES); break;
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
case TonemappingMode.GT:
|
|
material.EnableKeyword("_TONEMAP_GRANTURISMO");
|
|
break;
|
|
case TonemappingMode.ACES_CustomSR:
|
|
// custom ACES function with ABCDE param from this repo, it has better saturation than other tonemap method
|
|
// https://github.com/stalomeow/StarRailNPRShader/blob/main/Shaders/Postprocessing/UberPost.shader
|
|
material.EnableKeyword("_TONEMAP_ACES_CUSTOM");
|
|
material.SetFloat("_NiloToon_CustomACESParamA", 2.8f);
|
|
material.SetFloat("_NiloToon_CustomACESParamB", 0.4f);
|
|
material.SetFloat("_NiloToon_CustomACESParamC", 2.1f);
|
|
material.SetFloat("_NiloToon_CustomACESParamD", 0.5f);
|
|
material.SetFloat("_NiloToon_CustomACESParamE", 1.5f);
|
|
break;
|
|
case TonemappingMode.KhronosPBRNeutral:
|
|
material.EnableKeyword("_TONEMAP_KHRONOS_PBR_NEUTRAL");
|
|
break;
|
|
case TonemappingMode.NiloNPRNeutralV1:
|
|
material.EnableKeyword("_TONEMAP_NILO_NPR_NEUTRAL_V1");
|
|
break;
|
|
case TonemappingMode.NiloHybirdACES:
|
|
material.EnableKeyword("_TONEMAP_NILO_HYBIRD_ACES");
|
|
break;
|
|
//====================================================================================
|
|
|
|
default: break; // None
|
|
}
|
|
}
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
material.SetFloat("_NiloToonTonemappingCharacterAreaRemove", 1 - m_Tonemapping.ApplyToCharacter.value * m_Tonemapping.intensity.value);
|
|
material.SetFloat("_NiloToonTonemappingCharacterAreaPreTonemapBrightnessMul", m_Tonemapping.BrightnessMulForCharacter.value * m_Bloom.characterPreTonemapBrightness.value);
|
|
|
|
material.SetFloat("_NiloToonTonemappingNonCharacterAreaRemove", 1 - m_Tonemapping.ApplyToNonCharacter.value * m_Tonemapping.intensity.value);
|
|
material.SetFloat("_NiloToonTonemappingNonCharacterAreaPreTonemapBrightnessMul", m_Tonemapping.BrightnessMulForNonCharacter.value);
|
|
//====================================================================================
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// RG support
|
|
/////////////////////////////////////////////////////////////////////
|
|
#if UNITY_6000_0_OR_NEWER
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
|
|
{
|
|
var resourceData = frameContext.Get<UniversalResourceData>();
|
|
var cameraData = frameContext.Get<UniversalCameraData>();
|
|
|
|
// Start by pre-fetching all builtin effect settings we need
|
|
var stack = VolumeManager.instance.stack;
|
|
m_Bloom = stack.GetComponent<NiloToonBloomVolume>();
|
|
m_ColorLookup = stack.GetComponent<ColorLookup>();
|
|
m_ColorAdjustments = stack.GetComponent<ColorAdjustments>();
|
|
m_Tonemapping = stack.GetComponent<NiloToonTonemappingVolume>();
|
|
|
|
// Check if we need any effects
|
|
bool bloomActive = m_Bloom.IsActive() && settings.allowRenderNiloToonBloom && cameraData.postProcessEnabled;
|
|
bool tonemappingActive = m_Tonemapping.IsActive() && cameraData.postProcessEnabled;
|
|
bool uberNeeded = bloomActive || tonemappingActive;
|
|
|
|
if (!uberNeeded)
|
|
return;
|
|
|
|
// Create RG pass data
|
|
using (var builder = renderGraph.AddUnsafePass<NiloToonUberPassData>("NiloToon Uber PostProcess", out var passData))
|
|
{
|
|
var resourcesData = frameContext.Get<UniversalResourceData>();
|
|
|
|
// Store references
|
|
passData.materials = m_Materials;
|
|
passData.bloom = m_Bloom;
|
|
passData.colorLookup = m_ColorLookup;
|
|
passData.colorAdjustments = m_ColorAdjustments;
|
|
passData.tonemapping = m_Tonemapping;
|
|
passData.descriptor = resourcesData.activeColorTexture.GetDescriptor(renderGraph);
|
|
passData.defaultHDRFormat = m_DefaultHDRFormat;
|
|
passData.useRGBM = m_UseRGBM;
|
|
passData.bloomActive = bloomActive;
|
|
passData.tonemappingActive = tonemappingActive;
|
|
|
|
// Input: camera color
|
|
passData.cameraColorTexture = resourcesData.activeColorTexture;
|
|
builder.UseTexture(resourceData.activeColorTexture, AccessFlags.ReadWrite);
|
|
|
|
// Output: write back to camera color
|
|
passData.outputTexture = resourcesData.cameraColor;
|
|
|
|
// If bloom is active, create bloom textures
|
|
if (bloomActive)
|
|
{
|
|
SetupBloomRenderGraph(renderGraph, builder, passData, frameContext);
|
|
}
|
|
|
|
// Create temporary texture for uber pass
|
|
passData.tempTexture = renderGraph.CreateTexture(passData.descriptor);
|
|
builder.UseTexture(passData.tempTexture,AccessFlags.ReadWrite);
|
|
|
|
builder.AllowPassCulling(false);
|
|
builder.AllowGlobalStateModification(true);
|
|
|
|
// Set render function
|
|
builder.SetRenderFunc((NiloToonUberPassData data, UnsafeGraphContext context) =>
|
|
{
|
|
ExecuteRenderGraph(data, context);
|
|
});
|
|
}
|
|
}
|
|
|
|
private void SetupBloomRenderGraph(RenderGraph renderGraph, IUnsafeRenderGraphBuilder builder, NiloToonUberPassData passData, ContextContainer frameData)
|
|
{
|
|
// Calculate bloom dimensions
|
|
int th, tw;
|
|
if (m_Bloom.renderTextureOverridedToFixedHeight.overrideState)
|
|
{
|
|
th = m_Bloom.renderTextureOverridedToFixedHeight.value;
|
|
tw = (int)Mathf.Min(SystemInfo.maxTextureSize, th * ((float)passData.descriptor.width / (float)passData.descriptor.height));
|
|
}
|
|
else
|
|
{
|
|
tw = passData.descriptor.width >> 1;
|
|
th = passData.descriptor.height >> 1;
|
|
}
|
|
|
|
// Determine the iteration count
|
|
int maxSize = Mathf.Max(tw, th);
|
|
int iterations = Mathf.FloorToInt(Mathf.Log(maxSize, 2f) - 1);
|
|
int mipCount = Mathf.Clamp(iterations, 1, m_Bloom.maxIterations.value);
|
|
|
|
passData.bloomMipCount = mipCount;
|
|
passData.bloomMipDown = new TextureHandle[mipCount];
|
|
passData.bloomMipUp = new TextureHandle[mipCount];
|
|
|
|
// Create bloom texture descriptors
|
|
var desc = GetCompatibleDescriptor(tw, th, m_DefaultHDRFormat);
|
|
|
|
for (int i = 0; i < mipCount; i++)
|
|
{
|
|
// Create down and up sample textures
|
|
passData.bloomMipDown[i] = builder.CreateTransientTexture(new TextureDesc(desc.width, desc.height)
|
|
{
|
|
colorFormat = desc.graphicsFormat,
|
|
filterMode = FilterMode.Bilinear,
|
|
wrapMode = TextureWrapMode.Clamp,
|
|
name = $"_NiloToonBloomMipDown{i}"
|
|
});
|
|
|
|
passData.bloomMipUp[i] = builder.CreateTransientTexture(new TextureDesc(desc.width, desc.height)
|
|
{
|
|
colorFormat = desc.graphicsFormat,
|
|
filterMode = FilterMode.Bilinear,
|
|
wrapMode = TextureWrapMode.Clamp,
|
|
name = $"_NiloToonBloomMipUp{i}"
|
|
});
|
|
|
|
desc.width = Mathf.Max(1, desc.width >> 1);
|
|
desc.height = Mathf.Max(1, desc.height >> 1);
|
|
}
|
|
}
|
|
|
|
private void ExecuteRenderGraph(NiloToonUberPassData data, UnsafeGraphContext context)
|
|
{
|
|
var cmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
|
|
|
|
// Setup projection matrix
|
|
cmd.SetGlobalMatrix(ShaderConstants._FullscreenProjMat, GL.GetGPUProjectionMatrix(Matrix4x4.identity, true));
|
|
|
|
//using (new ProfilingScope(cmd, niloToonUberProfileSampler))
|
|
{
|
|
// Reset uber keywords
|
|
data.materials.uber.shaderKeywords = null;
|
|
|
|
// Setup bloom if active
|
|
if (data.bloomActive)
|
|
{
|
|
//using (new ProfilingScope(cmd, niloToonBloomProfileSampler))
|
|
{
|
|
SetupBloomRenderGraph(cmd, data);
|
|
}
|
|
}
|
|
|
|
// Setup color grading (always run)
|
|
SetupColorGradingRenderGraph(cmd, data);
|
|
|
|
// Execute uber pass if needed
|
|
if (data.bloomActive || data.tonemappingActive)
|
|
{
|
|
// 1. Copy camera color to temp texture
|
|
Blitter.BlitCameraTexture(cmd, data.cameraColorTexture, data.tempTexture,
|
|
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, data.materials.blit, 0);
|
|
|
|
// 2. Apply uber effects from temp to output
|
|
Blitter.BlitCameraTexture(cmd, data.tempTexture, data.outputTexture,
|
|
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, data.materials.uber, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SetupBloomRenderGraph(CommandBuffer cmd, NiloToonUberPassData data)
|
|
{
|
|
// Pre-filtering parameters
|
|
float clamp = data.bloom.clamp.value;
|
|
float threshold = Mathf.GammaToLinearSpace(data.bloom.threshold.value);
|
|
float thresholdKnee = threshold * 0.5f;
|
|
|
|
// Material setup
|
|
float scatter = Mathf.Lerp(0.05f, 0.95f, data.bloom.scatter.value);
|
|
var bloomMaterial = data.materials.bloom;
|
|
bloomMaterial.SetVector(ShaderConstants._Params, new Vector4(scatter, clamp, threshold, thresholdKnee));
|
|
CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.BloomHQ, data.bloom.highQualityFiltering.value);
|
|
|
|
// NiloToon specific bloom parameters
|
|
float finalThreshold = Mathf.GammaToLinearSpace(data.bloom.characterAreaOverridedThreshold.overrideState ?
|
|
data.bloom.characterAreaOverridedThreshold.value : data.bloom.threshold.value);
|
|
float finalThresholdKnee = finalThreshold * 0.5f;
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaThreshold", finalThreshold);
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaThresholdKnee", finalThresholdKnee);
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaBloomEmitMultiplier", data.bloom.characterAreaBloomEmitMultiplier.value);
|
|
|
|
Vector4 HSV_applyToCharAreaOnly = new Vector4(
|
|
data.bloom.HueOffset.value,
|
|
data.bloom.SaturationBoost.value,
|
|
data.bloom.ValueMultiply.value,
|
|
data.bloom.ApplyHSVToCharAreaOnly.value
|
|
);
|
|
bloomMaterial.SetVector("_NiloToonBloomHSVModifier", HSV_applyToCharAreaOnly);
|
|
|
|
// Prefilter
|
|
Blitter.BlitCameraTexture(cmd, data.cameraColorTexture, data.bloomMipDown[0],
|
|
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 0);
|
|
|
|
// Downsample - gaussian pyramid
|
|
var lastDown = data.bloomMipDown[0];
|
|
for (int i = 1; i < data.bloomMipCount; i++)
|
|
{
|
|
Blitter.BlitCameraTexture(cmd, lastDown, data.bloomMipUp[i],
|
|
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 1);
|
|
Blitter.BlitCameraTexture(cmd, data.bloomMipUp[i], data.bloomMipDown[i],
|
|
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 2);
|
|
lastDown = data.bloomMipDown[i];
|
|
}
|
|
|
|
// Upsample
|
|
for (int i = data.bloomMipCount - 2; i >= 0; i--)
|
|
{
|
|
var lowMip = (i == data.bloomMipCount - 2) ? data.bloomMipDown[i + 1] : data.bloomMipUp[i + 1];
|
|
var highMip = data.bloomMipDown[i];
|
|
var dst = data.bloomMipUp[i];
|
|
|
|
cmd.SetGlobalTexture(ShaderConstants._SourceTexLowMip, lowMip);
|
|
Blitter.BlitCameraTexture(cmd, highMip, dst,
|
|
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 3);
|
|
}
|
|
|
|
// Setup bloom on uber material
|
|
var tint = data.bloom.tint.value.linear;
|
|
var luma = ColorUtils.Luminance(tint);
|
|
tint = luma > 0f ? tint * (1f / luma) : Color.white;
|
|
|
|
var bloomParams = new Vector4(data.bloom.intensity.value, tint.r, tint.g, tint.b);
|
|
data.materials.uber.SetVector(ShaderConstants._Bloom_Params, bloomParams);
|
|
data.materials.uber.SetFloat(ShaderConstants._Bloom_RGBM, data.useRGBM ? 1f : 0f);
|
|
data.materials.uber.SetFloat("_NiloToonBloomCharacterAreaIntensity",
|
|
data.bloom.characterAreaOverridedIntensity.overrideState ?
|
|
data.bloom.characterAreaOverridedIntensity.value : data.bloom.intensity.value);
|
|
|
|
cmd.SetGlobalTexture(ShaderConstants._Bloom_Texture, data.bloomMipUp[0]);
|
|
|
|
// Setup lens dirt
|
|
var dirtTexture = data.bloom.dirtTexture.value == null ? Texture2D.blackTexture : data.bloom.dirtTexture.value;
|
|
float dirtRatio = dirtTexture.width / (float)dirtTexture.height;
|
|
float screenRatio = data.descriptor.width / (float)data.descriptor.height;
|
|
var dirtScaleOffset = new Vector4(1f, 1f, 0f, 0f);
|
|
float dirtIntensity = data.bloom.dirtIntensity.value;
|
|
|
|
if (dirtRatio > screenRatio)
|
|
{
|
|
dirtScaleOffset.x = screenRatio / dirtRatio;
|
|
dirtScaleOffset.z = (1f - dirtScaleOffset.x) * 0.5f;
|
|
}
|
|
else if (screenRatio > dirtRatio)
|
|
{
|
|
dirtScaleOffset.y = dirtRatio / screenRatio;
|
|
dirtScaleOffset.w = (1f - dirtScaleOffset.y) * 0.5f;
|
|
}
|
|
|
|
data.materials.uber.SetVector(ShaderConstants._LensDirt_Params, dirtScaleOffset);
|
|
data.materials.uber.SetFloat(ShaderConstants._LensDirt_Intensity, dirtIntensity);
|
|
data.materials.uber.SetTexture(ShaderConstants._LensDirt_Texture, dirtTexture);
|
|
|
|
// Keywords
|
|
if (data.bloom.highQualityFiltering.value)
|
|
data.materials.uber.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomHQDirt : ShaderKeywordStrings.BloomHQ);
|
|
else
|
|
data.materials.uber.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomLQDirt : ShaderKeywordStrings.BloomLQ);
|
|
}
|
|
|
|
private void SetupColorGradingRenderGraph(CommandBuffer cmd, NiloToonUberPassData data)
|
|
{
|
|
// Use default LUT values since we don't have access to full post-processing data in RG
|
|
int lutHeight = 32; // Default LUT size
|
|
int lutWidth = lutHeight * lutHeight;
|
|
|
|
float postExposureLinear = Mathf.Pow(2f, data.colorAdjustments.postExposure.value);
|
|
data.materials.uber.SetVector(ShaderConstants._Lut_Params, new Vector4(1f / lutWidth, 1f / lutHeight, lutHeight - 1f, postExposureLinear));
|
|
data.materials.uber.SetTexture(ShaderConstants._UserLut, data.colorLookup.texture.value);
|
|
data.materials.uber.SetVector(ShaderConstants._UserLut_Params, !data.colorLookup.IsActive()
|
|
? Vector4.zero
|
|
: new Vector4(1f / data.colorLookup.texture.value.width,
|
|
1f / data.colorLookup.texture.value.height,
|
|
data.colorLookup.texture.value.height - 1f,
|
|
data.colorLookup.contribution.value)
|
|
);
|
|
|
|
// Setup tonemapping
|
|
switch (data.tonemapping.mode.value)
|
|
{
|
|
case TonemappingMode.Neutral: data.materials.uber.EnableKeyword(ShaderKeywordStrings.TonemapNeutral); break;
|
|
case TonemappingMode.ACES: data.materials.uber.EnableKeyword(ShaderKeywordStrings.TonemapACES); break;
|
|
case TonemappingMode.GT:
|
|
data.materials.uber.EnableKeyword("_TONEMAP_GRANTURISMO");
|
|
break;
|
|
case TonemappingMode.ACES_CustomSR:
|
|
data.materials.uber.EnableKeyword("_TONEMAP_ACES_CUSTOM");
|
|
data.materials.uber.SetFloat("_NiloToon_CustomACESParamA", 2.8f);
|
|
data.materials.uber.SetFloat("_NiloToon_CustomACESParamB", 0.4f);
|
|
data.materials.uber.SetFloat("_NiloToon_CustomACESParamC", 2.1f);
|
|
data.materials.uber.SetFloat("_NiloToon_CustomACESParamD", 0.5f);
|
|
data.materials.uber.SetFloat("_NiloToon_CustomACESParamE", 1.5f);
|
|
break;
|
|
case TonemappingMode.KhronosPBRNeutral:
|
|
data.materials.uber.EnableKeyword("_TONEMAP_KHRONOS_PBR_NEUTRAL");
|
|
break;
|
|
case TonemappingMode.NiloNPRNeutralV1:
|
|
data.materials.uber.EnableKeyword("_TONEMAP_NILO_NPR_NEUTRAL_V1");
|
|
break;
|
|
case TonemappingMode.NiloHybirdACES:
|
|
data.materials.uber.EnableKeyword("_TONEMAP_NILO_HYBIRD_ACES");
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
// NiloToon specific parameters
|
|
data.materials.uber.SetFloat("_NiloToonTonemappingCharacterAreaRemove",
|
|
1 - data.tonemapping.ApplyToCharacter.value * data.tonemapping.intensity.value);
|
|
data.materials.uber.SetFloat("_NiloToonTonemappingCharacterAreaPreTonemapBrightnessMul",
|
|
data.tonemapping.BrightnessMulForCharacter.value * data.bloom.characterPreTonemapBrightness.value);
|
|
data.materials.uber.SetFloat("_NiloToonTonemappingNonCharacterAreaRemove",
|
|
1 - data.tonemapping.ApplyToNonCharacter.value * data.tonemapping.intensity.value);
|
|
data.materials.uber.SetFloat("_NiloToonTonemappingNonCharacterAreaPreTonemapBrightnessMul",
|
|
data.tonemapping.BrightnessMulForNonCharacter.value);
|
|
}
|
|
|
|
// RG Pass Data
|
|
private class NiloToonUberPassData
|
|
{
|
|
public MaterialLibrary materials;
|
|
public NiloToonBloomVolume bloom;
|
|
public ColorLookup colorLookup;
|
|
public ColorAdjustments colorAdjustments;
|
|
public NiloToonTonemappingVolume tonemapping;
|
|
public TextureDesc descriptor;
|
|
public GraphicsFormat defaultHDRFormat;
|
|
public bool useRGBM;
|
|
public bool bloomActive;
|
|
public bool tonemappingActive;
|
|
|
|
public TextureHandle cameraColorTexture;
|
|
public TextureHandle outputTexture;
|
|
public TextureHandle tempTexture;
|
|
|
|
// Bloom specific
|
|
public int bloomMipCount;
|
|
public TextureHandle[] bloomMipDown;
|
|
public TextureHandle[] bloomMipUp;
|
|
}
|
|
#endif
|
|
|
|
class MaterialLibrary
|
|
{
|
|
public readonly Material bloom;
|
|
public readonly Material uber;
|
|
public readonly Material blit;
|
|
|
|
// NiloToon edited, instead of receiving a PostProcessData class, we pass 2 Shaders directly
|
|
public MaterialLibrary(Shader bloomShader, Shader uberShader, Shader blitShader)
|
|
{
|
|
bloom = Load(bloomShader);
|
|
uber = Load(uberShader);
|
|
blit = Load(blitShader);
|
|
}
|
|
|
|
Material Load(Shader shader)
|
|
{
|
|
if (shader == null)
|
|
{
|
|
//Debug.LogErrorFormat($"Missing shader. {GetType().DeclaringType.Name} render pass will not execute. Check for missing reference in the renderer resources."); // NiloToonURP: removed
|
|
return null;
|
|
}
|
|
else if (!shader.isSupported)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return CoreUtils.CreateEngineMaterial(shader);
|
|
}
|
|
|
|
internal void Cleanup()
|
|
{
|
|
CoreUtils.Destroy(bloom);
|
|
CoreUtils.Destroy(uber);
|
|
CoreUtils.Destroy(blit);
|
|
}
|
|
}
|
|
|
|
// Precomputed shader ids to same some CPU cycles (mostly affects mobile)
|
|
static class ShaderConstants
|
|
{
|
|
public static readonly int _TempTarget = Shader.PropertyToID("_TempTarget");
|
|
public static readonly int _TempTarget2 = Shader.PropertyToID("_TempTarget2");
|
|
|
|
public static readonly int _StencilRef = Shader.PropertyToID("_StencilRef");
|
|
public static readonly int _StencilMask = Shader.PropertyToID("_StencilMask");
|
|
|
|
public static readonly int _FullCoCTexture = Shader.PropertyToID("_FullCoCTexture");
|
|
public static readonly int _HalfCoCTexture = Shader.PropertyToID("_HalfCoCTexture");
|
|
public static readonly int _DofTexture = Shader.PropertyToID("_DofTexture");
|
|
public static readonly int _CoCParams = Shader.PropertyToID("_CoCParams");
|
|
public static readonly int _BokehKernel = Shader.PropertyToID("_BokehKernel");
|
|
public static readonly int _BokehConstants = Shader.PropertyToID("_BokehConstants");
|
|
public static readonly int _PongTexture = Shader.PropertyToID("_PongTexture");
|
|
public static readonly int _PingTexture = Shader.PropertyToID("_PingTexture");
|
|
|
|
public static readonly int _Metrics = Shader.PropertyToID("_Metrics");
|
|
public static readonly int _AreaTexture = Shader.PropertyToID("_AreaTexture");
|
|
public static readonly int _SearchTexture = Shader.PropertyToID("_SearchTexture");
|
|
public static readonly int _EdgeTexture = Shader.PropertyToID("_EdgeTexture");
|
|
public static readonly int _BlendTexture = Shader.PropertyToID("_BlendTexture");
|
|
|
|
public static readonly int _ColorTexture = Shader.PropertyToID("_ColorTexture");
|
|
public static readonly int _Params = Shader.PropertyToID("_Params");
|
|
public static readonly int _SourceTexLowMip = Shader.PropertyToID("_SourceTexLowMip");
|
|
public static readonly int _Bloom_Params = Shader.PropertyToID("_Bloom_Params");
|
|
public static readonly int _Bloom_RGBM = Shader.PropertyToID("_Bloom_RGBM");
|
|
public static readonly int _Bloom_Texture = Shader.PropertyToID("_Bloom_Texture");
|
|
public static readonly int _LensDirt_Texture = Shader.PropertyToID("_LensDirt_Texture");
|
|
public static readonly int _LensDirt_Params = Shader.PropertyToID("_LensDirt_Params");
|
|
public static readonly int _LensDirt_Intensity = Shader.PropertyToID("_LensDirt_Intensity");
|
|
public static readonly int _Distortion_Params1 = Shader.PropertyToID("_Distortion_Params1");
|
|
public static readonly int _Distortion_Params2 = Shader.PropertyToID("_Distortion_Params2");
|
|
public static readonly int _Chroma_Params = Shader.PropertyToID("_Chroma_Params");
|
|
public static readonly int _Vignette_Params1 = Shader.PropertyToID("_Vignette_Params1");
|
|
public static readonly int _Vignette_Params2 = Shader.PropertyToID("_Vignette_Params2");
|
|
public static readonly int _Vignette_ParamsXR = Shader.PropertyToID("_Vignette_ParamsXR");
|
|
public static readonly int _Lut_Params = Shader.PropertyToID("_Lut_Params");
|
|
public static readonly int _UserLut_Params = Shader.PropertyToID("_UserLut_Params");
|
|
public static readonly int _InternalLut = Shader.PropertyToID("_InternalLut");
|
|
public static readonly int _UserLut = Shader.PropertyToID("_UserLut");
|
|
public static readonly int _DownSampleScaleFactor = Shader.PropertyToID("_DownSampleScaleFactor");
|
|
|
|
public static readonly int _FlareOcclusionRemapTex = Shader.PropertyToID("_FlareOcclusionRemapTex");
|
|
public static readonly int _FlareOcclusionTex = Shader.PropertyToID("_FlareOcclusionTex");
|
|
public static readonly int _FlareOcclusionIndex = Shader.PropertyToID("_FlareOcclusionIndex");
|
|
public static readonly int _FlareTex = Shader.PropertyToID("_FlareTex");
|
|
public static readonly int _FlareColorValue = Shader.PropertyToID("_FlareColorValue");
|
|
public static readonly int _FlareData0 = Shader.PropertyToID("_FlareData0");
|
|
public static readonly int _FlareData1 = Shader.PropertyToID("_FlareData1");
|
|
public static readonly int _FlareData2 = Shader.PropertyToID("_FlareData2");
|
|
public static readonly int _FlareData3 = Shader.PropertyToID("_FlareData3");
|
|
public static readonly int _FlareData4 = Shader.PropertyToID("_FlareData4");
|
|
public static readonly int _FlareData5 = Shader.PropertyToID("_FlareData5");
|
|
|
|
public static readonly int _FullscreenProjMat = Shader.PropertyToID("_FullscreenProjMat");
|
|
|
|
public static int[] _BloomMipUp;
|
|
public static int[] _BloomMipDown;
|
|
}
|
|
}
|
|
#else
|
|
|
|
public class NiloToonUberPostProcessPass : ScriptableRenderPass
|
|
{
|
|
#region Singleton
|
|
public static NiloToonUberPostProcessPass Instance
|
|
{
|
|
get => _instance;
|
|
}
|
|
static NiloToonUberPostProcessPass _instance;
|
|
#endregion
|
|
|
|
[Serializable]
|
|
public class Settings
|
|
{
|
|
[Header("Render Timing")]
|
|
[Tooltip("The default value is BeforeRenderingPostProcess + 0, you can edit it to make NiloToon work with other renderer features")]
|
|
[OverrideDisplayName("Renderer Feature Order Offset")]
|
|
[Revertible]
|
|
public int renderPassEventTimingOffset = 0;
|
|
|
|
[Header("Bloom")]
|
|
[Tooltip("Can turn off to prevent rendering NiloToonBloomVolume, which will improve performance for low quality graphics setting renderer")]
|
|
[OverrideDisplayName("Allow render Bloom?")]
|
|
[Revertible]
|
|
public bool allowRenderNiloToonBloom = true;
|
|
}
|
|
public Settings settings { get; }
|
|
|
|
NiloToonRendererFeatureSettings allSettings;
|
|
|
|
ProfilingSampler niloToonBloomProfileSampler;
|
|
ProfilingSampler niloToonUberProfileSampler;
|
|
#region [Copy and edited, from URP10.5.0's PostProcessPass.cs's fields]
|
|
const string k_RenderPostProcessingTag = "Render NiloToon PostProcessing Effects"; // edited string value, original is "Render PostProcessing Effects"
|
|
NiloToonBloomVolume m_Bloom; // edited type, original is Bloom
|
|
ColorLookup m_ColorLookup;
|
|
ColorAdjustments m_ColorAdjustments;
|
|
NiloToonTonemappingVolume m_Tonemapping; // edited type, original is Tonemapping
|
|
#endregion
|
|
|
|
#region [Direct copy and NO edit, from URP10.5.0's PostProcessPass.cs's fields]
|
|
RenderTextureDescriptor m_Descriptor;
|
|
RenderTargetHandle m_Source;
|
|
|
|
private static readonly ProfilingSampler m_ProfilingRenderPostProcessing = new ProfilingSampler(k_RenderPostProcessingTag);
|
|
|
|
MaterialLibrary m_Materials;
|
|
|
|
// Misc
|
|
const int k_MaxPyramidSize = 16;
|
|
readonly GraphicsFormat m_DefaultHDRFormat;
|
|
bool m_UseRGBM;
|
|
|
|
// Option to use procedural draw instead of cmd.blit
|
|
bool m_UseDrawProcedural;
|
|
#endregion
|
|
|
|
public NiloToonUberPostProcessPass(NiloToonRendererFeatureSettings allSettings)
|
|
{
|
|
this.allSettings = allSettings;
|
|
settings = allSettings.uberPostProcessSettings;
|
|
_instance = this;
|
|
|
|
niloToonBloomProfileSampler = new ProfilingSampler("NiloToonBloomProfileSampler");
|
|
niloToonUberProfileSampler = new ProfilingSampler("NiloToonUberProfileSampler");
|
|
|
|
Shader bloomShader = Shader.Find("Hidden/Universal Render Pipeline/NiloToonBloom");
|
|
Shader uberShader = Shader.Find("Hidden/Universal Render Pipeline/NiloToonUberPost");
|
|
Shader blitShader = Shader.Find("Hidden/Universal Render Pipeline/Blit");
|
|
|
|
#region [Copy and edited, from URP10.5.0's PostProcessPass.cs's constructor PostProcessPass(...)]
|
|
base.profilingSampler = new ProfilingSampler(nameof(NiloToonUberPostProcessPass)); // edited type, original is PostProcessPass
|
|
m_Materials = new MaterialLibrary(bloomShader, uberShader, blitShader); // edited input param, original is a PostProcessData class instance
|
|
#endregion
|
|
|
|
#region [Copy and remove unneeded, keep bloom only, from URP10.5.0's PostProcessPass.cs's constructor PostProcessPass(...)]
|
|
// Texture format pre-lookup
|
|
if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, FormatUsage.Linear | FormatUsage.Render))
|
|
{
|
|
m_DefaultHDRFormat = GraphicsFormat.B10G11R11_UFloatPack32;
|
|
m_UseRGBM = false;
|
|
}
|
|
else
|
|
{
|
|
m_DefaultHDRFormat = QualitySettings.activeColorSpace == ColorSpace.Linear
|
|
? GraphicsFormat.R8G8B8A8_SRGB
|
|
: GraphicsFormat.R8G8B8A8_UNorm;
|
|
m_UseRGBM = true;
|
|
}
|
|
|
|
// Bloom pyramid shader ids - can't use a simple stackalloc in the bloom function as we
|
|
// unfortunately need to allocate strings
|
|
ShaderConstants._BloomMipUp = new int[k_MaxPyramidSize];
|
|
ShaderConstants._BloomMipDown = new int[k_MaxPyramidSize];
|
|
#endregion
|
|
|
|
#region [Copy and edited, from URP10.5.0's PostProcessPass.cs's constructor PostProcessPass(...)]
|
|
for (int i = 0; i < k_MaxPyramidSize; i++)
|
|
{
|
|
ShaderConstants._BloomMipUp[i] = Shader.PropertyToID("_NiloToonBloomMipUp" + i); // edited string name, original is _BloomMipUp
|
|
ShaderConstants._BloomMipDown[i] = Shader.PropertyToID("_NiloToonBloomMipDown" + i); // edited string name, original is _BloomMipDown
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
#region [Copy and edited, from URP10.5.0's PostProcessPass.cs's Setup(...)]
|
|
public void Setup(in RenderTextureDescriptor baseDescriptor, in RenderTargetHandle source)
|
|
{
|
|
m_Descriptor = baseDescriptor;
|
|
m_Descriptor.useMipMap = false;
|
|
m_Descriptor.autoGenerateMips = false;
|
|
m_Source = source;
|
|
|
|
// NiloToonURP removed
|
|
/*
|
|
m_Destination = destination;
|
|
m_Depth = depth;
|
|
m_InternalLut = internalLut;
|
|
m_IsFinalPass = false;
|
|
m_HasFinalPass = hasFinalPass;
|
|
m_EnableSRGBConversionIfNeeded = enableSRGBConversion;
|
|
*/
|
|
}
|
|
#endregion
|
|
|
|
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
// [NiloToon added]
|
|
// re-init m_Materials if needed, usually m_Materials's materials are null on project's first-time startup (right after rebuild library folder)
|
|
if (m_Materials == null ||
|
|
m_Materials.blit == null ||
|
|
m_Materials.bloom == null ||
|
|
m_Materials.uber == null)
|
|
{
|
|
Shader bloomShader = Shader.Find("Hidden/Universal Render Pipeline/NiloToonBloom");
|
|
Shader uberShader = Shader.Find("Hidden/Universal Render Pipeline/NiloToonUberPost");
|
|
Shader blitShader = Shader.Find("Hidden/Universal Render Pipeline/Blit");
|
|
m_Materials = new MaterialLibrary(bloomShader, uberShader, blitShader);
|
|
}
|
|
|
|
#region [Copy and edited, from URP10.5.0's PostProcessPass.cs's Execute(...)]
|
|
// Start by pre-fetching all builtin effect settings we need
|
|
// Some of the color-grading settings are only used in the color grading lut pass
|
|
var stack = VolumeManager.instance.stack;
|
|
m_Bloom = stack.GetComponent<NiloToonBloomVolume>(); // edited type, original is Bloom
|
|
m_ColorLookup = stack.GetComponent<ColorLookup>();
|
|
m_ColorAdjustments = stack.GetComponent<ColorAdjustments>();
|
|
m_Tonemapping = stack.GetComponent<NiloToonTonemappingVolume>(); // edited type, original is Tonemapping
|
|
|
|
m_UseDrawProcedural = renderingData.cameraData.xrRendering; // edited, original is renderingData.cameraData.xr
|
|
m_UseDrawProcedural = false; // TEMP disabled to make Blit() works
|
|
#endregion
|
|
|
|
#region [Direct copy and no edit, from URP10.5.0's PostProcessPass.cs's Execute(...)]
|
|
|
|
// Regular render path (not on-tile) - we do everything in a single command buffer as it
|
|
// makes it easier to manage temporary targets' lifetime
|
|
var cmd = CommandBufferPool.Get();
|
|
using (new ProfilingScope(cmd, m_ProfilingRenderPostProcessing))
|
|
{
|
|
Render(cmd, ref renderingData);
|
|
}
|
|
|
|
context.ExecuteCommandBuffer(cmd);
|
|
CommandBufferPool.Release(cmd);
|
|
#endregion
|
|
}
|
|
|
|
void Render(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
#region [copy and edited, from URP10.5.0's PostProcessPass.cs's Render()]
|
|
ref var cameraData = ref renderingData.cameraData;
|
|
|
|
int source = m_Source.id;
|
|
|
|
// Utilities to simplify intermediate target management
|
|
int GetSource() => source;
|
|
|
|
// Setup projection matrix for cmd.DrawMesh()
|
|
cmd.SetGlobalMatrix(ShaderConstants._FullscreenProjMat, GL.GetGPUProjectionMatrix(Matrix4x4.identity, true));
|
|
|
|
// Combined post-processing stack
|
|
using (new ProfilingScope(cmd, niloToonUberProfileSampler)) // NiloToon edit: original = ProfilingSampler.Get(URPProfileId.UberPostProcess)
|
|
{
|
|
// Reset uber keywords
|
|
m_Materials.uber.shaderKeywords = null;
|
|
|
|
// Bloom goes first
|
|
bool bloomActive = m_Bloom.IsActive() && settings.allowRenderNiloToonBloom && cameraData.postProcessEnabled; // NiloToon edit: added && allowRenderNiloToonBloom && postProcessEnabled
|
|
if (bloomActive)
|
|
{
|
|
using (new ProfilingScope(cmd, niloToonBloomProfileSampler)) // NiloToon edit: ProfilingSampler.Get(URPProfileId.Bloom)
|
|
SetupBloom(cmd, GetSource(), m_Materials.uber);
|
|
}
|
|
|
|
// Setup other effects constants
|
|
bool tonemappingActive = m_Tonemapping.IsActive() && cameraData.postProcessEnabled;
|
|
|
|
// no need if check, always run
|
|
{
|
|
SetupColorGrading(cmd, ref renderingData, m_Materials.uber);
|
|
}
|
|
|
|
bool uberNeeded = bloomActive || tonemappingActive;
|
|
if (uberNeeded)
|
|
{
|
|
// 1.Blit direct copy _CameraColorTexture to _NiloToonUberTempRT
|
|
RenderTextureDescriptor rtdTempRT = renderingData.cameraData.cameraTargetDescriptor;
|
|
rtdTempRT.msaaSamples = 1; // no need MSAA for just a blit
|
|
cmd.GetTemporaryRT(Shader.PropertyToID("_NiloToonUberTempRT"), rtdTempRT, FilterMode.Point);
|
|
Blit(cmd, new RenderTargetIdentifier(GetSource()), new RenderTargetIdentifier("_NiloToonUberTempRT"), m_Materials.blit);
|
|
|
|
// 2.Blit _NiloToonUberTempRT to _CameraColorTexture, do uber postprocess
|
|
Blit(cmd, new RenderTargetIdentifier("_NiloToonUberTempRT"), new RenderTargetIdentifier(GetSource()), m_Materials.uber);
|
|
|
|
// 3.Cleanup
|
|
cmd.ReleaseTemporaryRT(Shader.PropertyToID("_NiloToonUberTempRT"));
|
|
}
|
|
|
|
// 3.Cleanup
|
|
if (bloomActive)
|
|
cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipUp[0]);
|
|
}
|
|
#endregion
|
|
}
|
|
#region [Copy and edited, from URP10.5.0's PostProcessPass.cs's SetupBloom()]
|
|
// (all changes will be marked by a [NiloToon edited] tag)
|
|
// (if there is no [NiloToon edited] tag, then it is a direct copy
|
|
void SetupBloom(CommandBuffer cmd, int source, Material uberMaterial)
|
|
{
|
|
// [NiloToon edited]
|
|
//===========================================================================================================
|
|
// URP's official bloom will have very different bloom result depending on game window size(height), because blur is applied to constant count of pixels(4+1+4).
|
|
// NiloToon's bloom can override to use a fixed size height instead of URP's "Start at half-res", to make all screen resolution's bloom result consistant.
|
|
|
|
int th;
|
|
int tw;
|
|
if (m_Bloom.renderTextureOverridedToFixedHeight.overrideState)
|
|
{
|
|
// NiloToon's bloom code
|
|
th = m_Bloom.renderTextureOverridedToFixedHeight.value;
|
|
tw = (int)Mathf.Min(SystemInfo.maxTextureSize,th * ((float)m_Descriptor.width / (float)m_Descriptor.height));
|
|
}
|
|
else
|
|
{
|
|
// URP's official bloom code
|
|
tw = m_Descriptor.width >> 1;
|
|
th = m_Descriptor.height >> 1;
|
|
}
|
|
//===========================================================================================================
|
|
|
|
// Determine the iteration count
|
|
int maxSize = Mathf.Max(tw, th);
|
|
int iterations = Mathf.FloorToInt(Mathf.Log(maxSize, 2f) - 1);
|
|
iterations -= m_Bloom.skipIterations.value;
|
|
int mipCount = Mathf.Clamp(iterations, 1, k_MaxPyramidSize);
|
|
|
|
// Pre-filtering parameters
|
|
float clamp = m_Bloom.clamp.value;
|
|
float threshold = Mathf.GammaToLinearSpace(m_Bloom.threshold.value);
|
|
float thresholdKnee = threshold * 0.5f; // Hardcoded soft knee
|
|
|
|
// Material setup
|
|
float scatter = Mathf.Lerp(0.05f, 0.95f, m_Bloom.scatter.value);
|
|
var bloomMaterial = m_Materials.bloom;
|
|
bloomMaterial.SetVector(ShaderConstants._Params, new Vector4(scatter, clamp, threshold, thresholdKnee));
|
|
CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.BloomHQ, m_Bloom.highQualityFiltering.value);
|
|
CoreUtils.SetKeyword(bloomMaterial, ShaderKeywordStrings.UseRGBM, m_UseRGBM);
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
// if not overridden, use generic threshold.
|
|
// if overridden, use characterAreaOverridedThreshold.
|
|
float finalThreshold = Mathf.GammaToLinearSpace(m_Bloom.characterAreaOverridedThreshold.overrideState ? m_Bloom.characterAreaOverridedThreshold.value : m_Bloom.threshold.value);
|
|
float finalThresholdKnee = finalThreshold * 0.5f; // Hardcoded soft knee
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaThreshold", finalThreshold);
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaThresholdKnee", finalThresholdKnee);
|
|
|
|
bloomMaterial.SetFloat("_NiloToonBloomCharacterAreaBloomEmitMultiplier", m_Bloom.characterAreaBloomEmitMultiplier.value);
|
|
|
|
Vector4 HSV_applyToCharAreaOnly;
|
|
HSV_applyToCharAreaOnly.x = m_Bloom.HueOffset.value;
|
|
HSV_applyToCharAreaOnly.y = m_Bloom.SaturationBoost.value;
|
|
HSV_applyToCharAreaOnly.z = m_Bloom.ValueMultiply.value;
|
|
HSV_applyToCharAreaOnly.w = m_Bloom.ApplyHSVToCharAreaOnly.value;
|
|
bloomMaterial.SetVector("_NiloToonBloomHSVModifier", HSV_applyToCharAreaOnly);
|
|
//====================================================================================
|
|
|
|
// Prefilter
|
|
var desc = GetCompatibleDescriptor(tw, th, m_DefaultHDRFormat);
|
|
cmd.GetTemporaryRT(ShaderConstants._BloomMipDown[0], desc, FilterMode.Bilinear);
|
|
cmd.GetTemporaryRT(ShaderConstants._BloomMipUp[0], desc, FilterMode.Bilinear);
|
|
Blit(cmd, source, ShaderConstants._BloomMipDown[0], bloomMaterial, 0);
|
|
|
|
// Downsample - gaussian pyramid
|
|
int lastDown = ShaderConstants._BloomMipDown[0];
|
|
for (int i = 1; i < mipCount; i++)
|
|
{
|
|
tw = Mathf.Max(1, tw >> 1);
|
|
th = Mathf.Max(1, th >> 1);
|
|
int mipDown = ShaderConstants._BloomMipDown[i];
|
|
int mipUp = ShaderConstants._BloomMipUp[i];
|
|
|
|
desc.width = tw;
|
|
desc.height = th;
|
|
|
|
cmd.GetTemporaryRT(mipDown, desc, FilterMode.Bilinear);
|
|
cmd.GetTemporaryRT(mipUp, desc, FilterMode.Bilinear);
|
|
|
|
// Classic two pass gaussian blur - use mipUp as a temporary target
|
|
// First pass does 2x downsampling + 9-tap gaussian
|
|
// Second pass does 9-tap gaussian using a 5-tap filter + bilinear filtering
|
|
Blit(cmd, lastDown, mipUp, bloomMaterial, 1);
|
|
Blit(cmd, mipUp, mipDown, bloomMaterial, 2);
|
|
|
|
lastDown = mipDown;
|
|
}
|
|
|
|
// Upsample (bilinear by default, HQ filtering does bicubic instead
|
|
for (int i = mipCount - 2; i >= 0; i--)
|
|
{
|
|
int lowMip = (i == mipCount - 2) ? ShaderConstants._BloomMipDown[i + 1] : ShaderConstants._BloomMipUp[i + 1];
|
|
int highMip = ShaderConstants._BloomMipDown[i];
|
|
int dst = ShaderConstants._BloomMipUp[i];
|
|
|
|
cmd.SetGlobalTexture(ShaderConstants._SourceTexLowMip, lowMip);
|
|
Blit(cmd, highMip, BlitDstDiscardContent(cmd, dst), bloomMaterial, 3);
|
|
}
|
|
|
|
// Cleanup
|
|
for (int i = 0; i < mipCount; i++)
|
|
{
|
|
cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipDown[i]);
|
|
if (i > 0) cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipUp[i]);
|
|
}
|
|
|
|
// Setup bloom on uber
|
|
var tint = m_Bloom.tint.value.linear;
|
|
var luma = ColorUtils.Luminance(tint);
|
|
tint = luma > 0f ? tint * (1f / luma) : Color.white;
|
|
|
|
var bloomParams = new Vector4(m_Bloom.intensity.value, tint.r, tint.g, tint.b);
|
|
uberMaterial.SetVector(ShaderConstants._Bloom_Params, bloomParams);
|
|
uberMaterial.SetFloat(ShaderConstants._Bloom_RGBM, m_UseRGBM ? 1f : 0f);
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
// if not overridden, use generic intensity.
|
|
// if overridden, use characterAreaOverridedIntensity.
|
|
uberMaterial.SetFloat("_NiloToonBloomCharacterAreaIntensity", m_Bloom.characterAreaOverridedIntensity.overrideState ? m_Bloom.characterAreaOverridedIntensity.value : m_Bloom.intensity.value);
|
|
//====================================================================================
|
|
|
|
cmd.SetGlobalTexture(ShaderConstants._Bloom_Texture, ShaderConstants._BloomMipUp[0]);
|
|
|
|
// Setup lens dirtiness on uber
|
|
// Keep the aspect ratio correct & center the dirt texture, we don't want it to be
|
|
// stretched or squashed
|
|
var dirtTexture = m_Bloom.dirtTexture.value == null ? Texture2D.blackTexture : m_Bloom.dirtTexture.value;
|
|
float dirtRatio = dirtTexture.width / (float)dirtTexture.height;
|
|
float screenRatio = m_Descriptor.width / (float)m_Descriptor.height;
|
|
var dirtScaleOffset = new Vector4(1f, 1f, 0f, 0f);
|
|
float dirtIntensity = m_Bloom.dirtIntensity.value;
|
|
|
|
if (dirtRatio > screenRatio)
|
|
{
|
|
dirtScaleOffset.x = screenRatio / dirtRatio;
|
|
dirtScaleOffset.z = (1f - dirtScaleOffset.x) * 0.5f;
|
|
}
|
|
else if (screenRatio > dirtRatio)
|
|
{
|
|
dirtScaleOffset.y = dirtRatio / screenRatio;
|
|
dirtScaleOffset.w = (1f - dirtScaleOffset.y) * 0.5f;
|
|
}
|
|
|
|
uberMaterial.SetVector(ShaderConstants._LensDirt_Params, dirtScaleOffset);
|
|
uberMaterial.SetFloat(ShaderConstants._LensDirt_Intensity, dirtIntensity);
|
|
uberMaterial.SetTexture(ShaderConstants._LensDirt_Texture, dirtTexture);
|
|
|
|
// Keyword setup - a bit convoluted as we're trying to save some variants in Uber...
|
|
if (m_Bloom.highQualityFiltering.value)
|
|
uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomHQDirt : ShaderKeywordStrings.BloomHQ);
|
|
else
|
|
uberMaterial.EnableKeyword(dirtIntensity > 0f ? ShaderKeywordStrings.BloomLQDirt : ShaderKeywordStrings.BloomLQ);
|
|
}
|
|
#endregion
|
|
|
|
#region [Copy and edited, from URP12.1.12's PostProcessPass.cs's SetupColorGrading()]
|
|
void SetupColorGrading(CommandBuffer cmd, ref RenderingData renderingData, Material material)
|
|
{
|
|
ref var postProcessingData = ref renderingData.postProcessingData;
|
|
bool hdr = postProcessingData.gradingMode == ColorGradingMode.HighDynamicRange;
|
|
int lutHeight = postProcessingData.lutSize;
|
|
int lutWidth = lutHeight * lutHeight;
|
|
|
|
// Source material setup
|
|
float postExposureLinear = Mathf.Pow(2f, m_ColorAdjustments.postExposure.value);
|
|
//cmd.SetGlobalTexture(ShaderConstants._InternalLut, m_InternalLut.Identifier()); // [NiloToon edit] temp disabled since we don't have m_InternalLut here
|
|
material.SetVector(ShaderConstants._Lut_Params, new Vector4(1f / lutWidth, 1f / lutHeight, lutHeight - 1f, postExposureLinear));
|
|
material.SetTexture(ShaderConstants._UserLut, m_ColorLookup.texture.value);
|
|
material.SetVector(ShaderConstants._UserLut_Params, !m_ColorLookup.IsActive()
|
|
? Vector4.zero
|
|
: new Vector4(1f / m_ColorLookup.texture.value.width,
|
|
1f / m_ColorLookup.texture.value.height,
|
|
m_ColorLookup.texture.value.height - 1f,
|
|
m_ColorLookup.contribution.value)
|
|
);
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
// NiloToon can't support HDR Grading Mode due to URP's design,
|
|
// so we just enable the same NiloToon tonemapping code for both ldr and hdr Color Grading Mode
|
|
hdr = false;
|
|
//====================================================================================
|
|
|
|
if (hdr)
|
|
{
|
|
material.EnableKeyword(ShaderKeywordStrings.HDRGrading);
|
|
}
|
|
else
|
|
{
|
|
switch (m_Tonemapping.mode.value)
|
|
{
|
|
case TonemappingMode.Neutral: material.EnableKeyword(ShaderKeywordStrings.TonemapNeutral); break;
|
|
case TonemappingMode.ACES: material.EnableKeyword(ShaderKeywordStrings.TonemapACES); break;
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
case TonemappingMode.GT:
|
|
material.EnableKeyword("_TONEMAP_GRANTURISMO");
|
|
break;
|
|
case TonemappingMode.ACES_CustomSR:
|
|
// custom ACES function with ABCDE param from this repo, it has better saturation than other tonemap method
|
|
// https://github.com/stalomeow/StarRailNPRShader/blob/main/Shaders/Postprocessing/UberPost.shader
|
|
material.EnableKeyword("_TONEMAP_ACES_CUSTOM");
|
|
material.SetFloat("_NiloToon_CustomACESParamA", 2.8f);
|
|
material.SetFloat("_NiloToon_CustomACESParamB", 0.4f);
|
|
material.SetFloat("_NiloToon_CustomACESParamC", 2.1f);
|
|
material.SetFloat("_NiloToon_CustomACESParamD", 0.5f);
|
|
material.SetFloat("_NiloToon_CustomACESParamE", 1.5f);
|
|
break;
|
|
case TonemappingMode.KhronosPBRNeutral:
|
|
material.EnableKeyword("_TONEMAP_KHRONOS_PBR_NEUTRAL");
|
|
break;
|
|
case TonemappingMode.NiloNPRNeutralV1:
|
|
material.EnableKeyword("_TONEMAP_NILO_NPR_NEUTRAL_V1");
|
|
break;
|
|
case TonemappingMode.NiloHybirdACES:
|
|
material.EnableKeyword("_TONEMAP_NILO_HYBIRD_ACES");
|
|
break;
|
|
//====================================================================================
|
|
|
|
default: break; // None
|
|
}
|
|
}
|
|
|
|
// [NiloToon added]
|
|
//====================================================================================
|
|
material.SetFloat("_NiloToonTonemappingCharacterAreaRemove", 1 - m_Tonemapping.ApplyToCharacter.value * m_Tonemapping.intensity.value);
|
|
material.SetFloat("_NiloToonTonemappingCharacterAreaPreTonemapBrightnessMul", m_Tonemapping.BrightnessMulForCharacter.value * m_Bloom.characterPreTonemapBrightness.value);
|
|
|
|
material.SetFloat("_NiloToonTonemappingNonCharacterAreaRemove", 1 - m_Tonemapping.ApplyToNonCharacter.value * m_Tonemapping.intensity.value);
|
|
material.SetFloat("_NiloToonTonemappingNonCharacterAreaPreTonemapBrightnessMul", m_Tonemapping.BrightnessMulForNonCharacter.value);
|
|
//====================================================================================
|
|
}
|
|
#endregion
|
|
|
|
#region [Copy and remove unneeded and edited, keep bloom and uber only, add blit, delay material create, from URP10.5.0's PostProcessPass.cs's MaterialLibrary class]
|
|
class MaterialLibrary
|
|
{
|
|
public readonly Material bloom;
|
|
public readonly Material uber;
|
|
public readonly Material blit;
|
|
|
|
// NiloToon edited, instead of receiving a PostProcessData class, we pass 2 Shaders directly
|
|
public MaterialLibrary(Shader bloomShader, Shader uberShader, Shader blitShader)
|
|
{
|
|
bloom = Load(bloomShader);
|
|
uber = Load(uberShader);
|
|
blit = Load(blitShader);
|
|
}
|
|
|
|
Material Load(Shader shader)
|
|
{
|
|
if (shader == null)
|
|
{
|
|
//Debug.LogErrorFormat($"Missing shader. {GetType().DeclaringType.Name} render pass will not execute. Check for missing reference in the renderer resources."); // NiloToonURP: removed
|
|
return null;
|
|
}
|
|
else if (!shader.isSupported)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return CoreUtils.CreateEngineMaterial(shader);
|
|
}
|
|
|
|
internal void Cleanup()
|
|
{
|
|
CoreUtils.Destroy(bloom);
|
|
CoreUtils.Destroy(uber);
|
|
CoreUtils.Destroy(blit);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region [Direct copy and no edit, from URP10.5.0's PostProcessPass.cs]
|
|
RenderTextureDescriptor GetCompatibleDescriptor()
|
|
=> GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_Descriptor.graphicsFormat, m_Descriptor.depthBufferBits);
|
|
|
|
RenderTextureDescriptor GetCompatibleDescriptor(int width, int height, GraphicsFormat format, int depthBufferBits = 0)
|
|
{
|
|
var desc = m_Descriptor;
|
|
desc.depthBufferBits = depthBufferBits;
|
|
desc.msaaSamples = 1;
|
|
desc.width = width;
|
|
desc.height = height;
|
|
desc.graphicsFormat = format;
|
|
return desc;
|
|
}
|
|
|
|
private BuiltinRenderTextureType BlitDstDiscardContent(CommandBuffer cmd, RenderTargetIdentifier rt)
|
|
{
|
|
// We set depth to DontCare because rt might be the source of PostProcessing used as a temporary target
|
|
// Source typically comes with a depth buffer and right now we don't have a way to only bind the color attachment of a RenderTargetIdentifier
|
|
cmd.SetRenderTarget(new RenderTargetIdentifier(rt, 0, CubemapFace.Unknown, -1),
|
|
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
|
|
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
|
|
return BuiltinRenderTextureType.CurrentActive;
|
|
}
|
|
|
|
private new void Blit(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, int passIndex = 0)
|
|
{
|
|
cmd.SetGlobalTexture(ShaderPropertyId.sourceTex, source);
|
|
if (m_UseDrawProcedural)
|
|
{
|
|
Vector4 scaleBias = new Vector4(1, 1, 0, 0);
|
|
cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
|
|
|
|
cmd.SetRenderTarget(new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1),
|
|
RenderBufferLoadAction.Load, RenderBufferStoreAction.Store, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store);
|
|
cmd.DrawProcedural(Matrix4x4.identity, material, passIndex, MeshTopology.Quads, 4, 1, null);
|
|
}
|
|
else
|
|
{
|
|
cmd.Blit(source, destination, material, passIndex);
|
|
}
|
|
}
|
|
|
|
|
|
// Precomputed shader ids to same some CPU cycles (mostly affects mobile)
|
|
static class ShaderConstants
|
|
{
|
|
public static readonly int _TempTarget = Shader.PropertyToID("_TempTarget");
|
|
public static readonly int _TempTarget2 = Shader.PropertyToID("_TempTarget2");
|
|
|
|
public static readonly int _StencilRef = Shader.PropertyToID("_StencilRef");
|
|
public static readonly int _StencilMask = Shader.PropertyToID("_StencilMask");
|
|
|
|
public static readonly int _FullCoCTexture = Shader.PropertyToID("_FullCoCTexture");
|
|
public static readonly int _HalfCoCTexture = Shader.PropertyToID("_HalfCoCTexture");
|
|
public static readonly int _DofTexture = Shader.PropertyToID("_DofTexture");
|
|
public static readonly int _CoCParams = Shader.PropertyToID("_CoCParams");
|
|
public static readonly int _BokehKernel = Shader.PropertyToID("_BokehKernel");
|
|
public static readonly int _PongTexture = Shader.PropertyToID("_PongTexture");
|
|
public static readonly int _PingTexture = Shader.PropertyToID("_PingTexture");
|
|
|
|
public static readonly int _Metrics = Shader.PropertyToID("_Metrics");
|
|
public static readonly int _AreaTexture = Shader.PropertyToID("_AreaTexture");
|
|
public static readonly int _SearchTexture = Shader.PropertyToID("_SearchTexture");
|
|
public static readonly int _EdgeTexture = Shader.PropertyToID("_EdgeTexture");
|
|
public static readonly int _BlendTexture = Shader.PropertyToID("_BlendTexture");
|
|
|
|
public static readonly int _ColorTexture = Shader.PropertyToID("_ColorTexture");
|
|
public static readonly int _Params = Shader.PropertyToID("_Params");
|
|
public static readonly int _SourceTexLowMip = Shader.PropertyToID("_SourceTexLowMip");
|
|
public static readonly int _Bloom_Params = Shader.PropertyToID("_Bloom_Params");
|
|
public static readonly int _Bloom_RGBM = Shader.PropertyToID("_Bloom_RGBM");
|
|
public static readonly int _Bloom_Texture = Shader.PropertyToID("_Bloom_Texture");
|
|
public static readonly int _LensDirt_Texture = Shader.PropertyToID("_LensDirt_Texture");
|
|
public static readonly int _LensDirt_Params = Shader.PropertyToID("_LensDirt_Params");
|
|
public static readonly int _LensDirt_Intensity = Shader.PropertyToID("_LensDirt_Intensity");
|
|
public static readonly int _Distortion_Params1 = Shader.PropertyToID("_Distortion_Params1");
|
|
public static readonly int _Distortion_Params2 = Shader.PropertyToID("_Distortion_Params2");
|
|
public static readonly int _Chroma_Params = Shader.PropertyToID("_Chroma_Params");
|
|
public static readonly int _Vignette_Params1 = Shader.PropertyToID("_Vignette_Params1");
|
|
public static readonly int _Vignette_Params2 = Shader.PropertyToID("_Vignette_Params2");
|
|
public static readonly int _Lut_Params = Shader.PropertyToID("_Lut_Params");
|
|
public static readonly int _UserLut_Params = Shader.PropertyToID("_UserLut_Params");
|
|
public static readonly int _InternalLut = Shader.PropertyToID("_InternalLut");
|
|
public static readonly int _UserLut = Shader.PropertyToID("_UserLut");
|
|
public static readonly int _DownSampleScaleFactor = Shader.PropertyToID("_DownSampleScaleFactor");
|
|
|
|
public static readonly int _FullscreenProjMat = Shader.PropertyToID("_FullscreenProjMat");
|
|
|
|
public static int[] _BloomMipUp;
|
|
public static int[] _BloomMipDown;
|
|
}
|
|
#endregion
|
|
|
|
#region [Direct copy and no edit, from URP10.5.0's UniversalRenderPipelineCore.cs]
|
|
internal static class ShaderPropertyId
|
|
{
|
|
public static readonly int glossyEnvironmentColor = Shader.PropertyToID("_GlossyEnvironmentColor");
|
|
public static readonly int subtractiveShadowColor = Shader.PropertyToID("_SubtractiveShadowColor");
|
|
|
|
public static readonly int ambientSkyColor = Shader.PropertyToID("unity_AmbientSky");
|
|
public static readonly int ambientEquatorColor = Shader.PropertyToID("unity_AmbientEquator");
|
|
public static readonly int ambientGroundColor = Shader.PropertyToID("unity_AmbientGround");
|
|
|
|
public static readonly int time = Shader.PropertyToID("_Time");
|
|
public static readonly int sinTime = Shader.PropertyToID("_SinTime");
|
|
public static readonly int cosTime = Shader.PropertyToID("_CosTime");
|
|
public static readonly int deltaTime = Shader.PropertyToID("unity_DeltaTime");
|
|
public static readonly int timeParameters = Shader.PropertyToID("_TimeParameters");
|
|
|
|
public static readonly int scaledScreenParams = Shader.PropertyToID("_ScaledScreenParams");
|
|
public static readonly int worldSpaceCameraPos = Shader.PropertyToID("_WorldSpaceCameraPos");
|
|
public static readonly int screenParams = Shader.PropertyToID("_ScreenParams");
|
|
public static readonly int projectionParams = Shader.PropertyToID("_ProjectionParams");
|
|
public static readonly int zBufferParams = Shader.PropertyToID("_ZBufferParams");
|
|
public static readonly int orthoParams = Shader.PropertyToID("unity_OrthoParams");
|
|
|
|
public static readonly int viewMatrix = Shader.PropertyToID("unity_MatrixV");
|
|
public static readonly int projectionMatrix = Shader.PropertyToID("glstate_matrix_projection");
|
|
public static readonly int viewAndProjectionMatrix = Shader.PropertyToID("unity_MatrixVP");
|
|
|
|
public static readonly int inverseViewMatrix = Shader.PropertyToID("unity_MatrixInvV");
|
|
public static readonly int inverseProjectionMatrix = Shader.PropertyToID("unity_MatrixInvP");
|
|
public static readonly int inverseViewAndProjectionMatrix = Shader.PropertyToID("unity_MatrixInvVP");
|
|
|
|
public static readonly int cameraProjectionMatrix = Shader.PropertyToID("unity_CameraProjection");
|
|
public static readonly int inverseCameraProjectionMatrix = Shader.PropertyToID("unity_CameraInvProjection");
|
|
public static readonly int worldToCameraMatrix = Shader.PropertyToID("unity_WorldToCamera");
|
|
public static readonly int cameraToWorldMatrix = Shader.PropertyToID("unity_CameraToWorld");
|
|
|
|
public static readonly int sourceTex = Shader.PropertyToID("_SourceTex");
|
|
public static readonly int scaleBias = Shader.PropertyToID("_ScaleBias");
|
|
public static readonly int scaleBiasRt = Shader.PropertyToID("_ScaleBiasRt");
|
|
|
|
// Required for 2D Unlit Shadergraph master node as it doesn't currently support hidden properties.
|
|
public static readonly int rendererColor = Shader.PropertyToID("_RendererColor");
|
|
}
|
|
#endregion
|
|
public override void OnCameraCleanup(CommandBuffer cmd)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
#endif
|
|
} |