You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
17 KiB
325 lines
17 KiB
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEditor.Rendering.HighDefinition;
|
|
|
|
// Include material common properties names
|
|
using static UnityEngine.Rendering.HighDefinition.HDMaterialProperties;
|
|
|
|
namespace UnityEngine.Rendering.HighDefinition
|
|
{
|
|
abstract class BaseLitAPI
|
|
{
|
|
// Wind
|
|
protected const string kWindEnabled = "_EnableWind";
|
|
|
|
public static DisplacementMode GetFilteredDisplacementMode(Material material)
|
|
{
|
|
return material.GetFilteredDisplacementMode((DisplacementMode)material.GetFloat(kDisplacementMode));
|
|
}
|
|
|
|
// All Setup Keyword functions must be static. It allow to create script to automatically update the shaders with a script if code change
|
|
static public void SetupBaseLitKeywords(Material material)
|
|
{
|
|
material.SetupBaseUnlitKeywords();
|
|
|
|
bool doubleSidedEnable = material.HasProperty(kDoubleSidedEnable) ? material.GetFloat(kDoubleSidedEnable) > 0.0f : false;
|
|
if (doubleSidedEnable)
|
|
{
|
|
DoubleSidedNormalMode doubleSidedNormalMode = (DoubleSidedNormalMode)material.GetFloat(kDoubleSidedNormalMode);
|
|
switch (doubleSidedNormalMode)
|
|
{
|
|
case DoubleSidedNormalMode.Mirror: // Mirror mode (in tangent space)
|
|
material.SetVector("_DoubleSidedConstants", new Vector4(1.0f, 1.0f, -1.0f, 0.0f));
|
|
break;
|
|
|
|
case DoubleSidedNormalMode.Flip: // Flip mode (in tangent space)
|
|
material.SetVector("_DoubleSidedConstants", new Vector4(-1.0f, -1.0f, -1.0f, 0.0f));
|
|
break;
|
|
|
|
case DoubleSidedNormalMode.None: // None mode (in tangent space)
|
|
material.SetVector("_DoubleSidedConstants", new Vector4(1.0f, 1.0f, 1.0f, 0.0f));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Displacement Mapping
|
|
{
|
|
bool enableVertexDisplacement = false;
|
|
bool enablePixelDisplacement = false;
|
|
bool enableTessellationDisplacement = false;
|
|
bool displacementLockObjectScale = false;
|
|
bool displacementLockTilingScale = false;
|
|
bool enableDepthOffset = false;
|
|
bool conservativeDepthOffset = false;
|
|
|
|
bool enableDisplacement = material.HasProperty(kDisplacementMode) && (GetFilteredDisplacementMode(material) != DisplacementMode.None);
|
|
|
|
if (enableDisplacement)
|
|
{
|
|
var displacementMode = GetFilteredDisplacementMode(material);
|
|
|
|
enableVertexDisplacement = displacementMode == DisplacementMode.Vertex;
|
|
enablePixelDisplacement = displacementMode == DisplacementMode.Pixel;
|
|
enableTessellationDisplacement = displacementMode == DisplacementMode.Tessellation;
|
|
|
|
displacementLockObjectScale = material.GetFloat(kDisplacementLockObjectScale) > 0.0f;
|
|
displacementLockTilingScale = material.GetFloat(kDisplacementLockTilingScale) > 0.0f;
|
|
}
|
|
|
|
// Depth Offset may be used without Displacement Mapping as well (a Shader Graph feature).
|
|
if (enablePixelDisplacement || (!material.HasProperty(kDisplacementMode) && material.HasProperty(kDepthOffsetEnable)))
|
|
{
|
|
enableDepthOffset = material.GetFloat(kDepthOffsetEnable) > 0.0f;
|
|
}
|
|
|
|
if (enableDepthOffset && material.HasProperty(kConservativeDepthOffsetEnable))
|
|
{
|
|
conservativeDepthOffset = material.GetFloat(kConservativeDepthOffsetEnable) > 0.0f;
|
|
}
|
|
|
|
CoreUtils.SetKeyword(material, "_VERTEX_DISPLACEMENT", enableVertexDisplacement);
|
|
CoreUtils.SetKeyword(material, "_PIXEL_DISPLACEMENT", enablePixelDisplacement);
|
|
CoreUtils.SetKeyword(material, "_TESSELLATION_DISPLACEMENT", enableTessellationDisplacement);
|
|
|
|
// Tessellation reuse vertex flag.
|
|
CoreUtils.SetKeyword(material, "_VERTEX_DISPLACEMENT_LOCK_OBJECT_SCALE", displacementLockObjectScale && (enableVertexDisplacement || enableTessellationDisplacement));
|
|
CoreUtils.SetKeyword(material, "_PIXEL_DISPLACEMENT_LOCK_OBJECT_SCALE", displacementLockObjectScale && enablePixelDisplacement);
|
|
CoreUtils.SetKeyword(material, "_DISPLACEMENT_LOCK_TILING_SCALE", displacementLockTilingScale && enableDisplacement);
|
|
|
|
CoreUtils.SetKeyword(material, "_DEPTHOFFSET_ON", enableDepthOffset);
|
|
CoreUtils.SetKeyword(material, "_CONSERVATIVE_DEPTH_OFFSET", conservativeDepthOffset);
|
|
}
|
|
|
|
CoreUtils.SetKeyword(material, "_VERTEX_WIND", false);
|
|
|
|
material.SetupMainTexForAlphaTestGI("_BaseColorMap", "_BaseColor");
|
|
|
|
// Use negation so we don't create keyword by default
|
|
CoreUtils.SetKeyword(material, "_DISABLE_DECALS", material.HasProperty(kSupportDecals) && material.GetFloat(kSupportDecals) == 0.0f);
|
|
CoreUtils.SetKeyword(material, "_DISABLE_SSR", material.HasProperty(kReceivesSSR) && material.GetFloat(kReceivesSSR) == 0.0f);
|
|
CoreUtils.SetKeyword(material, "_DISABLE_SSR_TRANSPARENT", material.HasProperty(kReceivesSSRTransparent) && material.GetFloat(kReceivesSSRTransparent) == 0.0f);
|
|
CoreUtils.SetKeyword(material, "_ENABLE_GEOMETRIC_SPECULAR_AA", material.HasProperty(kEnableGeometricSpecularAA) && material.GetFloat(kEnableGeometricSpecularAA) == 1.0f);
|
|
|
|
if (material.HasProperty(kRefractionModel))
|
|
{
|
|
var refractionModel = material.GetRefractionModel();
|
|
CoreUtils.SetKeyword(material, "_REFRACTION_PLANE", refractionModel == ScreenSpaceRefraction.RefractionModel.Planar);
|
|
CoreUtils.SetKeyword(material, "_REFRACTION_SPHERE", refractionModel == ScreenSpaceRefraction.RefractionModel.Sphere);
|
|
CoreUtils.SetKeyword(material, "_REFRACTION_THIN", refractionModel == ScreenSpaceRefraction.RefractionModel.Thin);
|
|
}
|
|
}
|
|
|
|
static public bool CompatibleWithExcludeFromTUAndAA(SurfaceType surfaceType, int renderQueue)
|
|
{
|
|
return surfaceType == SurfaceType.Transparent && HDRenderQueue.k_RenderQueue_Transparent.Contains(renderQueue);
|
|
}
|
|
|
|
static public bool CompatibleWithExcludeFromTUAndAA(Material material)
|
|
{
|
|
return CompatibleWithExcludeFromTUAndAA(material.GetSurfaceType(), material.renderQueue) && material.HasProperty(kExcludeFromTUAndAA);
|
|
}
|
|
|
|
// WW1MOD: added composition mask on stencil user bit 0
|
|
static public void SetupStencil(Material material, bool receivesLighting, bool receivesSSR, bool useSplitLighting, bool excludeFromTUAndAA = false, bool compositionMask = false)
|
|
{
|
|
// To determine if the shader is forward only, we can't rely on the presence of GBuffer pass because that depends on the active subshader, which
|
|
// depends on the active render pipeline, giving an inconsistent result. The properties of a shader are always the same so it's ok to check them
|
|
bool forwardOnly = material.shader.FindPropertyIndex(kZTestGBuffer) == -1;
|
|
bool hasRefraction = material.GetRefractionModel() != ScreenSpaceRefraction.RefractionModel.None;
|
|
|
|
ComputeStencilProperties(
|
|
receivesLighting,
|
|
forwardOnly,
|
|
receivesSSR,
|
|
useSplitLighting,
|
|
hasRefraction,
|
|
excludeFromTUAndAA,
|
|
compositionMask, // WW1MOD
|
|
out int stencilRef,
|
|
out int stencilWriteMask,
|
|
out int stencilRefDepth,
|
|
out int stencilWriteMaskDepth,
|
|
out int stencilRefGBuffer,
|
|
out int stencilWriteMaskGBuffer,
|
|
out int stencilRefMV,
|
|
out int stencilWriteMaskMV);
|
|
|
|
// As we tag both during motion vector pass and Gbuffer pass we need a separate state and we need to use the write mask
|
|
if (material.HasProperty(kStencilRef))
|
|
{
|
|
material.SetInt(kStencilRef, stencilRef);
|
|
material.SetInt(kStencilWriteMask, stencilWriteMask);
|
|
}
|
|
if (material.HasProperty(kStencilRefDepth))
|
|
{
|
|
material.SetInt(kStencilRefDepth, stencilRefDepth);
|
|
material.SetInt(kStencilWriteMaskDepth, stencilWriteMaskDepth);
|
|
}
|
|
if (material.HasProperty(kStencilRefGBuffer))
|
|
{
|
|
material.SetInt(kStencilRefGBuffer, stencilRefGBuffer);
|
|
material.SetInt(kStencilWriteMaskGBuffer, stencilWriteMaskGBuffer);
|
|
}
|
|
if (material.HasProperty(kStencilRefDistortionVec))
|
|
{
|
|
material.SetInt(kStencilRefDistortionVec, (int)StencilUsage.DistortionVectors);
|
|
material.SetInt(kStencilWriteMaskDistortionVec, (int)StencilUsage.DistortionVectors);
|
|
}
|
|
if (material.HasProperty(kStencilRefMV))
|
|
{
|
|
material.SetInt(kStencilRefMV, stencilRefMV);
|
|
material.SetInt(kStencilWriteMaskMV, stencilWriteMaskMV);
|
|
}
|
|
}
|
|
|
|
static public void ComputeStencilProperties(
|
|
bool receivesLighting,
|
|
bool forwardOnly,
|
|
bool receivesSSR,
|
|
bool useSplitLighting,
|
|
bool hasRefraction,
|
|
bool excludeFromTUAndAA,
|
|
bool compositionMask, // WW1MOD
|
|
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;
|
|
}
|
|
|
|
// WW1MOD: added composition mask on stencil user bit 0
|
|
if (compositionMask)
|
|
{
|
|
stencilRefDepth |= (int)StencilUsage.UserBit0;
|
|
stencilRef |= (int)StencilUsage.UserBit0;
|
|
stencilWriteMask |= (int)StencilUsage.UserBit0;
|
|
stencilWriteMaskDepth |= (int)StencilUsage.UserBit0;
|
|
}
|
|
|
|
stencilWriteMaskDepth |= (int)StencilUsage.IsUnlit;
|
|
stencilWriteMaskGBuffer |= (int)StencilUsage.IsUnlit;
|
|
stencilWriteMaskMV |= (int)StencilUsage.IsUnlit;
|
|
}
|
|
|
|
static public void SetupBaseLitMaterialPass(Material material)
|
|
{
|
|
material.SetupBaseUnlitPass();
|
|
}
|
|
|
|
static public void SetupDisplacement(Material material, int layerCount = 1)
|
|
{
|
|
DisplacementMode displacementMode = GetFilteredDisplacementMode(material);
|
|
for (int i = 0; i < layerCount; i++)
|
|
{
|
|
var heightAmplitude = layerCount > 1 ? kHeightAmplitude + i : kHeightAmplitude;
|
|
var heightCenter = layerCount > 1 ? kHeightCenter + i : kHeightCenter;
|
|
if (material.HasProperty(heightAmplitude) && material.HasProperty(heightCenter))
|
|
{
|
|
var heightPoMAmplitude = layerCount > 1 ? kHeightPoMAmplitude + i : kHeightPoMAmplitude;
|
|
var heightParametrization = layerCount > 1 ? kHeightParametrization + i : kHeightParametrization;
|
|
var heightTessAmplitude = layerCount > 1 ? kHeightTessAmplitude + i : kHeightTessAmplitude;
|
|
var heightTessCenter = layerCount > 1 ? kHeightTessCenter + i : kHeightTessCenter;
|
|
var heightOffset = layerCount > 1 ? kHeightOffset + i : kHeightOffset;
|
|
var heightMin = layerCount > 1 ? kHeightMin + i : kHeightMin;
|
|
var heightMax = layerCount > 1 ? kHeightMax + i : kHeightMax;
|
|
|
|
if (displacementMode == DisplacementMode.Pixel)
|
|
{
|
|
material.SetFloat(heightAmplitude, material.GetFloat(heightPoMAmplitude) * 0.01f); // Convert centimeters to meters.
|
|
material.SetFloat(heightCenter, 1.0f); // PoM is always inward so base (0 height) is mapped to 1 in the texture
|
|
}
|
|
else
|
|
{
|
|
var parametrization = (HeightmapParametrization)material.GetFloat(heightParametrization);
|
|
if (parametrization == HeightmapParametrization.MinMax)
|
|
{
|
|
float offset = material.GetFloat(heightOffset);
|
|
float minHeight = material.GetFloat(heightMin);
|
|
float amplitude = material.GetFloat(heightMax) - minHeight;
|
|
|
|
material.SetFloat(heightAmplitude, amplitude * 0.01f); // Convert centimeters to meters.
|
|
material.SetFloat(heightCenter, -(minHeight + offset) / Mathf.Max(1e-6f, amplitude));
|
|
}
|
|
else
|
|
{
|
|
float offset = material.GetFloat(heightOffset);
|
|
float center = material.GetFloat(heightTessCenter);
|
|
float amplitude = material.GetFloat(heightTessAmplitude);
|
|
|
|
material.SetFloat(heightAmplitude, amplitude * 0.01f); // Convert centimeters to meters.
|
|
material.SetFloat(heightCenter, -offset / Mathf.Max(1e-6f, amplitude) + center);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // namespace UnityEditor
|