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.
920 lines
42 KiB
920 lines
42 KiB
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", |
|
useInPreview = true, |
|
|
|
// 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 |
|
} |
|
}
|
|
|