Updated namespace;

Added UTSPass;
Chnaged the RTHanlde _HairShadowMap to not reallocate when screen resolution decreased;
This commit is contained in:
Misaki
2025-01-08 22:19:04 +09:00
parent 23862b4380
commit a7a9ad16b5
33 changed files with 457 additions and 599 deletions

View File

@@ -7,12 +7,12 @@ using UnityEditor;
using UnityEngine.Rendering.HighDefinition;
using Unity.Properties;
namespace Unity.Rendering.HighDefinition.Toon
namespace Misaki.HdrpToon
{
[ExecuteAlways]
[DisallowMultipleComponent]
[RequireComponent(typeof(Light))]
internal class BoxLightAdjustment : MonoBehaviour
public class BoxLightAdjustment : MonoBehaviour
{
private bool _initialized = false;
private bool _srpCallbackInitialized = false;

View File

@@ -3,19 +3,20 @@ using System.IO;
using UnityEditor;
using UnityEngine;
namespace Unity.Toonshader
namespace Misaki.HdrpToon
{
[Serializable]
public struct UTSOutlineSetting
internal struct UTSOutlineSetting
{
public bool enable;
}
[Serializable]
public struct UtsHairShadowSetting
internal struct UtsHairShadowSetting
{
public bool enable;
public RenderingLayerMask CasterRenderingLayer;
public UTSHairShadowPass.ShadowQuality shadowQuality;
public LayerMask shadowCasterLayer;
}
[CreateAssetMenu(fileName = "UTSRenderSetting", menuName = "UTS/RenderSetting")]
@@ -25,8 +26,10 @@ namespace Unity.Toonshader
public const string UTS_RENDERING_SETTINGS_PATH = "Assets/Resources/Settings/UTSRenderSettings.asset";
public const string UTS_RENDERING_SETTINGS_RESOURCES_PATH = "Settings/UTSRenderSettings";
public UTSOutlineSetting outlineSetting;
public UtsHairShadowSetting hairShadowSetting;
[SerializeField]
internal UTSOutlineSetting outlineSetting;
[SerializeField]
internal UtsHairShadowSetting hairShadowSetting;
internal static UTSRenderPassSettings GetOrCreateSettings()
{
@@ -43,6 +46,12 @@ namespace Unity.Toonshader
}
else
{
var directory = Path.GetDirectoryName(UTS_RENDERING_SETTINGS_PATH);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
renderingSettings = CreateInstance<UTSRenderPassSettings>();
AssetDatabase.CreateAsset(renderingSettings, UTS_RENDERING_SETTINGS_PATH);
AssetDatabase.Refresh();

View File

@@ -910,7 +910,7 @@ void Frag(PackedVaryingsToPS packedInput,
utsAggregateLighting.directSpecular += _SDFNoseHighlightCoef * SDFNoseHighlight(angle, sdfRes.g, rightside, SDF_UV) * lightColor;
#endif
#if defined(_RECEIVE_HAIR_SHADOW) && defined(_HAIR_SHADOWS)
#ifdef _RECEIVE_HAIR_SHADOW
// Push the face fragment view space position towards the light for a little bit
float hairShadowOpacity = saturate(Remap(length(posInput.positionWS), float2(_HairShadowFadeOutDistance, _HairShadowFadeInDistance), float2(0, 1)));
@@ -924,8 +924,8 @@ void Frag(PackedVaryingsToPS packedInput,
float2 samplingPoint = (input.positionSS.xy + shadowLength * viewLightDir.xy * (_ScreenSize.xy / float2 (1920.0f, 1080.0f))) * _ScreenSize.zw; // Use 1080p as the reference resolution to achieve consistent shadow lengths across various screen resolutions.
// Then sample the hair buffer, to see if the fragment lands in shadow.
float4 hairBuffer = SAMPLE_TEXTURE2D(_HairShadowTex, s_trilinear_clamp_sampler, samplingPoint);
float hairDepth = hairBuffer.r;
float2 scaledUVs = samplingPoint * _HairShadowRTHandleScale; // We have to including the scaling factor for our shadow map since we are not going to allocate new texture if the rendering resolution changed.
float hairDepth = SAMPLE_TEXTURE2D(_HairShadowTex, s_trilinear_clamp_sampler, scaledUVs).r;
float depthCorrect = posInput.deviceDepth <= hairDepth + _HairShadowDepthBias ? 1 : 0; // Hair < Face means Hair are closer to camera
// Note that we have LinearEyeDepth in the buffer. A comparison of depth is needed so that we don't project the shadow of hair behind the face.
float hairShadow = lerp(0,hairShadowOpacity,depthCorrect);

View File

@@ -344,6 +344,8 @@ CBUFFER_END
float _Outline_MaxWidth;
float4 _HairShadowRTHandleScale;
float _HairShadowDistance;
float _HairShadowDistanceScaleFactor;
float _HairShadowDepthBias;

View File

@@ -1,6 +1,6 @@
using UnityEngine.Rendering;
namespace Unity.Toonshader
namespace Misaki.HdrpToon
{
[GenerateHLSL]
public enum UTS_BSDFDebug

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic;
using UnityEngine.Rendering;
namespace Unity.Toonshader
namespace Misaki.HdrpToon
{
public static class UTSDebugPanel
{

View File

@@ -1,108 +1,146 @@
using Unity.Toonshader;
using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering.RendererUtils;
[HideInInspector]
public class UTSHairShadowPass : DrawRenderersCustomPass
namespace Misaki.HdrpToon
{
private const string Hair_Shadow_Distance_Prop_Name = "_HairShadowDistance";
private const string Hair_Shadow_Distance_Scale_Prop_Name = "_HairShadowDistanceScaleFactor";
private const string Hair_Shadow_Depth_Bias_Prop_Name = "_HairShadowDepthBias";
private const string Hair_Shadow_FadeIn_Prop_Name = "_HairShadowFadeInDistance";
private const string Hair_Shadow_Fade_Out_Prop_Name = "_HairShadowFadeOutDistance";
private const string Output_RT_Name = "_HairShadowTex";
private RTHandle _outputRTHandle;
private bool _isEnable = false;
public UnityEngine.RenderingLayerMask renderingLayerMask;
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
[HideInInspector]
internal class UTSHairShadowPass : DrawRenderersCustomPass
{
_outputRTHandle?.Release();
_outputRTHandle = RTHandles.Alloc(Screen.width, Screen.height, colorFormat: GraphicsFormat.D32_SFloat, filterMode: FilterMode.Bilinear, wrapMode: TextureWrapMode.Clamp, isShadowMap: true, name: Output_RT_Name);
SetEnable(true);
}
protected override void Execute(CustomPassContext ctx)
{
var utsRenderer = ctx.hdCamera.volumeStack.GetComponent<UTSRenderer>();
if (utsRenderer == null || !utsRenderer.enableHairShadow.value || !utsRenderer.enable.value)
public enum ShadowQuality
{
SetEnable(false);
return;
Low,
High
}
if (!_isEnable)
private const string Hair_Shadow_RTHandle_Scale_Prop_Name = "_HairShadowRTHandleScale";
private const string Hair_Shadow_Distance_Prop_Name = "_HairShadowDistance";
private const string Hair_Shadow_Distance_Scale_Prop_Name = "_HairShadowDistanceScaleFactor";
private const string Hair_Shadow_Depth_Bias_Prop_Name = "_HairShadowDepthBias";
private const string Hair_Shadow_FadeIn_Prop_Name = "_HairShadowFadeInDistance";
private const string Hair_Shadow_Fade_Out_Prop_Name = "_HairShadowFadeOutDistance";
private const string Output_RT_Name = "_HairShadowTex";
private RTHandle _outputRTHandle;
private bool _needReallocate;
private ShadowQuality _shadowQuality = ShadowQuality.High;
internal ShadowQuality CurrentShadowQuality
{
return;
get => _shadowQuality;
set
{
if (_shadowQuality == value)
{
return;
}
_shadowQuality = value;
_needReallocate = true;
}
}
SetShadowProperty(utsRenderer);
if (_outputRTHandle != null)
private bool ShouldReallocateBuffer()
{
return _outputRTHandle == null || _outputRTHandle.rt == null || !_outputRTHandle.rt.IsCreated() || _needReallocate;
}
private void ReallocateBuffer()
{
#if UNITY_EDITOR
if (EditorApplication.isCompiling)
{
return;
}
#endif
var scale = _shadowQuality switch
{
ShadowQuality.Low => new Vector2(0.5f, 0.5f),
ShadowQuality.High => Vector2.one,
_ => Vector2.zero
};
var format = _shadowQuality switch
{
ShadowQuality.Low => GraphicsFormat.D16_UNorm,
ShadowQuality.High => GraphicsFormat.D32_SFloat,
_ => GraphicsFormat.D16_UNorm
};
_outputRTHandle?.Release();
_outputRTHandle = RTHandles.Alloc(scale, colorFormat: format, filterMode: FilterMode.Bilinear, wrapMode: TextureWrapMode.Clamp, isShadowMap: true, name: Output_RT_Name);
Shader.SetGlobalTexture(Output_RT_Name, _outputRTHandle);
CoreUtils.SetRenderTarget(ctx.cmd, _outputRTHandle, ClearFlag.DepthStencil);
_needReallocate = false;
}
var mask = RenderStateMask.Nothing;
var stateBlock = new RenderStateBlock(mask)
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{
depthState = new DepthState(true, CompareFunction.LessEqual),
};
ReallocateBuffer();
}
var result = new RendererListDesc(HDShaderPassNames.s_DepthForwardOnlyName, ctx.cullingResults, ctx.hdCamera.camera)
protected override void Execute(CustomPassContext ctx)
{
renderQueueRange = GetRenderQueueRange(RenderQueueType.All),
sortingCriteria = SortingCriteria.CommonOpaque,
excludeObjectMotionVectors = false,
stateBlock = stateBlock,
renderingLayerMask = renderingLayerMask,
};
CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, ctx.renderContext.CreateRendererList(result));
}
private static void SetShadowProperty(UTSRenderer utsRenderer)
{
Shader.SetGlobalFloat(Hair_Shadow_Distance_Prop_Name, utsRenderer.shadowDistance.value);
Shader.SetGlobalFloat(Hair_Shadow_Distance_Scale_Prop_Name, utsRenderer.shadowDistanceScale.value);
Shader.SetGlobalFloat(Hair_Shadow_Depth_Bias_Prop_Name, utsRenderer.shadowDepthBias.value);
Shader.SetGlobalFloat(Hair_Shadow_FadeIn_Prop_Name, utsRenderer.shadowFadeIn.value);
Shader.SetGlobalFloat(Hair_Shadow_Fade_Out_Prop_Name, utsRenderer.shadowFadeOut.value);
}
protected override void Cleanup()
{
Release();
}
public void Release()
{
SetEnable(false);
_outputRTHandle?.Release();
}
public void SetEnable(bool isEnable)
{
if (_isEnable != isEnable)
{
if (isEnable)
if (ShouldReallocateBuffer())
{
Shader.EnableKeyword("_HAIR_SHADOWS");
}
else
{
Shader.DisableKeyword("_HAIR_SHADOWS");
ReallocateBuffer();
return;
}
_isEnable = isEnable;
CoreUtils.SetRenderTarget(ctx.cmd, _outputRTHandle, ClearFlag.DepthStencil);
var utsRenderer = ctx.hdCamera.volumeStack.GetComponent<UTSRenderer>();
var shouldRender = utsRenderer != null && utsRenderer.enableHairShadow.value && utsRenderer.state.value;
if (!shouldRender)
{
CoreUtils.ClearRenderTarget(ctx.cmd, ClearFlag.DepthStencil, Color.black);
return;
}
var mask = RenderStateMask.Nothing;
var stateBlock = new RenderStateBlock(mask)
{
depthState = new DepthState(true, CompareFunction.LessEqual),
};
var result = new RendererListDesc(HDShaderPassNames.s_DepthForwardOnlyName, ctx.cullingResults, ctx.hdCamera.camera)
{
renderQueueRange = GetRenderQueueRange(RenderQueueType.All),
sortingCriteria = SortingCriteria.CommonOpaque,
excludeObjectMotionVectors = false,
stateBlock = stateBlock,
layerMask = layerMask,
};
CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, ctx.renderContext.CreateRendererList(result));
Shader.SetGlobalVector(Hair_Shadow_RTHandle_Scale_Prop_Name, _outputRTHandle.rtHandleProperties.rtHandleScale);
Shader.SetGlobalFloat(Hair_Shadow_Distance_Prop_Name, utsRenderer.shadowDistance.value);
Shader.SetGlobalFloat(Hair_Shadow_Distance_Scale_Prop_Name, utsRenderer.shadowDistanceScale.value);
Shader.SetGlobalFloat(Hair_Shadow_Depth_Bias_Prop_Name, utsRenderer.shadowDepthBias.value);
Shader.SetGlobalFloat(Hair_Shadow_FadeIn_Prop_Name, utsRenderer.shadowFadeIn.value);
Shader.SetGlobalFloat(Hair_Shadow_Fade_Out_Prop_Name, utsRenderer.shadowFadeOut.value);
}
protected override void Cleanup()
{
Release();
}
public void Release()
{
#if UNITY_EDITOR
if (EditorApplication.isCompiling)
{
return;
}
#endif
_outputRTHandle?.Release();
}
}
}

View File

@@ -1,41 +1,47 @@
using Unity.Toonshader;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
[HideInInspector]
public class UTSOutlinePass : DrawRenderersCustomPass
namespace Misaki.HdrpToon
{
private ShaderTagId outlineTag = new("Outline");
protected override void Execute(CustomPassContext ctx)
[HideInInspector]
internal class UTSOutlinePass : DrawRenderersCustomPass
{
var utsRenderer = ctx.hdCamera.volumeStack.GetComponent<UTSRenderer>();
if (utsRenderer == null)
return;
private ShaderTagId outlineTag = new("Outline");
if (!utsRenderer.enableOutline.value || !utsRenderer.enable.value)
return;
Shader.SetGlobalFloat("_Outline_MaxWidth", utsRenderer.outlineMaxWidth.value * 0.01f);
var mask = RenderStateMask.Nothing;
var stateBlock = new RenderStateBlock(mask)
protected override void Execute(CustomPassContext ctx)
{
depthState = new DepthState(depthWrite, depthCompareFunction),
// We disable the stencil when the depth is overwritten but we don't write to it, to prevent writing to the stencil.
stencilState = new StencilState(false),
};
var utsRenderer = ctx.hdCamera.volumeStack.GetComponent<UTSRenderer>();
if (utsRenderer == null)
{
return;
}
var renderConfig = HDUtils.GetRendererConfiguration(false, false);
var result = new UnityEngine.Rendering.RendererUtils.RendererListDesc(outlineTag, ctx.cullingResults, ctx.hdCamera.camera)
{
rendererConfiguration = renderConfig,
renderQueueRange = GetRenderQueueRange(RenderQueueType.All),
excludeObjectMotionVectors = false,
stateBlock = stateBlock,
};
if (!utsRenderer.enableOutline.value || !utsRenderer.state.value)
{
return;
}
CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, ctx.renderContext.CreateRendererList(result));
Shader.SetGlobalFloat("_Outline_MaxWidth", utsRenderer.outlineMaxWidth.value * 0.01f);
var mask = RenderStateMask.Nothing;
var stateBlock = new RenderStateBlock(mask)
{
depthState = new DepthState(depthWrite, depthCompareFunction),
// We disable the stencil when the depth is overwritten but we don't write to it, to prevent writing to the stencil.
stencilState = new StencilState(false),
};
var renderConfig = HDUtils.GetRendererConfiguration(false, false);
var result = new UnityEngine.Rendering.RendererUtils.RendererListDesc(outlineTag, ctx.cullingResults, ctx.hdCamera.camera)
{
rendererConfiguration = renderConfig,
renderQueueRange = GetRenderQueueRange(RenderQueueType.All),
excludeObjectMotionVectors = false,
stateBlock = stateBlock,
};
CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, ctx.renderContext.CreateRendererList(result));
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
namespace Misaki.HdrpToon
{
internal class UTSPass : CustomPass
{
private const int Adjustment_Curve_Precision = 128;
private const string Compensation_Prop_Name = "_ToonEvAdjustmentCompensation";
private const string Exposure_Adjustment_Prop_Name = "_ToonEvAdjustmentCurve";
private const string Exposure_Array_Prop_Name = "_ToonEvAdjustmentValueArray";
private const string Exposure_Min_Prop_Name = "_ToonEvAdjustmentValueMin";
private const string Exposure_Max_Prop_Name = "_ToonEvAdjustmentValueMax";
private const string Toon_Light_Filter_Prop_Name = "_ToonLightHiCutFilter";
private const string Ignore_Volume_Exposure_Prop_Name = "_ToonIgnoreExposureMultiplier";
private float _max;
private float _min;
private float[] _exposureArray;
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{
_exposureArray = new float[Adjustment_Curve_Precision];
}
protected override void Execute(CustomPassContext ctx)
{
var utsRenderer = ctx.hdCamera.volumeStack.GetComponent<UTSRenderer>();
if (utsRenderer == null)
{
return;
}
var toonEVAdjustment = utsRenderer.toonEVAdjustment.value ? 1 : 0;
var lightIntensityLimiter = utsRenderer.lightIntensityLimiter.value ? 1 : 0;
var ignoreVolumeExposure = utsRenderer.ignoreVolumeExposure.value ? 1 : 0;
var compensation = utsRenderer.compensation.value;
if (!utsRenderer.state.value)
{
_min = 0;
_max = 0;
_exposureArray.AsSpan().Fill(0);
toonEVAdjustment = 0;
lightIntensityLimiter = 0;
ignoreVolumeExposure = 0;
compensation = 0;
}
else
{
// Fail safe in case the curve is deleted / has 0 point
var curve = utsRenderer.adjustmentCurve.value;
if (curve == null || curve.length == 0)
{
_min = 0f;
_max = 0f;
_exposureArray.AsSpan().Fill(0);
}
else
{
_min = curve[0].time;
_max = curve[curve.length - 1].time;
var step = (_max - _min) / (Adjustment_Curve_Precision - 1f);
for (var i = 0; i < Adjustment_Curve_Precision; i++)
{
_exposureArray[i] = curve.Evaluate(_min + step * i);
}
}
}
Shader.SetGlobalFloatArray(Exposure_Array_Prop_Name, _exposureArray);
Shader.SetGlobalFloat(Exposure_Min_Prop_Name, _min);
Shader.SetGlobalFloat(Exposure_Max_Prop_Name, _max);
Shader.SetGlobalInt(Exposure_Adjustment_Prop_Name, toonEVAdjustment);
Shader.SetGlobalInt(Toon_Light_Filter_Prop_Name, lightIntensityLimiter);
Shader.SetGlobalInt(Ignore_Volume_Exposure_Prop_Name, ignoreVolumeExposure);
Shader.SetGlobalFloat(Compensation_Prop_Name, compensation);
}
protected override void Cleanup()
{
_exposureArray = null;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: be0dbffe58fd1fc48a45d8a6e1791ac0

View File

@@ -1,65 +0,0 @@
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
namespace Unity.Toonshader
{
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoad]
#endif
public static class RegisterUTSRenderPass
{
private static readonly UTSRenderPassSettings _renderSetting;
private static readonly UTSOutlinePass _outlinePass;
private static readonly UTSHairShadowPass _hairShadowPass;
static RegisterUTSRenderPass()
{
_renderSetting = UTSRenderPassSettings.GetOrCreateSettings();
if (_renderSetting == null)
{
return;
}
_outlinePass = new()
{
name = "UTS Outline",
};
_hairShadowPass = new()
{
name = "UTS Hair Shadow Map",
renderingLayerMask = _renderSetting.hairShadowSetting.CasterRenderingLayer,
targetColorBuffer = CustomPass.TargetBuffer.None,
targetDepthBuffer = CustomPass.TargetBuffer.None,
};
RegisterCustomPasses();
}
[RuntimeInitializeOnLoadMethod]
public static void RegisterCustomPasses()
{
CustomPassVolume.RegisterUniqueGlobalCustomPass(CustomPassInjectionPoint.AfterOpaqueDepthAndNormal, _hairShadowPass);
CustomPassVolume.RegisterUniqueGlobalCustomPass(CustomPassInjectionPoint.BeforePostProcess, _outlinePass);
_hairShadowPass.SetEnable(_renderSetting.hairShadowSetting.enable);
_outlinePass.enabled = _renderSetting.outlineSetting.enable;
}
public static void UnregisterGlobalCustomPass()
{
CustomPassVolume.UnregisterGlobalCustomPass(_hairShadowPass);
CustomPassVolume.UnregisterGlobalCustomPass(_outlinePass);
_hairShadowPass.Release();
}
public static void NotifyRendererSettingChanged()
{
_hairShadowPass.SetEnable(_renderSetting.hairShadowSetting.enable);
_hairShadowPass.renderingLayerMask = _renderSetting.hairShadowSetting.CasterRenderingLayer;
_outlinePass.enabled = _renderSetting.outlineSetting.enable;
}
}
}

View File

@@ -0,0 +1,82 @@
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
namespace Misaki.HdrpToon
{
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoad]
#endif
public static class UTSRenderPassRegistrar
{
private static UTSRenderPassSettings _renderSetting;
private static UTSPass _utsPass;
private static UTSHairShadowPass _hairShadowPass;
private static UTSOutlinePass _outlinePass;
static UTSRenderPassRegistrar() => RegisterCustomPasses();
[RuntimeInitializeOnLoadMethod]
public static void RegisterCustomPasses()
{
_renderSetting = UTSRenderPassSettings.GetOrCreateSettings();
if (_renderSetting == null)
{
return;
}
_utsPass = new UTSPass()
{
name = "UTS Pass",
targetColorBuffer = CustomPass.TargetBuffer.None,
targetDepthBuffer = CustomPass.TargetBuffer.None,
};
_hairShadowPass = new()
{
name = "UTS Hair Shadow Map",
layerMask = _renderSetting.hairShadowSetting.shadowCasterLayer,
targetColorBuffer = CustomPass.TargetBuffer.None,
targetDepthBuffer = CustomPass.TargetBuffer.None,
};
_outlinePass = new()
{
name = "UTS Outline",
targetColorBuffer = CustomPass.TargetBuffer.None,
targetDepthBuffer = CustomPass.TargetBuffer.None,
};
CustomPassVolume.RegisterGlobalCustomPass(CustomPassInjectionPoint.BeforeRendering, _utsPass);
CustomPassVolume.RegisterGlobalCustomPass(CustomPassInjectionPoint.AfterOpaqueDepthAndNormal, _hairShadowPass);
CustomPassVolume.RegisterGlobalCustomPass(CustomPassInjectionPoint.BeforePostProcess, _outlinePass);
NotifyRendererSettingChanged();
}
public static void UnregisterGlobalCustomPass()
{
CustomPassVolume.UnregisterGlobalCustomPass(_utsPass);
CustomPassVolume.UnregisterGlobalCustomPass(_hairShadowPass);
CustomPassVolume.UnregisterGlobalCustomPass(_outlinePass);
}
public static void NotifyRendererSettingChanged()
{
if (_hairShadowPass == null || _outlinePass == null)
{
return;
}
_hairShadowPass.layerMask = _renderSetting.hairShadowSetting.shadowCasterLayer;
_hairShadowPass.enabled = _renderSetting.hairShadowSetting.enable;
_hairShadowPass.CurrentShadowQuality = _renderSetting.hairShadowSetting.shadowQuality;
if (!_renderSetting.hairShadowSetting.enable)
{
_hairShadowPass.Release();
}
_outlinePass.enabled = _renderSetting.outlineSetting.enable;
}
}
}

View File

@@ -1,198 +1,39 @@
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace Unity.Toonshader
namespace Misaki.HdrpToon
{
[Serializable, VolumeComponentMenu("Rendering/Unity Toon Shader")]
[Serializable, VolumeComponentMenu("Rendering/UTS Renderer")]
public class UTSRenderer : VolumeComponent
{
// flags
bool _initialized = false;
const int kAdjustmentCurvePrecision = 128;
const string kCompensationPropName = "_ToonEvAdjustmentCompensation";
const string kExposureAdjustmentPropName = "_ToonEvAdjustmentCurve";
const string kExposureArrayPropName = "_ToonEvAdjustmentValueArray";
const string kExposureMinPropName = "_ToonEvAdjustmentValueMin";
const string kExposureMaxPropName = "_ToonEvAdjustmentValueMax";
const string kToonLightFilterPropName = "_ToonLightHiCutFilter";
const string kIgnoreVolumeExposurePropName = "_ToonIgnoreExposureMultiplier";
[SerializeField]
internal float[] _ExposureArray;
[SerializeField]
internal float _Max, _Min;
//CustomPassVolume customPassVolume = new();
//UTSOutlinePass outlinePass = new();
#if UNITY_EDITOR
#pragma warning restore CS0414
bool m_isCompiling = false;
#endif
public BoolParameter enable = new BoolParameter(false, BoolParameter.DisplayType.EnumPopup);
public BoolParameter state = new(false, BoolParameter.DisplayType.EnumPopup);
[Space]
[Header("Outline")]
public BoolParameter enableOutline = new BoolParameter(false);
public MinFloatParameter outlineMaxWidth = new MinFloatParameter(1.0f, 0.0f);
public BoolParameter enableOutline = new(false);
public MinFloatParameter outlineMaxWidth = new(1.0f, 0.0f);
[Space]
[Header("Hair Shadow")]
public BoolParameter enableHairShadow = new BoolParameter(false);
public ClampedFloatParameter shadowDistance = new ClampedFloatParameter(5.0f, 0.0f, 20.0f);
public ClampedFloatParameter shadowDistanceScale = new ClampedFloatParameter(0.5f, 0.0f, 1.0f);
public ClampedFloatParameter shadowDepthBias = new ClampedFloatParameter(0f, 0.0f, 0.01f);
public FloatParameter shadowFadeIn = new FloatParameter(45f);
public FloatParameter shadowFadeOut = new FloatParameter(50f);
public BoolParameter enableHairShadow = new(false);
public ClampedFloatParameter shadowDistance = new(5.0f, 0.0f, 20.0f);
public ClampedFloatParameter shadowDistanceScale = new(0.5f, 0.0f, 1.0f);
public ClampedFloatParameter shadowDepthBias = new(0f, 0.0f, 0.01f);
public FloatParameter shadowFadeIn = new(45f);
public FloatParameter shadowFadeOut = new(50f);
[Space]
[Header("Exposure")]
public BoolParameter ignoreVolumeExposure = new BoolParameter(false);
public BoolParameter lightIntensityLimiter = new BoolParameter(false);
public MinFloatParameter compensation = new MinFloatParameter(0.0f, 0.0f);
public BoolParameter toonEVAdjustment = new BoolParameter(false);
public AnimationCurveParameter adjustmentCurve = new AnimationCurveParameter(DefaultAnimationCurve());
public BoolParameter ignoreVolumeExposure = new(false);
public BoolParameter lightIntensityLimiter = new(false);
public MinFloatParameter compensation = new(0.0f, 0.0f);
public BoolParameter toonEVAdjustment = new(false);
public AnimationCurveParameter adjustmentCurve = new(DefaultAnimationCurve());
UTSRenderer()
{
displayName = "UTS Renderer";
}
protected override void OnEnable()
{
base.OnEnable();
UTSDebugPanel.OnEnable();
Initialize();
}
protected override void OnDisable()
{
base.OnDisable();
UTSDebugPanel.OnDisable();
Release();
}
private void OnValidate()
{
if (!enable.value)
{
Release();
return;
}
Initialize();
if (!_initialized)
{
return;
}
// Fail safe in case the curve is deleted / has 0 point
var curve = adjustmentCurve.value;
if (curve == null || curve.length == 0)
{
_Min = 0f;
_Max = 0f;
for (var i = 0; i < kAdjustmentCurvePrecision; i++)
_ExposureArray[i] = 0.0f;
}
else
{
_Min = curve[0].time;
_Max = curve[curve.length - 1].time;
var step = (_Max - _Min) / (kAdjustmentCurvePrecision - 1f);
for (var i = 0; i < kAdjustmentCurvePrecision; i++)
_ExposureArray[i] = curve.Evaluate(_Min + step * i);
}
#if UNITY_EDITOR
// handle script recompile
if (EditorApplication.isCompiling && !m_isCompiling)
{
// on compile begin
m_isCompiling = true;
// Release(); no need
return; //
}
else if (!EditorApplication.isCompiling && m_isCompiling)
{
// on compile end
m_isCompiling = false;
}
#endif
Shader.SetGlobalFloatArray(kExposureArrayPropName, _ExposureArray);
Shader.SetGlobalFloat(kExposureMinPropName, _Min);
Shader.SetGlobalFloat(kExposureMaxPropName, _Max);
Shader.SetGlobalInt(kExposureAdjustmentPropName, toonEVAdjustment.value ? 1 : 0);
Shader.SetGlobalInt(kToonLightFilterPropName, lightIntensityLimiter.value ? 1 : 0);
Shader.SetGlobalInt(kIgnoreVolumeExposurePropName, ignoreVolumeExposure.value ? 1 : 0);
Shader.SetGlobalFloat(kCompensationPropName, compensation.value);
}
internal static AnimationCurve DefaultAnimationCurve()
private static AnimationCurve DefaultAnimationCurve()
{
return AnimationCurve.Linear(-10f, -10f, -1.32f, -1.32f);
}
void Initialize()
{
if (_initialized)
{
return;
}
#if UNITY_EDITOR
// initializing renderer can interfere GI baking. so wait until it is completed.
if (EditorApplication.isCompiling)
return;
#endif
if (_ExposureArray == null || _ExposureArray.Length != kAdjustmentCurvePrecision)
{
_ExposureArray = new float[kAdjustmentCurvePrecision];
}
_initialized = true;
}
protected override void OnDestroy()
{
base.OnDestroy();
Release();
}
new void Release()
{
if (_initialized)
{
_ExposureArray = null;
Shader.SetGlobalFloat(kExposureMinPropName, 0);
Shader.SetGlobalFloat(kExposureMaxPropName, 0);
Shader.SetGlobalInt(kExposureAdjustmentPropName, 0);
Shader.SetGlobalInt(kToonLightFilterPropName, 0);
Shader.SetGlobalInt(kIgnoreVolumeExposurePropName, 0);
Shader.SetGlobalFloat(kCompensationPropName, 0);
}
_initialized = false;
base.Release();
}
private void Reset()
{
OnDisable();
OnEnable();
DefaultAnimationCurve();
}
}
}
}