Firstborn/Library/PackageCache/com.unity.render-pipelines..../Editor/ShaderGraph/Targets/UniversalLitSubTarget.cs

920 lines
42 KiB
C#
Raw Normal View History

2023-03-28 13:24:16 -04:00
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.ShaderGraph;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using UnityEditor.ShaderGraph.Legacy;
using static UnityEditor.Rendering.Universal.ShaderGraph.SubShaderUtils;
using UnityEngine.Rendering.Universal;
using static Unity.Rendering.Universal.ShaderUtils;
namespace UnityEditor.Rendering.Universal.ShaderGraph
{
sealed class UniversalLitSubTarget : UniversalSubTarget, ILegacyTarget
{
static readonly GUID kSourceCodeGuid = new GUID("d6c78107b64145745805d963de80cc17"); // UniversalLitSubTarget.cs
[SerializeField]
WorkflowMode m_WorkflowMode = WorkflowMode.Metallic;
[SerializeField]
NormalDropOffSpace m_NormalDropOffSpace = NormalDropOffSpace.Tangent;
[SerializeField]
bool m_ClearCoat = false;
public UniversalLitSubTarget()
{
displayName = "Lit";
}
protected override ShaderID shaderID => ShaderID.SG_Lit;
public WorkflowMode workflowMode
{
get => m_WorkflowMode;
set => m_WorkflowMode = value;
}
public NormalDropOffSpace normalDropOffSpace
{
get => m_NormalDropOffSpace;
set => m_NormalDropOffSpace = value;
}
public bool clearCoat
{
get => m_ClearCoat;
set => m_ClearCoat = value;
}
private bool complexLit
{
get
{
// Rules for switching to ComplexLit with forward only pass
return clearCoat; // && <complex feature>
}
}
public override bool IsActive() => true;
public override void Setup(ref TargetSetupContext context)
{
context.AddAssetDependency(kSourceCodeGuid, AssetCollection.Flags.SourceDependency);
base.Setup(ref context);
var universalRPType = typeof(UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset);
if (!context.HasCustomEditorForRenderPipeline(universalRPType))
{
var gui = typeof(ShaderGraphLitGUI);
#if HAS_VFX_GRAPH
if (TargetsVFX())
gui = typeof(VFXShaderGraphLitGUI);
#endif
context.AddCustomEditorForRenderPipeline(gui.FullName, universalRPType);
}
// Process SubShaders
context.AddSubShader(PostProcessSubShader(SubShaders.LitComputeDotsSubShader(target, workflowMode, target.renderType, target.renderQueue, complexLit)));
context.AddSubShader(PostProcessSubShader(SubShaders.LitGLESSubShader(target, workflowMode, target.renderType, target.renderQueue, complexLit)));
}
public override void ProcessPreviewMaterial(Material material)
{
if (target.allowMaterialOverride)
{
// copy our target's default settings into the material
// (technically not necessary since we are always recreating the material from the shader each time,
// which will pull over the defaults from the shader definition)
// but if that ever changes, this will ensure the defaults are set
material.SetFloat(Property.SpecularWorkflowMode, (float)workflowMode);
material.SetFloat(Property.CastShadows, target.castShadows ? 1.0f : 0.0f);
material.SetFloat(Property.ReceiveShadows, target.receiveShadows ? 1.0f : 0.0f);
material.SetFloat(Property.SurfaceType, (float)target.surfaceType);
material.SetFloat(Property.BlendMode, (float)target.alphaMode);
material.SetFloat(Property.AlphaClip, target.alphaClip ? 1.0f : 0.0f);
material.SetFloat(Property.CullMode, (int)target.renderFace);
material.SetFloat(Property.ZWriteControl, (float)target.zWriteControl);
material.SetFloat(Property.ZTest, (float)target.zTestMode);
}
// We always need these properties regardless of whether the material is allowed to override
// Queue control & offset enable correct automatic render queue behavior
// Control == 0 is automatic, 1 is user-specified render queue
material.SetFloat(Property.QueueOffset, 0.0f);
material.SetFloat(Property.QueueControl, (float)BaseShaderGUI.QueueControl.Auto);
// call the full unlit material setup function
ShaderGraphLitGUI.UpdateMaterial(material, MaterialUpdateType.CreatedNewMaterial);
}
public override void GetFields(ref TargetFieldContext context)
{
base.GetFields(ref context);
var descs = context.blocks.Select(x => x.descriptor);
// Lit -- always controlled by subtarget
context.AddField(UniversalFields.NormalDropOffOS, normalDropOffSpace == NormalDropOffSpace.Object);
context.AddField(UniversalFields.NormalDropOffTS, normalDropOffSpace == NormalDropOffSpace.Tangent);
context.AddField(UniversalFields.NormalDropOffWS, normalDropOffSpace == NormalDropOffSpace.World);
context.AddField(UniversalFields.Normal, descs.Contains(BlockFields.SurfaceDescription.NormalOS) ||
descs.Contains(BlockFields.SurfaceDescription.NormalTS) ||
descs.Contains(BlockFields.SurfaceDescription.NormalWS));
// Complex Lit
// Template Predicates
//context.AddField(UniversalFields.PredicateClearCoat, clearCoat);
}
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
{
context.AddBlock(BlockFields.SurfaceDescription.Smoothness);
context.AddBlock(BlockFields.SurfaceDescription.NormalOS, normalDropOffSpace == NormalDropOffSpace.Object);
context.AddBlock(BlockFields.SurfaceDescription.NormalTS, normalDropOffSpace == NormalDropOffSpace.Tangent);
context.AddBlock(BlockFields.SurfaceDescription.NormalWS, normalDropOffSpace == NormalDropOffSpace.World);
context.AddBlock(BlockFields.SurfaceDescription.Emission);
context.AddBlock(BlockFields.SurfaceDescription.Occlusion);
// when the surface options are material controlled, we must show all of these blocks
// when target controlled, we can cull the unnecessary blocks
context.AddBlock(BlockFields.SurfaceDescription.Specular, (workflowMode == WorkflowMode.Specular) || target.allowMaterialOverride);
context.AddBlock(BlockFields.SurfaceDescription.Metallic, (workflowMode == WorkflowMode.Metallic) || target.allowMaterialOverride);
context.AddBlock(BlockFields.SurfaceDescription.Alpha, (target.surfaceType == SurfaceType.Transparent || target.alphaClip) || target.allowMaterialOverride);
context.AddBlock(BlockFields.SurfaceDescription.AlphaClipThreshold, (target.alphaClip) || target.allowMaterialOverride);
// always controlled by subtarget clearCoat checkbox (no Material control)
context.AddBlock(BlockFields.SurfaceDescription.CoatMask, clearCoat);
context.AddBlock(BlockFields.SurfaceDescription.CoatSmoothness, clearCoat);
}
public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode)
{
// if using material control, add the material property to control workflow mode
if (target.allowMaterialOverride)
{
collector.AddFloatProperty(Property.SpecularWorkflowMode, (float)workflowMode);
collector.AddFloatProperty(Property.CastShadows, target.castShadows ? 1.0f : 0.0f);
collector.AddFloatProperty(Property.ReceiveShadows, target.receiveShadows ? 1.0f : 0.0f);
// setup properties using the defaults
collector.AddFloatProperty(Property.SurfaceType, (float)target.surfaceType);
collector.AddFloatProperty(Property.BlendMode, (float)target.alphaMode);
collector.AddFloatProperty(Property.AlphaClip, target.alphaClip ? 1.0f : 0.0f);
collector.AddFloatProperty(Property.SrcBlend, 1.0f); // always set by material inspector, ok to have incorrect values here
collector.AddFloatProperty(Property.DstBlend, 0.0f); // always set by material inspector, ok to have incorrect values here
collector.AddToggleProperty(Property.ZWrite, (target.surfaceType == SurfaceType.Opaque));
collector.AddFloatProperty(Property.ZWriteControl, (float)target.zWriteControl);
collector.AddFloatProperty(Property.ZTest, (float)target.zTestMode); // ztest mode is designed to directly pass as ztest
collector.AddFloatProperty(Property.CullMode, (float)target.renderFace); // render face enum is designed to directly pass as a cull mode
}
// We always need these properties regardless of whether the material is allowed to override other shader properties.
// Queue control & offset enable correct automatic render queue behavior. Control == 0 is automatic, 1 is user-specified.
// We initialize queue control to -1 to indicate to UpdateMaterial that it needs to initialize it properly on the material.
collector.AddFloatProperty(Property.QueueOffset, 0.0f);
collector.AddFloatProperty(Property.QueueControl, -1.0f);
}
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
{
var universalTarget = (target as UniversalTarget);
universalTarget.AddDefaultMaterialOverrideGUI(ref context, onChange, registerUndo);
context.AddProperty("Workflow Mode", new EnumField(WorkflowMode.Metallic) { value = workflowMode }, (evt) =>
{
if (Equals(workflowMode, evt.newValue))
return;
registerUndo("Change Workflow");
workflowMode = (WorkflowMode)evt.newValue;
onChange();
});
universalTarget.AddDefaultSurfacePropertiesGUI(ref context, onChange, registerUndo, showReceiveShadows: true);
context.AddProperty("Fragment Normal Space", new EnumField(NormalDropOffSpace.Tangent) { value = normalDropOffSpace }, (evt) =>
{
if (Equals(normalDropOffSpace, evt.newValue))
return;
registerUndo("Change Fragment Normal Space");
normalDropOffSpace = (NormalDropOffSpace)evt.newValue;
onChange();
});
context.AddProperty("Clear Coat", new Toggle() { value = clearCoat }, (evt) =>
{
if (Equals(clearCoat, evt.newValue))
return;
registerUndo("Change Clear Coat");
clearCoat = evt.newValue;
onChange();
});
}
protected override int ComputeMaterialNeedsUpdateHash()
{
int hash = base.ComputeMaterialNeedsUpdateHash();
hash = hash * 23 + target.allowMaterialOverride.GetHashCode();
return hash;
}
public bool TryUpgradeFromMasterNode(IMasterNode1 masterNode, out Dictionary<BlockFieldDescriptor, int> blockMap)
{
blockMap = null;
if (!(masterNode is PBRMasterNode1 pbrMasterNode))
return false;
m_WorkflowMode = (WorkflowMode)pbrMasterNode.m_Model;
m_NormalDropOffSpace = (NormalDropOffSpace)pbrMasterNode.m_NormalDropOffSpace;
// Handle mapping of Normal block specifically
BlockFieldDescriptor normalBlock;
switch (m_NormalDropOffSpace)
{
case NormalDropOffSpace.Object:
normalBlock = BlockFields.SurfaceDescription.NormalOS;
break;
case NormalDropOffSpace.World:
normalBlock = BlockFields.SurfaceDescription.NormalWS;
break;
default:
normalBlock = BlockFields.SurfaceDescription.NormalTS;
break;
}
// Set blockmap
blockMap = new Dictionary<BlockFieldDescriptor, int>()
{
{ BlockFields.VertexDescription.Position, 9 },
{ BlockFields.VertexDescription.Normal, 10 },
{ BlockFields.VertexDescription.Tangent, 11 },
{ BlockFields.SurfaceDescription.BaseColor, 0 },
{ normalBlock, 1 },
{ BlockFields.SurfaceDescription.Emission, 4 },
{ BlockFields.SurfaceDescription.Smoothness, 5 },
{ BlockFields.SurfaceDescription.Occlusion, 6 },
{ BlockFields.SurfaceDescription.Alpha, 7 },
{ BlockFields.SurfaceDescription.AlphaClipThreshold, 8 },
};
// PBRMasterNode adds/removes Metallic/Specular based on settings
if (m_WorkflowMode == WorkflowMode.Specular)
blockMap.Add(BlockFields.SurfaceDescription.Specular, 3);
else if (m_WorkflowMode == WorkflowMode.Metallic)
blockMap.Add(BlockFields.SurfaceDescription.Metallic, 2);
return true;
}
#region SubShader
static class SubShaders
{
// SM 4.5, compute with dots instancing
public static SubShaderDescriptor LitComputeDotsSubShader(UniversalTarget target, WorkflowMode workflowMode, string renderType, string renderQueue, bool complexLit)
{
SubShaderDescriptor result = new SubShaderDescriptor()
{
pipelineTag = UniversalTarget.kPipelineTag,
customTags = UniversalTarget.kLitMaterialTypeTag,
renderType = renderType,
renderQueue = renderQueue,
generatesPreview = true,
passes = new PassCollection()
};
if (complexLit)
result.passes.Add(LitPasses.ForwardOnly(target, workflowMode, complexLit, CoreBlockMasks.Vertex, LitBlockMasks.FragmentComplexLit, CorePragmas.DOTSForward));
else
result.passes.Add(LitPasses.Forward(target, workflowMode, CorePragmas.DOTSForward));
if (!complexLit)
result.passes.Add(LitPasses.GBuffer(target, workflowMode));
// cull the shadowcaster pass if we know it will never be used
if (target.castShadows || target.allowMaterialOverride)
result.passes.Add(PassVariant(CorePasses.ShadowCaster(target), CorePragmas.DOTSInstanced));
if (target.mayWriteDepth)
result.passes.Add(PassVariant(CorePasses.DepthOnly(target), CorePragmas.DOTSInstanced));
if (complexLit)
result.passes.Add(PassVariant(LitPasses.DepthNormalOnly(target), CorePragmas.DOTSInstanced));
else
result.passes.Add(PassVariant(LitPasses.DepthNormal(target), CorePragmas.DOTSInstanced));
result.passes.Add(PassVariant(LitPasses.Meta(target), CorePragmas.DOTSDefault));
// Currently neither of these passes (selection/picking) can be last for the game view for
// UI shaders to render correctly. Verify [1352225] before changing this order.
result.passes.Add(PassVariant(CorePasses.SceneSelection(target), CorePragmas.DOTSDefault));
result.passes.Add(PassVariant(CorePasses.ScenePicking(target), CorePragmas.DOTSDefault));
result.passes.Add(PassVariant(LitPasses._2D(target), CorePragmas.DOTSDefault));
return result;
}
public static SubShaderDescriptor LitGLESSubShader(UniversalTarget target, WorkflowMode workflowMode, string renderType, string renderQueue, bool complexLit)
{
// SM 2.0, GLES
// ForwardOnly pass is used as complex Lit SM 2.0 fallback for GLES.
// Drops advanced features and renders materials as Lit.
SubShaderDescriptor result = new SubShaderDescriptor()
{
pipelineTag = UniversalTarget.kPipelineTag,
customTags = UniversalTarget.kLitMaterialTypeTag,
renderType = renderType,
renderQueue = renderQueue,
generatesPreview = true,
passes = new PassCollection()
};
if (complexLit)
result.passes.Add(LitPasses.ForwardOnly(target, workflowMode, complexLit, CoreBlockMasks.Vertex, LitBlockMasks.FragmentComplexLit, CorePragmas.Forward));
else
result.passes.Add(LitPasses.Forward(target, workflowMode));
// cull the shadowcaster pass if we know it will never be used
if (target.castShadows || target.allowMaterialOverride)
result.passes.Add(CorePasses.ShadowCaster(target));
if (target.mayWriteDepth)
result.passes.Add(CorePasses.DepthOnly(target));
if (complexLit)
result.passes.Add(CorePasses.DepthNormalOnly(target));
else
result.passes.Add(CorePasses.DepthNormal(target));
result.passes.Add(LitPasses.Meta(target));
// Currently neither of these passes (selection/picking) can be last for the game view for
// UI shaders to render correctly. Verify [1352225] before changing this order.
result.passes.Add(CorePasses.SceneSelection(target));
result.passes.Add(CorePasses.ScenePicking(target));
result.passes.Add(LitPasses._2D(target));
return result;
}
}
#endregion
#region Passes
static class LitPasses
{
static void AddWorkflowModeControlToPass(ref PassDescriptor pass, UniversalTarget target, WorkflowMode workflowMode)
{
if (target.allowMaterialOverride)
pass.keywords.Add(LitDefines.SpecularSetup);
else if (workflowMode == WorkflowMode.Specular)
pass.defines.Add(LitDefines.SpecularSetup, 1);
}
static void AddReceiveShadowsControlToPass(ref PassDescriptor pass, UniversalTarget target, bool receiveShadows)
{
if (target.allowMaterialOverride)
pass.keywords.Add(LitKeywords.ReceiveShadowsOff);
else if (!receiveShadows)
pass.defines.Add(LitKeywords.ReceiveShadowsOff, 1);
}
public static PassDescriptor Forward(UniversalTarget target, WorkflowMode workflowMode, PragmaCollection pragmas = null)
{
var result = new PassDescriptor()
{
// Definition
displayName = "Universal Forward",
referenceName = "SHADERPASS_FORWARD",
lightMode = "UniversalForward",
useInPreview = true,
// Template
passTemplatePath = UniversalTarget.kUberTemplatePath,
sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = LitBlockMasks.FragmentLit,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.Forward,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.UberSwitchedRenderState(target),
pragmas = pragmas ?? CorePragmas.Forward, // NOTE: SM 2.0 only GL
defines = new DefineCollection() { CoreDefines.UseFragmentFog },
keywords = new KeywordCollection() { LitKeywords.Forward },
includes = LitIncludes.Forward,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
CorePasses.AddTargetSurfaceControlsToPass(ref result, target);
AddWorkflowModeControlToPass(ref result, target, workflowMode);
AddReceiveShadowsControlToPass(ref result, target, target.receiveShadows);
return result;
}
public static PassDescriptor ForwardOnly(
UniversalTarget target,
WorkflowMode workflowMode,
bool complexLit,
BlockFieldDescriptor[] vertexBlocks,
BlockFieldDescriptor[] pixelBlocks,
PragmaCollection pragmas)
{
var result = new PassDescriptor
{
// Definition
displayName = "Universal Forward Only",
referenceName = "SHADERPASS_FORWARDONLY",
lightMode = "UniversalForwardOnly",
useInPreview = true,
// Template
passTemplatePath = UniversalTarget.kUberTemplatePath,
sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = vertexBlocks,
validPixelBlocks = pixelBlocks,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.Forward,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.UberSwitchedRenderState(target),
pragmas = pragmas,
defines = new DefineCollection() { CoreDefines.UseFragmentFog },
keywords = new KeywordCollection() { LitKeywords.Forward },
includes = LitIncludes.Forward,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
if (complexLit)
result.defines.Add(LitDefines.ClearCoat, 1);
CorePasses.AddTargetSurfaceControlsToPass(ref result, target);
AddWorkflowModeControlToPass(ref result, target, workflowMode);
AddReceiveShadowsControlToPass(ref result, target, target.receiveShadows);
return result;
}
// Deferred only in SM4.5, MRT not supported in GLES2
public static PassDescriptor GBuffer(UniversalTarget target, WorkflowMode workflowMode)
{
var result = new PassDescriptor
{
// Definition
displayName = "GBuffer",
referenceName = "SHADERPASS_GBUFFER",
lightMode = "UniversalGBuffer",
// Template
passTemplatePath = UniversalTarget.kUberTemplatePath,
sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = LitBlockMasks.FragmentLit,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.GBuffer,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.UberSwitchedRenderState(target),
pragmas = CorePragmas.DOTSGBuffer,
defines = new DefineCollection() { CoreDefines.UseFragmentFog },
keywords = new KeywordCollection() { LitKeywords.GBuffer },
includes = LitIncludes.GBuffer,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
CorePasses.AddTargetSurfaceControlsToPass(ref result, target);
AddWorkflowModeControlToPass(ref result, target, workflowMode);
AddReceiveShadowsControlToPass(ref result, target, target.receiveShadows);
return result;
}
public static PassDescriptor Meta(UniversalTarget target)
{
var result = new PassDescriptor()
{
// Definition
displayName = "Meta",
referenceName = "SHADERPASS_META",
lightMode = "Meta",
// Template
passTemplatePath = UniversalTarget.kUberTemplatePath,
sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = LitBlockMasks.FragmentMeta,
// Fields
structs = CoreStructCollections.Default,
requiredFields = LitRequiredFields.Meta,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.Meta,
pragmas = CorePragmas.Default,
defines = new DefineCollection() { CoreDefines.UseFragmentFog },
keywords = new KeywordCollection() { CoreKeywordDescriptors.EditorVisualization },
includes = LitIncludes.Meta,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
CorePasses.AddAlphaClipControlToPass(ref result, target);
return result;
}
public static PassDescriptor _2D(UniversalTarget target)
{
var result = new PassDescriptor()
{
// Definition
referenceName = "SHADERPASS_2D",
lightMode = "Universal2D",
// Template
passTemplatePath = UniversalTarget.kUberTemplatePath,
sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = CoreBlockMasks.FragmentColorAlpha,
// Fields
structs = CoreStructCollections.Default,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.UberSwitchedRenderState(target),
pragmas = CorePragmas.Instanced,
defines = new DefineCollection(),
keywords = new KeywordCollection(),
includes = LitIncludes._2D,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
CorePasses.AddAlphaClipControlToPass(ref result, target);
return result;
}
public static PassDescriptor DepthNormal(UniversalTarget target)
{
var result = new PassDescriptor()
{
// Definition
displayName = "DepthNormals",
referenceName = "SHADERPASS_DEPTHNORMALS",
lightMode = "DepthNormals",
useInPreview = false,
// Template
passTemplatePath = UniversalTarget.kUberTemplatePath,
sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = CoreBlockMasks.FragmentDepthNormals,
// Fields
structs = CoreStructCollections.Default,
requiredFields = CoreRequiredFields.DepthNormals,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.DepthNormalsOnly(target),
pragmas = CorePragmas.Instanced,
defines = new DefineCollection(),
keywords = new KeywordCollection(),
includes = CoreIncludes.DepthNormalsOnly,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
CorePasses.AddAlphaClipControlToPass(ref result, target);
return result;
}
public static PassDescriptor DepthNormalOnly(UniversalTarget target)
{
var result = new PassDescriptor()
{
// Definition
displayName = "DepthNormalsOnly",
referenceName = "SHADERPASS_DEPTHNORMALSONLY",
lightMode = "DepthNormalsOnly",
useInPreview = false,
// Template
passTemplatePath = UniversalTarget.kUberTemplatePath,
sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories,
// Port Mask
validVertexBlocks = CoreBlockMasks.Vertex,
validPixelBlocks = CoreBlockMasks.FragmentDepthNormals,
// Fields
structs = CoreStructCollections.Default,
requiredFields = CoreRequiredFields.DepthNormals,
fieldDependencies = CoreFieldDependencies.Default,
// Conditional State
renderStates = CoreRenderStates.DepthNormalsOnly(target),
pragmas = CorePragmas.Instanced,
defines = new DefineCollection(),
keywords = new KeywordCollection(),
includes = CoreIncludes.DepthNormalsOnly,
// Custom Interpolator Support
customInterpolators = CoreCustomInterpDescriptors.Common
};
CorePasses.AddAlphaClipControlToPass(ref result, target);
return result;
}
}
#endregion
#region PortMasks
static class LitBlockMasks
{
public static readonly BlockFieldDescriptor[] FragmentLit = new BlockFieldDescriptor[]
{
BlockFields.SurfaceDescription.BaseColor,
BlockFields.SurfaceDescription.NormalOS,
BlockFields.SurfaceDescription.NormalTS,
BlockFields.SurfaceDescription.NormalWS,
BlockFields.SurfaceDescription.Emission,
BlockFields.SurfaceDescription.Metallic,
BlockFields.SurfaceDescription.Specular,
BlockFields.SurfaceDescription.Smoothness,
BlockFields.SurfaceDescription.Occlusion,
BlockFields.SurfaceDescription.Alpha,
BlockFields.SurfaceDescription.AlphaClipThreshold,
};
public static readonly BlockFieldDescriptor[] FragmentComplexLit = new BlockFieldDescriptor[]
{
BlockFields.SurfaceDescription.BaseColor,
BlockFields.SurfaceDescription.NormalOS,
BlockFields.SurfaceDescription.NormalTS,
BlockFields.SurfaceDescription.NormalWS,
BlockFields.SurfaceDescription.Emission,
BlockFields.SurfaceDescription.Metallic,
BlockFields.SurfaceDescription.Specular,
BlockFields.SurfaceDescription.Smoothness,
BlockFields.SurfaceDescription.Occlusion,
BlockFields.SurfaceDescription.Alpha,
BlockFields.SurfaceDescription.AlphaClipThreshold,
BlockFields.SurfaceDescription.CoatMask,
BlockFields.SurfaceDescription.CoatSmoothness,
};
public static readonly BlockFieldDescriptor[] FragmentMeta = new BlockFieldDescriptor[]
{
BlockFields.SurfaceDescription.BaseColor,
BlockFields.SurfaceDescription.Emission,
BlockFields.SurfaceDescription.Alpha,
BlockFields.SurfaceDescription.AlphaClipThreshold,
};
}
#endregion
#region RequiredFields
static class LitRequiredFields
{
public static readonly FieldCollection Forward = new FieldCollection()
{
StructFields.Attributes.uv1,
StructFields.Attributes.uv2,
StructFields.Varyings.positionWS,
StructFields.Varyings.normalWS,
StructFields.Varyings.tangentWS, // needed for vertex lighting
StructFields.Varyings.viewDirectionWS,
UniversalStructFields.Varyings.staticLightmapUV,
UniversalStructFields.Varyings.dynamicLightmapUV,
UniversalStructFields.Varyings.sh,
UniversalStructFields.Varyings.fogFactorAndVertexLight, // fog and vertex lighting, vert input is dependency
UniversalStructFields.Varyings.shadowCoord, // shadow coord, vert input is dependency
};
public static readonly FieldCollection GBuffer = new FieldCollection()
{
StructFields.Attributes.uv1,
StructFields.Attributes.uv2,
StructFields.Varyings.positionWS,
StructFields.Varyings.normalWS,
StructFields.Varyings.tangentWS, // needed for vertex lighting
StructFields.Varyings.viewDirectionWS,
UniversalStructFields.Varyings.staticLightmapUV,
UniversalStructFields.Varyings.dynamicLightmapUV,
UniversalStructFields.Varyings.sh,
UniversalStructFields.Varyings.fogFactorAndVertexLight, // fog and vertex lighting, vert input is dependency
UniversalStructFields.Varyings.shadowCoord, // shadow coord, vert input is dependency
};
public static readonly FieldCollection Meta = new FieldCollection()
{
StructFields.Attributes.positionOS,
StructFields.Attributes.normalOS,
StructFields.Attributes.uv0, //
StructFields.Attributes.uv1, // needed for meta vertex position
StructFields.Attributes.uv2, // needed for meta UVs
StructFields.Attributes.instanceID, // needed for rendering instanced terrain
StructFields.Varyings.positionCS,
StructFields.Varyings.texCoord0, // needed for meta UVs
StructFields.Varyings.texCoord1, // VizUV
StructFields.Varyings.texCoord2, // LightCoord
};
}
#endregion
#region Defines
static class LitDefines
{
public static readonly KeywordDescriptor ClearCoat = new KeywordDescriptor()
{
displayName = "Clear Coat",
referenceName = "_CLEARCOAT",
type = KeywordType.Boolean,
definition = KeywordDefinition.ShaderFeature,
scope = KeywordScope.Local,
stages = KeywordShaderStage.Fragment
};
public static readonly KeywordDescriptor SpecularSetup = new KeywordDescriptor()
{
displayName = "Specular Setup",
referenceName = "_SPECULAR_SETUP",
type = KeywordType.Boolean,
definition = KeywordDefinition.ShaderFeature,
scope = KeywordScope.Local,
stages = KeywordShaderStage.Fragment
};
}
#endregion
#region Keywords
static class LitKeywords
{
public static readonly KeywordDescriptor ReceiveShadowsOff = new KeywordDescriptor()
{
displayName = "Receive Shadows Off",
referenceName = ShaderKeywordStrings._RECEIVE_SHADOWS_OFF,
type = KeywordType.Boolean,
definition = KeywordDefinition.ShaderFeature,
scope = KeywordScope.Local,
};
public static readonly KeywordDescriptor ScreenSpaceAmbientOcclusion = new KeywordDescriptor()
{
displayName = "Screen Space Ambient Occlusion",
referenceName = "_SCREEN_SPACE_OCCLUSION",
type = KeywordType.Boolean,
definition = KeywordDefinition.MultiCompile,
scope = KeywordScope.Global,
stages = KeywordShaderStage.Fragment,
};
public static readonly KeywordCollection Forward = new KeywordCollection
{
{ ScreenSpaceAmbientOcclusion },
{ CoreKeywordDescriptors.StaticLightmap },
{ CoreKeywordDescriptors.DynamicLightmap },
{ CoreKeywordDescriptors.DirectionalLightmapCombined },
{ CoreKeywordDescriptors.MainLightShadows },
{ CoreKeywordDescriptors.AdditionalLights },
{ CoreKeywordDescriptors.AdditionalLightShadows },
{ CoreKeywordDescriptors.ReflectionProbeBlending },
{ CoreKeywordDescriptors.ReflectionProbeBoxProjection },
{ CoreKeywordDescriptors.ShadowsSoft },
{ CoreKeywordDescriptors.LightmapShadowMixing },
{ CoreKeywordDescriptors.ShadowsShadowmask },
{ CoreKeywordDescriptors.DBuffer },
{ CoreKeywordDescriptors.LightLayers },
{ CoreKeywordDescriptors.DebugDisplay },
{ CoreKeywordDescriptors.LightCookies },
{ CoreKeywordDescriptors.ClusteredRendering },
};
public static readonly KeywordCollection GBuffer = new KeywordCollection
{
{ CoreKeywordDescriptors.StaticLightmap },
{ CoreKeywordDescriptors.DynamicLightmap },
{ CoreKeywordDescriptors.DirectionalLightmapCombined },
{ CoreKeywordDescriptors.MainLightShadows },
{ CoreKeywordDescriptors.ReflectionProbeBlending },
{ CoreKeywordDescriptors.ReflectionProbeBoxProjection },
{ CoreKeywordDescriptors.ShadowsSoft },
{ CoreKeywordDescriptors.LightmapShadowMixing },
{ CoreKeywordDescriptors.MixedLightingSubtractive },
{ CoreKeywordDescriptors.ShadowsShadowmask },
{ CoreKeywordDescriptors.DBuffer },
{ CoreKeywordDescriptors.GBufferNormalsOct },
{ CoreKeywordDescriptors.LightLayers },
{ CoreKeywordDescriptors.RenderPassEnabled },
{ CoreKeywordDescriptors.DebugDisplay },
};
}
#endregion
#region Includes
static class LitIncludes
{
const string kShadows = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl";
const string kMetaInput = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/MetaInput.hlsl";
const string kForwardPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/PBRForwardPass.hlsl";
const string kGBuffer = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityGBuffer.hlsl";
const string kPBRGBufferPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/PBRGBufferPass.hlsl";
const string kLightingMetaPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/LightingMetaPass.hlsl";
const string k2DPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/PBR2DPass.hlsl";
public static readonly IncludeCollection Forward = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ kShadows, IncludeLocation.Pregraph },
{ CoreIncludes.ShaderGraphPregraph },
{ CoreIncludes.DBufferPregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ kForwardPass, IncludeLocation.Postgraph },
};
public static readonly IncludeCollection GBuffer = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ kShadows, IncludeLocation.Pregraph },
{ CoreIncludes.ShaderGraphPregraph },
{ CoreIncludes.DBufferPregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ kGBuffer, IncludeLocation.Postgraph },
{ kPBRGBufferPass, IncludeLocation.Postgraph },
};
public static readonly IncludeCollection Meta = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ CoreIncludes.ShaderGraphPregraph },
{ kMetaInput, IncludeLocation.Pregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ kLightingMetaPass, IncludeLocation.Postgraph },
};
public static readonly IncludeCollection _2D = new IncludeCollection
{
// Pre-graph
{ CoreIncludes.CorePregraph },
{ CoreIncludes.ShaderGraphPregraph },
// Post-graph
{ CoreIncludes.CorePostgraph },
{ k2DPass, IncludeLocation.Postgraph },
};
}
#endregion
}
}