Added stencil setup in UTSAPI;

Changed hair shadow length from screen space to world space;
This commit is contained in:
2025-05-24 00:05:50 +09:00
parent 5b2eb17148
commit 1a93e81edd
7 changed files with 193 additions and 41 deletions

View File

@@ -4,24 +4,57 @@ using static Misaki.HdrpToon.UTSPropertyName;
namespace Misaki.HdrpToon
{
internal enum RenderPriority
{
Opaque = RenderQueue.Geometry,
OpaqueDecal = RenderQueue.Geometry + 225, // Opaque Decal mean Opaque that can receive decal
OpaqueAlphaTest = RenderQueue.AlphaTest,
OpaqueDecalAlphaTest = RenderQueue.AlphaTest + 25,
// Warning: we must not change Geometry last value to stay compatible with occlusion
OpaqueLast = RenderQueue.GeometryLast,
AfterPostprocessOpaque = RenderQueue.GeometryLast + 1,
AfterPostprocessOpaqueAlphaTest = RenderQueue.GeometryLast + 10,
TransparentFirst = RenderQueue.Transparent - 100,
Transparent = RenderQueue.Transparent,
TransparentLast = RenderQueue.Transparent + 100,
}
internal enum StencilUsage
{
Clear = 0,
// Note: first bit is free and can still be used by both phases.
// --- Following bits are used before transparent rendering ---
IsUnlit = (1 << 0), // Unlit materials (shader and shader graph) except for the shadow matte
RequiresDeferredLighting = (1 << 1),
SubsurfaceScattering = (1 << 2), // SSS, Split Lighting
TraceReflectionRay = (1 << 3), // SSR or RTR - slot is reuse in transparent
Decals = (1 << 4), // Use to tag when an Opaque Decal is render into DBuffer
ObjectMotionVector = (1 << 5), // Animated object (for motion blur, SSR, SSAO, TAA)
// --- Stencil is cleared after opaque rendering has finished ---
// --- Following bits are used exclusively for what happens after opaque ---
WaterExclusion = (1 << 0), // Prevents water surface from being rendered.
ExcludeFromTUAndAA = (1 << 1), // Disable Temporal Upscaling and Antialiasing for certain objects
DistortionVectors = (1 << 2), // Distortion pass - reset after distortion pass, shared with SMAA
SMAA = (1 << 2), // Subpixel Morphological Antialiasing
// Reserved TraceReflectionRay = (1 << 3) for transparent SSR or RTR
Refractive = (1 << 4), // Indicates there's a refractive object
WaterSurface = (1 << 5), // Reserved for water surface usage (If update the value of 'STENCILUSAGE_WATER_SURFACE' in LensFlareCommon.hlsl)
// --- Following are user bits, we don't touch them inside HDRP and is up to the user to handle them ---
UserBit0 = (1 << 6),
UserBit1 = (1 << 7),
HDRPReservedBits = 255 & ~(UserBit0 | UserBit1),
}
internal class UTSAPI
{
private enum RenderPriority
{
Opaque = RenderQueue.Geometry,
OpaqueDecal = RenderQueue.Geometry + 225, // Opaque Decal mean Opaque that can receive decal
OpaqueAlphaTest = RenderQueue.AlphaTest,
OpaqueDecalAlphaTest = RenderQueue.AlphaTest + 25,
// Warning: we must not change Geometry last value to stay compatible with occlusion
OpaqueLast = RenderQueue.GeometryLast,
AfterPostprocessOpaque = RenderQueue.GeometryLast + 1,
AfterPostprocessOpaqueAlphaTest = RenderQueue.GeometryLast + 10,
TransparentFirst = RenderQueue.Transparent - 100,
Transparent = RenderQueue.Transparent,
TransparentLast = RenderQueue.Transparent + 100,
}
public static void SetupPass(Material material)
{
@@ -39,6 +72,80 @@ namespace Misaki.HdrpToon
CoreUtils.SetKeyword(material, "_DOUBLESIDED_ON", doubleSidedEnable);
}
static public void ComputeStencilProperties(bool receivesLighting, bool forwardOnly, bool receivesSSR, bool useSplitLighting, bool hasRefraction, bool excludeFromTUAndAA,
out int stencilRef, out int stencilWriteMask, out int stencilRefDepth, out int stencilWriteMaskDepth, out int stencilRefGBuffer, out int stencilWriteMaskGBuffer, out int stencilRefMV, out int stencilWriteMaskMV)
{
// Stencil usage rules:
// TraceReflectionRay need to be tagged during depth prepass
// RequiresDeferredLighting need to be tagged during GBuffer
// SubsurfaceScattering need to be tagged during either GBuffer or Forward pass
// ObjectMotionVectors need to be tagged in velocity pass.
// As motion vectors pass can be use as a replacement of depth prepass it also need to have TraceReflectionRay
// As GBuffer pass can have no depth prepass, it also need to have TraceReflectionRay
// Object motion vectors is always render after a full depth buffer (if there is no depth prepass for GBuffer all object motion vectors are render after GBuffer)
// so we have a guarantee than when we write object motion vectors no other object will be draw on top (and so would have require to overwrite motion vectors).
// Final combination is:
// Prepass: TraceReflectionRay
// Motion vectors: TraceReflectionRay, ObjectVelocity
// GBuffer: LightingMask, ObjectVelocity
// Forward: LightingMask
stencilRef = (int)StencilUsage.Clear; // Forward case
stencilWriteMask = (int)StencilUsage.RequiresDeferredLighting | (int)StencilUsage.SubsurfaceScattering;
stencilRefDepth = 0;
stencilWriteMaskDepth = 0;
stencilRefGBuffer = (int)StencilUsage.RequiresDeferredLighting;
stencilWriteMaskGBuffer = (int)StencilUsage.RequiresDeferredLighting | (int)StencilUsage.SubsurfaceScattering;
stencilRefMV = (int)StencilUsage.ObjectMotionVector;
stencilWriteMaskMV = (int)StencilUsage.ObjectMotionVector;
// ForwardOnly materials with motion vectors are rendered after GBuffer, so we need to clear the deferred bit in the stencil
if (forwardOnly)
stencilWriteMaskMV |= (int)StencilUsage.RequiresDeferredLighting;
if (useSplitLighting)
{
stencilRefGBuffer |= (int)StencilUsage.SubsurfaceScattering;
stencilRef |= (int)StencilUsage.SubsurfaceScattering;
}
if (receivesSSR)
{
stencilRefDepth |= (int)StencilUsage.TraceReflectionRay;
stencilRefGBuffer |= (int)StencilUsage.TraceReflectionRay;
stencilRefMV |= (int)StencilUsage.TraceReflectionRay;
}
stencilWriteMaskDepth |= (int)StencilUsage.TraceReflectionRay;
stencilWriteMaskGBuffer |= (int)StencilUsage.TraceReflectionRay;
stencilWriteMaskMV |= (int)StencilUsage.TraceReflectionRay;
if (hasRefraction)
{
stencilRefDepth |= (int)StencilUsage.Refractive;
stencilWriteMaskDepth |= (int)StencilUsage.Refractive;
}
if (!receivesLighting)
{
stencilRefDepth |= (int)StencilUsage.IsUnlit;
stencilWriteMaskDepth |= (int)StencilUsage.IsUnlit;
stencilRefMV |= (int)StencilUsage.IsUnlit;
}
if (excludeFromTUAndAA)
{
stencilRefDepth |= (int)StencilUsage.ExcludeFromTUAndAA;
stencilRef |= (int)StencilUsage.ExcludeFromTUAndAA;
stencilWriteMask |= (int)StencilUsage.ExcludeFromTUAndAA;
stencilWriteMaskDepth |= (int)StencilUsage.ExcludeFromTUAndAA;
}
stencilWriteMaskDepth |= (int)StencilUsage.IsUnlit;
stencilWriteMaskGBuffer |= (int)StencilUsage.IsUnlit;
stencilWriteMaskMV |= (int)StencilUsage.IsUnlit;
}
public static void SetupProperties(Material material)
{
var surfaceType = (SurfaceType)material.GetInteger(SurfaceOptions.SURFACE_TYPE);
@@ -119,15 +226,32 @@ namespace Misaki.HdrpToon
if (isBackFaceEnable)
{
material.SetInt(InternalProperties.CULL_MODE_FORWARD, (int)CullMode.Back);
material.SetInteger(InternalProperties.CULL_MODE_FORWARD, (int)CullMode.Back);
}
else
{
material.SetInteger(InternalProperties.CULL_MODE_FORWARD, (int)(doubleSidedEnable ? CullMode.Off : cullMode));
}
// TODO: Setup stencil value. Currently it produce noticeable jittering when surface type is transparent.
// This is caused by taa, _StencilWriteMask need to include StencilUsage.ExcludeFromTUAndAA when surface type is transparent.
// Stencil
ComputeStencilProperties(true, true, true, false, false, false,
out var stencilRef, out var stencilWriteMask, out var stencilRefDepth, out var stencilWriteMaskDepth,
out var stencilRefGBuffer, out var stencilWriteMaskGBuffer, out var stencilRefMV, out var stencilWriteMaskMV);
material.SetInteger(InternalProperties.STENCIL_REF, stencilRef);
material.SetInteger(InternalProperties.STENCIL_WRITE_MASK, stencilWriteMask);
material.SetInteger(InternalProperties.STENCIL_REF_DEPTH, stencilRefDepth);
material.SetInteger(InternalProperties.STENCIL_WRITE_MASK_DEPTH, stencilWriteMaskDepth);
material.SetInteger(InternalProperties.STENCIL_REF_G_BUFFER, stencilRefGBuffer);
material.SetInteger(InternalProperties.STENCIL_WRITE_MASK_G_BUFFER, stencilWriteMaskGBuffer);
material.SetInteger(InternalProperties.STENCIL_REF_DISTORTION_VEC, (int)StencilUsage.DistortionVectors);
material.SetInteger(InternalProperties.STENCIL_WRITE_MASK_DISTORTION_VEC, (int)StencilUsage.DistortionVectors);
material.SetInteger(InternalProperties.STENCIL_REF_MV, stencilRefMV);
material.SetInteger(InternalProperties.STENCIL_WRITE_MASK_MV, stencilWriteMaskMV);
}
}
}