forked from BilalY/Rasagar
396 lines
23 KiB
C#
396 lines
23 KiB
C#
using System;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
// Include material common properties names
|
|
using static UnityEngine.Rendering.HighDefinition.HDMaterialProperties;
|
|
|
|
namespace UnityEngine.Rendering.HighDefinition
|
|
{
|
|
// Extension class to setup material keywords on unlit materials
|
|
static class BaseUnlitAPI
|
|
{
|
|
public static void SetupBaseUnlitKeywords(this Material material)
|
|
{
|
|
// First thing, be sure to have an up to date RenderQueue
|
|
material.ResetMaterialCustomRenderQueue();
|
|
|
|
bool alphaTestEnable = material.HasProperty(kAlphaCutoffEnabled) && material.GetFloat(kAlphaCutoffEnabled) > 0.0f;
|
|
CoreUtils.SetKeyword(material, "_ALPHATEST_ON", alphaTestEnable);
|
|
|
|
SurfaceType surfaceType = material.GetSurfaceType();
|
|
CoreUtils.SetKeyword(material, "_SURFACE_TYPE_TRANSPARENT", surfaceType == SurfaceType.Transparent);
|
|
|
|
bool refractiveSort = (surfaceType == SurfaceType.Transparent) && HDRenderQueue.k_RenderQueue_PreRefraction.Contains(material.renderQueue) && material.HasProperty(kPerPixelSorting) && material.GetInt(kPerPixelSorting) > 0;
|
|
CoreUtils.SetKeyword(material, "_TRANSPARENT_REFRACTIVE_SORT", refractiveSort);
|
|
|
|
bool transparentWritesMotionVec = (surfaceType == SurfaceType.Transparent) && !refractiveSort && material.HasProperty(kTransparentWritingMotionVec) && material.GetInt(kTransparentWritingMotionVec) > 0;
|
|
CoreUtils.SetKeyword(material, "_TRANSPARENT_WRITES_MOTION_VEC", transparentWritesMotionVec);
|
|
|
|
if (material.HasProperty(kAddPrecomputedVelocity))
|
|
CoreUtils.SetKeyword(material, "_ADD_PRECOMPUTED_VELOCITY", material.GetAddPrecomputedVelocity());
|
|
|
|
HDRenderQueue.RenderQueueType renderQueueType = HDRenderQueue.GetTypeByRenderQueueValue(material.renderQueue);
|
|
bool needOffScreenBlendFactor = renderQueueType == HDRenderQueue.RenderQueueType.AfterPostprocessTransparent || renderQueueType == HDRenderQueue.RenderQueueType.LowTransparent;
|
|
|
|
// Alpha tested materials always have a prepass where we perform the clip.
|
|
// Then during Gbuffer pass we don't perform the clip test, so we need to use depth equal in this case.
|
|
if (material.HasProperty(kZTestGBuffer))
|
|
{
|
|
if (alphaTestEnable)
|
|
{
|
|
material.SetInt(kZTestGBuffer, (int)UnityEngine.Rendering.CompareFunction.Equal);
|
|
}
|
|
else
|
|
{
|
|
material.SetInt(kZTestGBuffer, (int)UnityEngine.Rendering.CompareFunction.LessEqual);
|
|
}
|
|
}
|
|
|
|
// If the material use the kZTestDepthEqualForOpaque it mean it require depth equal test for opaque but transparent are not affected
|
|
if (material.HasProperty(kZTestDepthEqualForOpaque))
|
|
{
|
|
if (surfaceType == SurfaceType.Opaque)
|
|
{
|
|
// When the material is after post process, we need to use LEssEqual because there is no depth prepass for unlit opaque
|
|
if (HDRenderQueue.k_RenderQueue_AfterPostProcessOpaque.Contains(material.renderQueue))
|
|
material.SetInt(kZTestDepthEqualForOpaque, (int)UnityEngine.Rendering.CompareFunction.LessEqual);
|
|
else
|
|
material.SetInt(kZTestDepthEqualForOpaque, (int)UnityEngine.Rendering.CompareFunction.Equal);
|
|
}
|
|
else
|
|
material.SetInt(kZTestDepthEqualForOpaque, (int)material.GetTransparentZTest());
|
|
}
|
|
|
|
if (surfaceType == SurfaceType.Opaque)
|
|
{
|
|
material.SetOverrideTag("RenderType", alphaTestEnable ? "TransparentCutout" : "");
|
|
material.SetInt(HDShaderIDs._SrcBlend, (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt(HDShaderIDs._DstBlend, (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
material.SetInt(HDShaderIDs._DstBlend2, (int)UnityEngine.Rendering.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.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
material.SetInt(kZWrite, 1);
|
|
}
|
|
else
|
|
{
|
|
material.SetOverrideTag("RenderType", "Transparent");
|
|
material.SetInt(kZWrite, material.GetTransparentZWrite() ? 1 : 0);
|
|
material.SetInt(HDShaderIDs._DstBlend2, (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
|
|
if (material.HasProperty(kBlendMode))
|
|
{
|
|
var blendMode = material.GetBlendMode();
|
|
|
|
// When doing off-screen transparency accumulation, we change blend factors as described here: https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html
|
|
switch (blendMode)
|
|
{
|
|
// Alpha
|
|
// color: src * src_a + dst * (1 - src_a)
|
|
// src * src_a is done in the shader as it allow to reduce precision issue when using _BLENDMODE_PRESERVE_SPECULAR_LIGHTING (See Material.hlsl)
|
|
case BlendingMode.Alpha:
|
|
material.SetInt(HDShaderIDs._SrcBlend, (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt(HDShaderIDs._DstBlend, (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
if (needOffScreenBlendFactor)
|
|
{
|
|
material.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
material.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
}
|
|
else
|
|
{
|
|
material.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
}
|
|
break;
|
|
|
|
// Additive
|
|
// color: src * src_a + dst
|
|
// src * src_a is done in the shader
|
|
case BlendingMode.Additive:
|
|
material.SetInt(HDShaderIDs._SrcBlend, (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt(HDShaderIDs._DstBlend, (int)UnityEngine.Rendering.BlendMode.One);
|
|
if (needOffScreenBlendFactor)
|
|
{
|
|
material.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
material.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
}
|
|
else
|
|
{
|
|
material.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
}
|
|
break;
|
|
|
|
// PremultipliedAlpha
|
|
// color: src * src_a + dst * (1 - src_a)
|
|
// src is supposed to have been multiplied by alpha in the texture on artists side.
|
|
case BlendingMode.Premultiply:
|
|
material.SetInt(HDShaderIDs._SrcBlend, (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt(HDShaderIDs._DstBlend, (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
if (needOffScreenBlendFactor)
|
|
{
|
|
material.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
material.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
}
|
|
else
|
|
{
|
|
material.SetInt("_AlphaSrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_AlphaDstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool fogEnabled = material.HasProperty(kEnableFogOnTransparent) && material.GetFloat(kEnableFogOnTransparent) > 0.0f && surfaceType == SurfaceType.Transparent;
|
|
CoreUtils.SetKeyword(material, "_ENABLE_FOG_ON_TRANSPARENT", fogEnabled);
|
|
|
|
if (material.HasProperty(kDistortionEnable) && material.HasProperty(kDistortionBlendMode))
|
|
{
|
|
bool distortionDepthTest = material.GetFloat(kDistortionDepthTest) > 0.0f;
|
|
if (material.HasProperty(kZTestModeDistortion))
|
|
{
|
|
if (distortionDepthTest)
|
|
{
|
|
material.SetInt(kZTestModeDistortion, (int)UnityEngine.Rendering.CompareFunction.LessEqual);
|
|
}
|
|
else
|
|
{
|
|
material.SetInt(kZTestModeDistortion, (int)UnityEngine.Rendering.CompareFunction.Always);
|
|
}
|
|
}
|
|
|
|
var distortionBlendMode = material.GetInt(kDistortionBlendMode);
|
|
switch (distortionBlendMode)
|
|
{
|
|
default:
|
|
case 0: // Add
|
|
material.SetInt("_DistortionSrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_DistortionDstBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
|
|
material.SetInt("_DistortionBlurSrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_DistortionBlurDstBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_DistortionBlurBlendOp", (int)UnityEngine.Rendering.BlendOp.Add);
|
|
break;
|
|
|
|
case 1: // Multiply
|
|
material.SetInt("_DistortionSrcBlend", (int)UnityEngine.Rendering.BlendMode.DstColor);
|
|
material.SetInt("_DistortionDstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
|
|
material.SetInt("_DistortionBlurSrcBlend", (int)UnityEngine.Rendering.BlendMode.DstAlpha);
|
|
material.SetInt("_DistortionBlurDstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
material.SetInt("_DistortionBlurBlendOp", (int)UnityEngine.Rendering.BlendOp.Add);
|
|
break;
|
|
|
|
case 2: // Replace
|
|
material.SetInt("_DistortionSrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_DistortionDstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
|
|
material.SetInt("_DistortionBlurSrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
material.SetInt("_DistortionBlurDstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
material.SetInt("_DistortionBlurBlendOp", (int)UnityEngine.Rendering.BlendOp.Add);
|
|
break;
|
|
}
|
|
}
|
|
|
|
CullMode doubleSidedOffMode = (surfaceType == SurfaceType.Transparent) ? material.GetTransparentCullMode() : material.GetOpaqueCullMode();
|
|
|
|
bool isBackFaceEnable = material.HasProperty(kTransparentBackfaceEnable) && material.GetFloat(kTransparentBackfaceEnable) > 0.0f && surfaceType == SurfaceType.Transparent;
|
|
bool doubleSidedEnable = material.HasProperty(kDoubleSidedEnable) && material.GetFloat(kDoubleSidedEnable) > 0.0f;
|
|
|
|
DoubleSidedGIMode doubleSidedGIMode = DoubleSidedGIMode.Auto;
|
|
if (material.HasProperty(kDoubleSidedGIMode))
|
|
{
|
|
doubleSidedGIMode = (DoubleSidedGIMode)material.GetFloat(kDoubleSidedGIMode);
|
|
}
|
|
|
|
// Disable culling if double sided
|
|
material.SetInt("_CullMode", doubleSidedEnable ? (int)UnityEngine.Rendering.CullMode.Off : (int)doubleSidedOffMode);
|
|
|
|
// We have a separate cullmode (_CullModeForward) for Forward in case we use backface then frontface rendering, need to configure it
|
|
if (isBackFaceEnable)
|
|
{
|
|
material.SetInt("_CullModeForward", (int)UnityEngine.Rendering.CullMode.Back);
|
|
}
|
|
else
|
|
{
|
|
material.SetInt("_CullModeForward", (int)(doubleSidedEnable ? UnityEngine.Rendering.CullMode.Off : doubleSidedOffMode));
|
|
}
|
|
|
|
CoreUtils.SetKeyword(material, "_DOUBLESIDED_ON", doubleSidedEnable);
|
|
|
|
// A material's GI flag internally keeps track of whether emission is enabled at all, it's enabled but has no effect
|
|
// or is enabled and may be modified at runtime. This state depends on the values of the current flag and emissive color.
|
|
// The fixup routine makes sure that the material is in the correct state if/when changes are made to the mode or color.
|
|
if (material.HasProperty(kEmissionColor))
|
|
{
|
|
material.SetColor(kEmissionColor, Color.white); // kEmissionColor must always be white to allow our own material to control the GI (this allow to fallback from builtin unity to our system).
|
|
// as it happen with old material that it isn't the case, we force it.
|
|
#if UNITY_EDITOR
|
|
UnityEditor.MaterialEditor.FixupEmissiveFlag(material);
|
|
#endif
|
|
}
|
|
|
|
material.SetupMainTexForAlphaTestGI("_UnlitColorMap", "_UnlitColor");
|
|
|
|
// depth offset for ShaderGraphs (they don't have the displacement mode property)
|
|
if (!material.HasProperty(kDisplacementMode) && material.HasProperty(kDepthOffsetEnable))
|
|
{
|
|
// Depth offset is only enabled if per pixel displacement is
|
|
bool depthOffsetEnable = (material.GetFloat(kDepthOffsetEnable) > 0.0f);
|
|
CoreUtils.SetKeyword(material, "_DEPTHOFFSET_ON", depthOffsetEnable);
|
|
|
|
// conservative depth offset for ShaderGraphs
|
|
if (material.HasProperty(kConservativeDepthOffsetEnable))
|
|
{
|
|
// Depth offset is only enabled if per pixel displacement is
|
|
bool conservativeDepthOffset = (material.GetFloat(kConservativeDepthOffsetEnable) > 0.0f);
|
|
CoreUtils.SetKeyword(material, "_CONSERVATIVE_DEPTH_OFFSET", conservativeDepthOffset);
|
|
}
|
|
}
|
|
|
|
if (material.HasProperty(kTessellationMode))
|
|
{
|
|
TessellationMode tessMode = (TessellationMode)material.GetFloat(kTessellationMode);
|
|
CoreUtils.SetKeyword(material, "_TESSELLATION_PHONG", tessMode == TessellationMode.Phong);
|
|
}
|
|
|
|
// DoubleSidedGI has to be synced with our double sided toggle
|
|
if (doubleSidedGIMode == DoubleSidedGIMode.Auto)
|
|
material.doubleSidedGI = doubleSidedEnable;
|
|
else if (doubleSidedGIMode == DoubleSidedGIMode.On)
|
|
material.doubleSidedGI = true;
|
|
else if (doubleSidedGIMode == DoubleSidedGIMode.Off)
|
|
material.doubleSidedGI = false;
|
|
}
|
|
|
|
// This is a hack for GI. PVR looks in the shader for a texture named "_MainTex" to extract the opacity of the material for baking. In the same manner, "_Cutoff" and "_Color" are also necessary.
|
|
// Since we don't have those parameters in our shaders we need to provide a "fake" useless version of them with the right values for the GI to work.
|
|
public static void SetupMainTexForAlphaTestGI(this Material material, string colorMapPropertyName, string colorPropertyName)
|
|
{
|
|
if (material.HasProperty(colorMapPropertyName))
|
|
{
|
|
var mainTex = material.GetTexture(colorMapPropertyName);
|
|
var mainTexScale = material.GetTextureScale(colorMapPropertyName);
|
|
var mainTexOffset = material.GetTextureOffset(colorMapPropertyName);
|
|
material.SetTexture("_MainTex", mainTex);
|
|
material.SetTextureScale("_MainTex", mainTexScale);
|
|
material.SetTextureOffset("_MainTex", mainTexOffset);
|
|
}
|
|
|
|
if (material.HasProperty(colorPropertyName))
|
|
{
|
|
var color = material.GetColor(colorPropertyName);
|
|
material.SetColor("_Color", color);
|
|
}
|
|
|
|
if (material.HasProperty(kAlphaCutoff)) // Same for all our materials
|
|
{
|
|
var cutoff = material.GetFloat(kAlphaCutoff);
|
|
material.SetFloat(kCutoff, cutoff);
|
|
}
|
|
}
|
|
|
|
static public void SetupBaseUnlitPass(this Material material)
|
|
{
|
|
if (HDMaterial.IsShaderGraph(material))
|
|
{
|
|
// Shader graph generate distortion pass only if required. So we can safely enable it
|
|
// all the time here.
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_DistortionVectorsStr, true);
|
|
}
|
|
else if (material.HasProperty(kDistortionEnable))
|
|
{
|
|
bool distortionEnable = material.GetFloat(kDistortionEnable) > 0.0f && ((SurfaceType)material.GetFloat(kSurfaceType) == SurfaceType.Transparent);
|
|
|
|
bool distortionOnly = false;
|
|
if (material.HasProperty(kDistortionOnly))
|
|
{
|
|
distortionOnly = material.GetFloat(kDistortionOnly) > 0.0f;
|
|
}
|
|
|
|
// If distortion only is enabled, disable all passes (except distortion and debug)
|
|
bool enablePass = !(distortionEnable && distortionOnly);
|
|
|
|
// Disable all passes except distortion
|
|
// Distortion is setup in code above
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_ForwardStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_DepthOnlyStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_DepthForwardOnlyStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_ForwardOnlyStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_GBufferStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_GBufferWithPrepassStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_DistortionVectorsStr, distortionEnable); // note: use distortionEnable
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_TransparentDepthPrepassStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_TransparentBackfaceStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_TransparentDepthPostpassStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_RayTracingPrepassStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_MetaStr, enablePass);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_ShadowCasterStr, enablePass);
|
|
}
|
|
|
|
if (material.HasProperty(kTransparentDepthPrepassEnable))
|
|
{
|
|
bool isTransparent = material.GetSurfaceType() == SurfaceType.Transparent;
|
|
bool depthWriteEnable = material.GetFloat(kTransparentDepthPrepassEnable) > 0.0f;
|
|
bool ssrTransparent = material.ReceiveSSRTransparent();
|
|
bool isRefractive = material.GetRefractionModel() != ScreenSpaceRefraction.RefractionModel.None;
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_TransparentDepthPrepassStr, isTransparent && (depthWriteEnable || ssrTransparent || isRefractive));
|
|
}
|
|
|
|
if (material.HasProperty(kTransparentDepthPostpassEnable))
|
|
{
|
|
bool depthWriteEnable = (material.GetFloat(kTransparentDepthPostpassEnable) > 0.0f) && ((SurfaceType)material.GetFloat(kSurfaceType) == SurfaceType.Transparent);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_TransparentDepthPostpassStr, depthWriteEnable);
|
|
}
|
|
|
|
if (material.HasProperty(kTransparentBackfaceEnable))
|
|
{
|
|
bool backFaceEnable = (material.GetFloat(kTransparentBackfaceEnable) > 0.0f) && ((SurfaceType)material.GetFloat(kSurfaceType) == SurfaceType.Transparent);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_TransparentBackfaceStr, backFaceEnable);
|
|
}
|
|
|
|
if (material.HasProperty(kRayTracing))
|
|
{
|
|
bool rayTracingEnable = (material.GetFloat(kRayTracing) > 0.0f);
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_RayTracingPrepassStr, rayTracingEnable);
|
|
}
|
|
|
|
bool allowMotionVectorPass = true;
|
|
if (HDMaterial.IsShaderGraph(material))
|
|
{
|
|
// We have no way to setup motion vector pass to be false by default for a shader graph
|
|
// So here we workaround it with materialTag system by checking if a tag exist to know if it is
|
|
// the first time we display this information. And thus setup the MotionVector Pass to false.
|
|
const string materialTag = "MotionVector";
|
|
const string defaultTag = "Nothing";
|
|
|
|
if (material.GetTag(materialTag, false, defaultTag) == defaultTag)
|
|
{
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_MotionVectorsStr, false);
|
|
material.SetOverrideTag(materialTag, "User");
|
|
}
|
|
|
|
allowMotionVectorPass = !material.GetShaderPassEnabled(HDShaderPassNames.s_MotionVectorsStr);
|
|
}
|
|
|
|
if (allowMotionVectorPass)
|
|
{
|
|
//In the case of additional velocity data we will enable the motion vector pass.
|
|
bool addPrecomputedVelocity = material.GetAddPrecomputedVelocity();
|
|
|
|
// We don't have any vertex animation for lit/unlit vector, so we
|
|
// setup motion vector pass to false. Remind that in HDRP this
|
|
// doesn't disable motion vector, it just mean that the material
|
|
// don't do any vertex deformation but we can still have
|
|
// skinning / morph target
|
|
material.SetShaderPassEnabled(HDShaderPassNames.s_MotionVectorsStr, addPrecomputedVelocity);
|
|
}
|
|
}
|
|
}
|
|
}
|