Files
com.misaki.hdrp-toon/Runtime/UTSAPI.cs
2025-05-22 22:28:48 +09:00

133 lines
6.8 KiB
C#

using UnityEngine;
using UnityEngine.Rendering;
using static Misaki.HdrpToon.UTSPropertyName;
namespace Misaki.HdrpToon
{
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)
{
material.SetShaderPassEnabled(UTSPassName.HAIR_SHADOW_CASTER_PASS_NAME, (MaterialType)material.GetInteger(SurfaceOptions.MATERIAL_TYPE) == MaterialType.FrontHair);
material.SetShaderPassEnabled(UTSPassName.HAIR_BLENDING_TARGET_PASS_NAME, material.GetInteger(SurfaceOptions.HAIR_BLENDING_TARGET) == 1);
}
public static void SetupKeywords(Material material)
{
var surfaceType = (SurfaceType)material.GetInteger(SurfaceOptions.SURFACE_TYPE);
var cullMode = (CullMode)material.GetInteger(SurfaceOptions.CULL_MODE);
var doubleSidedEnable = cullMode == CullMode.Off;
CoreUtils.SetKeyword(material, "_SURFACE_TYPE_TRANSPARENT", surfaceType == SurfaceType.Transparent);
CoreUtils.SetKeyword(material, "_DOUBLESIDED_ON", doubleSidedEnable);
}
public static void SetupProperties(Material material)
{
var surfaceType = (SurfaceType)material.GetInteger(SurfaceOptions.SURFACE_TYPE);
var cullMode = (CullMode)material.GetInteger(SurfaceOptions.CULL_MODE);
// Surface type
var isTransparent = surfaceType == SurfaceType.Transparent;
var isAlphaClip = material.GetInteger(SurfaceOptions.ALPHA_CLIP_ENABLE) == 1;
var renderQueue = isTransparent ? RenderPriority.Transparent : (isAlphaClip ? RenderPriority.OpaqueAlphaTest : RenderPriority.Opaque);
material.SetInteger(InternalProperties.SURFACE_TYPE, isTransparent ? 1 : 0);
material.renderQueue = (int)renderQueue;
// We only do clip for alpha clip in depth pre-pass once. Z test for GBuffer and forward pass need to set to equal to make sure alpha clip works correctly.
if (isAlphaClip)
{
material.SetInteger(InternalProperties.ZTEST_GBUFFER, (int)CompareFunction.Equal);
}
else
{
material.SetInteger(InternalProperties.ZTEST_GBUFFER, (int)CompareFunction.LessEqual);
}
if (isTransparent)
{
material.SetInteger(InternalProperties.ZTEST_DEPTH_EQUAL_FOR_OPAQUE, material.GetInteger(InternalProperties.ZTEST_TRANSPARENT));
material.SetOverrideTag("RenderType", "Transparent");
// TODO: Z write for transparent.
material.SetInteger(InternalProperties.ZWRITE, 0);
material.SetInteger(InternalProperties.DEST_BLEND2, (int)BlendMode.OneMinusSrcAlpha);
//TODO: Implement additive and pre-multiply mode.
material.SetInteger(InternalProperties.SRC_BLEND, (int)BlendMode.One);
material.SetInteger(InternalProperties.DEST_BLEND, (int)BlendMode.OneMinusSrcAlpha);
material.SetInteger(InternalProperties.ALPHA_SRC_BLEND, (int)BlendMode.One);
material.SetInteger(InternalProperties.ALPHA_DEST_BLEND, (int)BlendMode.OneMinusSrcAlpha);
}
else
{
material.SetInteger(InternalProperties.ZTEST_DEPTH_EQUAL_FOR_OPAQUE, (int)CompareFunction.Equal);
material.SetOverrideTag("RenderType", isAlphaClip ? "TransparentCutout" : "");
material.SetInteger(InternalProperties.SRC_BLEND, (int)BlendMode.One);
material.SetInteger(InternalProperties.DEST_BLEND, (int)BlendMode.Zero);
material.SetInteger(InternalProperties.DEST_BLEND2, (int)BlendMode.Zero);
// Caution: we need to setup One for src and Zero for Dst for all element as users could switch from transparent to Opaque and keep remaining value.
// Unity will disable Blending based on these default value.
// Note that for after postprocess we setup 0 in opacity inside the shaders, so we correctly end with 0 in opacity for the compositing pass
material.SetInteger(InternalProperties.ALPHA_SRC_BLEND, (int)BlendMode.One);
material.SetInteger(InternalProperties.ALPHA_DEST_BLEND, (int)BlendMode.Zero);
material.SetInteger(InternalProperties.ZWRITE, 1);
}
// Double sided
var isBackFaceEnable = material.GetInteger(InternalProperties.TRANSPARENT_BACKFACE_ENABLE) == 1 && surfaceType == SurfaceType.Transparent;
var doubleSidedEnable = cullMode == CullMode.Off;
if (doubleSidedEnable)
{
var doubleSidedNormalMode = (DoubleSidedMode)material.GetInteger(SurfaceOptions.DOUBLE_SIDED_NORMAL_MODE);
switch (doubleSidedNormalMode)
{
case DoubleSidedMode.None:
material.SetVector(InternalProperties.DOUBLE_SIDED_CONSTANTS, new Vector4(1.0f, 1.0f, 1.0f, 0.0f));
break;
case DoubleSidedMode.Mirror:
material.SetVector(InternalProperties.DOUBLE_SIDED_CONSTANTS, new Vector4(1.0f, 1.0f, -1.0f, 0.0f));
break;
case DoubleSidedMode.Flip:
material.SetVector(InternalProperties.DOUBLE_SIDED_CONSTANTS, new Vector4(-1.0f, -1.0f, -1.0f, 0.0f));
break;
}
}
if (isBackFaceEnable)
{
material.SetInt(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.
}
}
}