using System; using System.Linq; using System.Collections.Generic; using UnityEngine; using UnityEditor.ShaderGraph; using UnityEngine.Rendering; using UnityEditor.UIElements; using UnityEngine.UIElements; using UnityEditor.ShaderGraph.Legacy; using UnityEngine.Rendering.Universal; using UnityEditor.ShaderGraph.Internal; namespace UnityEditor.Rendering.Universal.ShaderGraph { sealed class UniversalDecalSubTarget : SubTarget { static readonly GUID kSourceCodeGuid = new GUID("f6cdcb0f9c306bf4895b74013d29ed47"); // UniversalDecalSubTarget.cs internal class Styles { public const string header = "Surface Options"; public static GUIContent affectAlbedoText = new GUIContent("Affect BaseColor", "When enabled, this decal uses its base color. When disabled, the decal has no base color effect."); public static GUIContent affectNormalText = new GUIContent("Affect Normal", "When enabled, this decal uses its normal. When disabled, the decal has no normal effect."); public static GUIContent affectNormalBlendText = new GUIContent("Affect Normal Blend", "When enabled, this decal uses its normal blending. When disabled, the decal has no normal blending effect."); public static GUIContent affectMetalText = new GUIContent("Affect Metal", "When enabled, this decal uses the metallic channel of its Mask Map. When disabled, the decal has no metallic effect."); public static GUIContent affectAmbientOcclusionText = new GUIContent("Affect Ambient Occlusion", "When enabled, this decal uses the smoothness channel of its Mask Map. When disabled, the decal has no smoothness effect."); public static GUIContent affectSmoothnessText = new GUIContent("Affect Smoothness", "When enabled, this decal uses the ambient occlusion channel of its Mask Map. When disabled, the decal has no ambient occlusion effect."); public static GUIContent affectEmissionText = new GUIContent("Affect Emission", "When enabled, this decal becomes emissive and appears self-illuminated. Affect Emission does not support Affects Transparent option on Decal Projector."); public static GUIContent supportLodCrossFadeText = new GUIContent("Support LOD CrossFade", "When enabled, this decal material supports LOD Cross fade if use on a Mesh."); } private const string kMaterial = "Material"; private static FieldDescriptor AffectsAlbedo = new FieldDescriptor(kMaterial, "AffectsAlbedo", ""); private static FieldDescriptor AffectsNormal = new FieldDescriptor(kMaterial, "AffectsNormal", ""); private static FieldDescriptor AffectsNormalBlend = new FieldDescriptor(kMaterial, "AffectsNormalBlend", ""); private static FieldDescriptor AffectsMAOS = new FieldDescriptor(kMaterial, "AffectsAO", ""); private static FieldDescriptor AffectsEmission = new FieldDescriptor(kMaterial, "AffectsEmission", ""); private static FieldDescriptor AffectsDBuffer = new FieldDescriptor(kMaterial, "AffectsDBuffer", ""); private static FieldDescriptor DecalDefault = new FieldDescriptor(kMaterial, "DecalDefault", ""); private static FieldDescriptor AngleFade = new FieldDescriptor(kMaterial, "AngleFade", ""); [System.Serializable] class DecalData { public bool affectsAlbedo = true; public bool affectsNormalBlend = true; public bool affectsNormal = true; public bool affectsMAOS; public bool affectsEmission; public int drawOrder; public bool supportLodCrossFade; public bool angleFade; } [SerializeField] DecalData m_DecalData; [SerializeField] private DecalData decalData { get { if (m_DecalData == null) m_DecalData = new DecalData(); return m_DecalData; } } public UniversalDecalSubTarget() { displayName = "Decal"; } public override bool IsActive() => true; public override void Setup(ref TargetSetupContext context) { context.AddAssetDependency(kSourceCodeGuid, AssetCollection.Flags.SourceDependency); context.AddCustomEditorForRenderPipeline("UnityEditor.Rendering.Universal.DecalShaderGraphGUI", typeof(UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset)); // TODO: This should be owned by URP { SubShaderDescriptor subShader = SubShaders.Decal; var passes = new PassCollection(); foreach (var pass in subShader.passes) { var passDescriptor = pass.descriptor; CollectPassRenderState(ref passDescriptor); passes.Add(passDescriptor, pass.fieldConditions); } subShader.passes = passes; context.AddSubShader(subShader); } } private void CollectPassRenderState(ref PassDescriptor pass) { if (pass.lightMode == DecalShaderPassNames.DecalGBufferProjector || pass.lightMode == DecalShaderPassNames.DecalGBufferMesh) { // Make copy to avoid overwriting static pass.renderStates = new RenderStateCollection() { pass.renderStates }; if (decalData.affectsAlbedo) pass.renderStates.Add(RenderState.ColorMask("ColorMask RGB")); else pass.renderStates.Add(RenderState.ColorMask("ColorMask 0")); pass.renderStates.Add(RenderState.ColorMask("ColorMask 0 1")); if (decalData.affectsNormal) pass.renderStates.Add(RenderState.ColorMask("ColorMask RGB 2")); else pass.renderStates.Add(RenderState.ColorMask("ColorMask 0 2")); // GI needs it unconditionaly pass.renderStates.Add(RenderState.ColorMask("ColorMask RGB 3")); } if (pass.lightMode == DecalShaderPassNames.DBufferProjector || pass.lightMode == DecalShaderPassNames.DBufferMesh) { // Make copy to avoid overwriting static pass.renderStates = new RenderStateCollection() { pass.renderStates }; if (decalData.affectsAlbedo) pass.renderStates.Add(DecalColorMasks.ColorMaskRGBA0); else pass.renderStates.Add(DecalColorMasks.ColorMaskNone0); if (decalData.affectsNormal) pass.renderStates.Add(DecalColorMasks.ColorMaskRGBA1); else pass.renderStates.Add(DecalColorMasks.ColorMaskNone1); if (decalData.affectsMAOS) pass.renderStates.Add(DecalColorMasks.ColorMaskRGBA2); else pass.renderStates.Add(DecalColorMasks.ColorMaskNone2); } } public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode) { Vector1ShaderProperty drawOrder = new Vector1ShaderProperty(); drawOrder.overrideReferenceName = "_DrawOrder"; drawOrder.displayName = "Draw Order"; drawOrder.floatType = FloatType.Slider; drawOrder.rangeValues = new Vector2(-50, 50); drawOrder.hidden = true; drawOrder.value = 0; collector.AddShaderProperty(drawOrder); collector.AddShaderProperty(new Vector1ShaderProperty { overrideReferenceName = "_DecalMeshBiasType", displayName = "DecalMesh BiasType", floatType = FloatType.Enum, value = (int)DecalMeshDepthBiasType.DepthBias, enumNames = { "Depth Bias", "View Bias" }, enumValues = { (int)DecalMeshDepthBiasType.DepthBias, (int)DecalMeshDepthBiasType.ViewBias }, hidden = true }); Vector1ShaderProperty decalMeshDepthBias = new Vector1ShaderProperty(); decalMeshDepthBias.overrideReferenceName = "_DecalMeshDepthBias"; decalMeshDepthBias.displayName = "DecalMesh DepthBias"; decalMeshDepthBias.hidden = true; decalMeshDepthBias.floatType = FloatType.Default; decalMeshDepthBias.value = 0; collector.AddShaderProperty(decalMeshDepthBias); Vector1ShaderProperty decalMeshViewBias = new Vector1ShaderProperty(); decalMeshViewBias.overrideReferenceName = "_DecalMeshViewBias"; decalMeshViewBias.displayName = "DecalMesh ViewBias"; decalMeshViewBias.hidden = true; decalMeshViewBias.floatType = FloatType.Default; decalMeshViewBias.value = 0; collector.AddShaderProperty(decalMeshViewBias); if (decalData.angleFade) { Vector1ShaderProperty decalAngleFadeSupported = new Vector1ShaderProperty(); decalAngleFadeSupported.overrideReferenceName = "_DecalAngleFadeSupported"; decalAngleFadeSupported.displayName = "Decal Angle Fade Supported"; decalAngleFadeSupported.hidden = true; decalAngleFadeSupported.floatType = FloatType.Default; decalAngleFadeSupported.value = 1; collector.AddShaderProperty(decalAngleFadeSupported); } } public override void GetFields(ref TargetFieldContext context) { // Decal properties context.AddField(AffectsAlbedo, decalData.affectsAlbedo); context.AddField(AffectsNormal, decalData.affectsNormal); context.AddField(AffectsNormalBlend, decalData.affectsNormalBlend); context.AddField(AffectsMAOS, decalData.affectsMAOS); context.AddField(AffectsEmission, decalData.affectsEmission); context.AddField(AffectsDBuffer, decalData.affectsAlbedo || decalData.affectsNormal || decalData.affectsMAOS); context.AddField(DecalDefault, decalData.affectsAlbedo || decalData.affectsNormal || decalData.affectsMAOS || decalData.affectsEmission); context.AddField(Fields.LodCrossFade, decalData.supportLodCrossFade); context.AddField(AngleFade, decalData.angleFade); } public override void GetActiveBlocks(ref TargetActiveBlockContext context) { // Vertex context.AddBlock(BlockFields.VertexDescription.Position); context.AddBlock(BlockFields.VertexDescription.Normal); context.AddBlock(BlockFields.VertexDescription.Tangent); // Decal context.AddBlock(BlockFields.SurfaceDescription.BaseColor, decalData.affectsAlbedo); context.AddBlock(BlockFields.SurfaceDescription.Alpha, decalData.affectsAlbedo || decalData.affectsEmission); context.AddBlock(BlockFields.SurfaceDescription.NormalTS, decalData.affectsNormal); context.AddBlock(UniversalBlockFields.SurfaceDescription.NormalAlpha, decalData.affectsNormal && decalData.affectsNormalBlend); context.AddBlock(BlockFields.SurfaceDescription.Metallic, decalData.affectsMAOS); context.AddBlock(BlockFields.SurfaceDescription.Occlusion, decalData.affectsMAOS); context.AddBlock(BlockFields.SurfaceDescription.Smoothness, decalData.affectsMAOS); context.AddBlock(UniversalBlockFields.SurfaceDescription.MAOSAlpha, decalData.affectsMAOS); context.AddBlock(BlockFields.SurfaceDescription.Emission, decalData.affectsEmission); } public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action registerUndo) { context.AddProperty("Affect BaseColor", new Toggle() { value = decalData.affectsAlbedo }, (evt) => { if (Equals(decalData.affectsAlbedo, evt.newValue)) return; registerUndo("Change Affect BaseColor"); decalData.affectsAlbedo = (bool)evt.newValue; onChange(); }); context.AddProperty("Affect Normal", new Toggle() { value = decalData.affectsNormal }, (evt) => { if (Equals(decalData.affectsNormal, evt.newValue)) return; registerUndo("Change Affects Normal"); decalData.affectsNormal = (bool)evt.newValue; onChange(); }); context.globalIndentLevel++; context.AddProperty("Blend", new Toggle() { value = decalData.affectsNormalBlend }, (evt) => { if (Equals(decalData.affectsNormalBlend, evt.newValue)) return; registerUndo("Change Affects Normal Blend"); decalData.affectsNormalBlend = (bool)evt.newValue; onChange(); }); context.globalIndentLevel--; context.AddProperty("Affect MAOS", new Toggle() { value = decalData.affectsMAOS }, (evt) => { if (Equals(decalData.affectsMAOS, evt.newValue)) return; registerUndo("Change Affect MAOS"); decalData.affectsMAOS = (bool)evt.newValue; onChange(); }); context.AddProperty("Affect Emission", new Toggle() { value = decalData.affectsEmission }, (evt) => { if (Equals(decalData.affectsEmission, evt.newValue)) return; registerUndo("Change Affect Emission"); decalData.affectsEmission = (bool)evt.newValue; onChange(); }); context.AddProperty("Supports LOD Cross Fade", new Toggle() { value = decalData.supportLodCrossFade }, (evt) => { if (Equals(decalData.supportLodCrossFade, evt.newValue)) return; registerUndo("Change Supports LOD Cross Fade"); decalData.supportLodCrossFade = (bool)evt.newValue; onChange(); }); context.AddProperty("Angle Fade", new Toggle() { value = decalData.angleFade }, (evt) => { if (Equals(decalData.angleFade, evt.newValue)) return; registerUndo("Change Angle Fade"); decalData.angleFade = (bool)evt.newValue; onChange(); }); } #region SubShader static class SubShaders { // Relies on the order shader passes are declared in DecalSystem.cs public static SubShaderDescriptor Decal = new SubShaderDescriptor() { pipelineTag = UniversalTarget.kPipelineTag, customTags = "\"PreviewType\"=\"Plane\"", generatesPreview = true, passes = new PassCollection { { DecalPasses.DBufferProjector, new FieldCondition(AffectsDBuffer, true) }, { DecalPasses.ForwardEmissiveProjector, new FieldCondition(AffectsEmission, true) }, { DecalPasses.ScreenSpaceProjector, new FieldCondition(DecalDefault, true) }, { DecalPasses.GBufferProjector, new FieldCondition(DecalDefault, true) }, { DecalPasses.DBufferMesh, new FieldCondition(AffectsDBuffer, true) }, { DecalPasses.ForwardEmissiveMesh, new FieldCondition(AffectsEmission, true) }, { DecalPasses.ScreenSpaceMesh, new FieldCondition(DecalDefault, true) }, { DecalPasses.GBufferMesh, new FieldCondition(DecalDefault, true) }, { DecalPasses.ScenePicking, new FieldCondition(DecalDefault, true) }, }, }; } #endregion #region Passes static class DecalPasses { public static PassDescriptor ScenePicking = new PassDescriptor() { // Definition displayName = "ScenePickingPass", referenceName = "SHADERPASS_DEPTHONLY", lightMode = "Picking", useInPreview = false, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Collections renderStates = DecalRenderStates.ScenePicking, pragmas = DecalPragmas.MultipleRenderTargets, defines = DecalDefines.ScenePicking, includes = DecalIncludes.ScenePicking, structs = CoreStructCollections.Default, fieldDependencies = CoreFieldDependencies.Default, }; public static PassDescriptor DBufferProjector = new PassDescriptor() { // Definition displayName = DecalShaderPassNames.DBufferProjector, referenceName = "SHADERPASS_DBUFFER_PROJECTOR", lightMode = DecalShaderPassNames.DBufferProjector, useInPreview = false, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port mask validPixelBlocks = DecalBlockMasks.FragmentWithoutEmessive, //Fields structs = CoreStructCollections.Default, fieldDependencies = CoreFieldDependencies.Default, renderStates = DecalRenderStates.DBufferProjector, pragmas = DecalPragmas.MultipleRenderTargets, keywords = DecalKeywords.DBufferProjector, defines = DecalDefines.Projector, includes = DecalIncludes.DBuffer, }; public static PassDescriptor ForwardEmissiveProjector = new PassDescriptor() { // Definition displayName = DecalShaderPassNames.DecalProjectorForwardEmissive, referenceName = "SHADERPASS_FORWARD_EMISSIVE_PROJECTOR", lightMode = DecalShaderPassNames.DecalProjectorForwardEmissive, useInPreview = false, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port mask validPixelBlocks = DecalBlockMasks.ForwardOnlyEmissive, //Fields structs = CoreStructCollections.Default, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = DecalRenderStates.ForwardEmissiveProjector, pragmas = DecalPragmas.MultipleRenderTargets, defines = DecalDefines.ProjectorWithEmission, includes = DecalIncludes.DBuffer, }; public static PassDescriptor ScreenSpaceProjector = new PassDescriptor() { // Definition displayName = DecalShaderPassNames.DecalScreenSpaceProjector, referenceName = "SHADERPASS_DECAL_SCREEN_SPACE_PROJECTOR", lightMode = DecalShaderPassNames.DecalScreenSpaceProjector, useInPreview = false, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port mask validPixelBlocks = DecalBlockMasks.Fragment, //Fields structs = CoreStructCollections.Default, requiredFields = DecalRequiredFields.ScreenSpaceProjector, fieldDependencies = CoreFieldDependencies.Default, renderStates = DecalRenderStates.ScreenSpaceProjector, pragmas = DecalPragmas.ScreenSpace, defines = DecalDefines.ProjectorWithEmission, keywords = DecalKeywords.ScreenSpaceProjector, includes = DecalIncludes.ScreenSpace, }; public static PassDescriptor GBufferProjector = new PassDescriptor() { // Definition displayName = DecalShaderPassNames.DecalGBufferProjector, referenceName = "SHADERPASS_DECAL_GBUFFER_PROJECTOR", lightMode = DecalShaderPassNames.DecalGBufferProjector, useInPreview = false, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port mask validPixelBlocks = DecalBlockMasks.Fragment, //Fields structs = CoreStructCollections.Default, requiredFields = DecalRequiredFields.GBufferProjector, fieldDependencies = CoreFieldDependencies.Default, renderStates = DecalRenderStates.GBufferProjector, pragmas = DecalPragmas.GBuffer, defines = DecalDefines.ProjectorWithEmission, keywords = DecalKeywords.GBufferProjector, includes = DecalIncludes.GBuffer, }; public static PassDescriptor DBufferMesh = new PassDescriptor() { // Definition displayName = DecalShaderPassNames.DBufferMesh, referenceName = "SHADERPASS_DBUFFER_MESH", lightMode = DecalShaderPassNames.DBufferMesh, useInPreview = false, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port mask validPixelBlocks = DecalBlockMasks.FragmentWithoutEmessive, //Fields structs = CoreStructCollections.Default, requiredFields = DecalRequiredFields.Mesh, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = DecalRenderStates.DBufferMesh, pragmas = DecalPragmas.MultipleRenderTargets, defines = DecalDefines.Mesh, keywords = DecalKeywords.DBufferMesh, includes = DecalIncludes.DBuffer, }; public static PassDescriptor ForwardEmissiveMesh = new PassDescriptor() { // Definition displayName = DecalShaderPassNames.DecalMeshForwardEmissive, referenceName = "SHADERPASS_FORWARD_EMISSIVE_MESH", lightMode = DecalShaderPassNames.DecalMeshForwardEmissive, useInPreview = false, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port mask validPixelBlocks = DecalBlockMasks.Fragment, //Fields structs = CoreStructCollections.Default, requiredFields = DecalRequiredFields.Mesh, fieldDependencies = CoreFieldDependencies.Default, // Conditional State renderStates = DecalRenderStates.ForwardEmissiveMesh, pragmas = DecalPragmas.MultipleRenderTargets, defines = DecalDefines.MeshWithEmission, includes = DecalIncludes.DBuffer, }; public static PassDescriptor ScreenSpaceMesh = new PassDescriptor() { // Definition displayName = DecalShaderPassNames.DecalScreenSpaceMesh, referenceName = "SHADERPASS_DECAL_SCREEN_SPACE_MESH", lightMode = DecalShaderPassNames.DecalScreenSpaceMesh, useInPreview = true, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port mask validPixelBlocks = DecalBlockMasks.Fragment, // todo //Fields structs = CoreStructCollections.Default, requiredFields = DecalRequiredFields.ScreenSpaceMesh, fieldDependencies = CoreFieldDependencies.Default, renderStates = DecalRenderStates.ScreenSpaceMesh, pragmas = DecalPragmas.ScreenSpace, defines = DecalDefines.MeshWithEmission, keywords = DecalKeywords.ScreenSpaceMesh, includes = DecalIncludes.ScreenSpace, }; public static PassDescriptor GBufferMesh = new PassDescriptor() { // Definition displayName = DecalShaderPassNames.DecalGBufferMesh, referenceName = "SHADERPASS_DECAL_GBUFFER_MESH", lightMode = DecalShaderPassNames.DecalGBufferMesh, useInPreview = false, // Template passTemplatePath = "Packages/com.unity.render-pipelines.universal/Editor/Decal/DecalPass.template", sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(), // Port mask validPixelBlocks = DecalBlockMasks.Fragment, // todo //Fields structs = CoreStructCollections.Default, requiredFields = DecalRequiredFields.ScreenSpaceMesh, fieldDependencies = CoreFieldDependencies.Default, renderStates = DecalRenderStates.GBufferMesh, pragmas = DecalPragmas.GBuffer, defines = DecalDefines.MeshWithEmission, keywords = DecalKeywords.GBufferMesh, includes = DecalIncludes.GBuffer, }; } #endregion #region PortMasks static class DecalBlockMasks { public static BlockFieldDescriptor[] FragmentWithoutEmessive = new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.BaseColor, BlockFields.SurfaceDescription.Alpha, BlockFields.SurfaceDescription.NormalTS, UniversalBlockFields.SurfaceDescription.NormalAlpha, BlockFields.SurfaceDescription.Metallic, BlockFields.SurfaceDescription.Occlusion, BlockFields.SurfaceDescription.Smoothness, UniversalBlockFields.SurfaceDescription.MAOSAlpha, }; public static BlockFieldDescriptor[] ForwardOnlyEmissive = new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.Alpha, BlockFields.SurfaceDescription.Emission, }; public static BlockFieldDescriptor[] Fragment = new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.BaseColor, BlockFields.SurfaceDescription.Alpha, BlockFields.SurfaceDescription.NormalTS, UniversalBlockFields.SurfaceDescription.NormalAlpha, BlockFields.SurfaceDescription.Metallic, BlockFields.SurfaceDescription.Occlusion, BlockFields.SurfaceDescription.Smoothness, UniversalBlockFields.SurfaceDescription.MAOSAlpha, BlockFields.SurfaceDescription.Emission, }; } #endregion #region RequiredFields static class DecalRequiredFields { public static FieldCollection Mesh = new FieldCollection() { StructFields.Attributes.normalOS, StructFields.Attributes.tangentOS, StructFields.Attributes.uv1, StructFields.Attributes.uv2, StructFields.Varyings.normalWS, StructFields.Varyings.tangentWS, StructFields.Varyings.positionWS, StructFields.Varyings.texCoord0, }; public static FieldCollection ScreenSpaceProjector = new FieldCollection() { StructFields.Varyings.normalWS, StructFields.Varyings.viewDirectionWS, UniversalStructFields.Varyings.staticLightmapUV, UniversalStructFields.Varyings.dynamicLightmapUV, UniversalStructFields.Varyings.sh, UniversalStructFields.Varyings.fogFactorAndVertexLight, // fog and vertex lighting, vert input is dependency // todo //UniversalStructFields.Varyings.shadowCoord, // shadow coord, vert input is dependency }; public static FieldCollection GBufferProjector = new FieldCollection() { StructFields.Varyings.normalWS, StructFields.Varyings.viewDirectionWS, UniversalStructFields.Varyings.staticLightmapUV, UniversalStructFields.Varyings.dynamicLightmapUV, UniversalStructFields.Varyings.sh, // todo //UniversalStructFields.Varyings.shadowCoord, // shadow coord, vert input is dependency }; public static FieldCollection ScreenSpaceMesh = new FieldCollection() { StructFields.Attributes.normalOS, StructFields.Attributes.tangentOS, StructFields.Attributes.uv1, StructFields.Attributes.uv2, StructFields.Varyings.normalWS, StructFields.Varyings.tangentWS, StructFields.Varyings.positionWS, StructFields.Varyings.texCoord0, StructFields.Varyings.viewDirectionWS, UniversalStructFields.Varyings.staticLightmapUV, UniversalStructFields.Varyings.dynamicLightmapUV, UniversalStructFields.Varyings.sh, UniversalStructFields.Varyings.fogFactorAndVertexLight, // fog and vertex lighting, vert input is dependency // todo //UniversalStructFields.Varyings.shadowCoord, // shadow coord, vert input is dependency }; } #endregion #region ColorMask static class DecalColorMasks { public static RenderStateDescriptor ColorMaskRGBA0 = RenderState.ColorMask("ColorMask RGBA"); public static RenderStateDescriptor ColorMaskNone0 = RenderState.ColorMask("ColorMask 0"); public static RenderStateDescriptor ColorMaskRGBA1 = RenderState.ColorMask("ColorMask RGBA 1"); public static RenderStateDescriptor ColorMaskNone1 = RenderState.ColorMask("ColorMask 0 1"); public static RenderStateDescriptor ColorMaskRGBA2 = RenderState.ColorMask("ColorMask RGBA 2"); public static RenderStateDescriptor ColorMaskNone2 = RenderState.ColorMask("ColorMask 0 2"); } #endregion #region RenderStates static class DecalRenderStates { private readonly static string[] s_DBufferBlends = new string[] { "Blend 0 SrcAlpha OneMinusSrcAlpha, Zero OneMinusSrcAlpha", "Blend 1 SrcAlpha OneMinusSrcAlpha, Zero OneMinusSrcAlpha", "Blend 2 SrcAlpha OneMinusSrcAlpha, Zero OneMinusSrcAlpha", }; private readonly static string[] s_GBufferBlends = new string[] { "Blend 0 SrcAlpha OneMinusSrcAlpha", "Blend 1 SrcAlpha OneMinusSrcAlpha", "Blend 2 SrcAlpha OneMinusSrcAlpha", "Blend 3 SrcAlpha OneMinusSrcAlpha", }; public static RenderStateCollection ScenePicking = new RenderStateCollection { { RenderState.Cull(Cull.Back) }, }; public static RenderStateCollection DBufferProjector = new RenderStateCollection { { RenderState.Blend(s_DBufferBlends[0]) }, { RenderState.Blend(s_DBufferBlends[1]) }, { RenderState.Blend(s_DBufferBlends[2]) }, { RenderState.Cull(Cull.Front) }, { RenderState.ZTest(ZTest.Greater) }, { RenderState.ZWrite(ZWrite.Off) }, }; public static RenderStateCollection ForwardEmissiveProjector = new RenderStateCollection { { RenderState.Blend("Blend 0 SrcAlpha One") }, { RenderState.Cull(Cull.Front) }, { RenderState.ZTest(ZTest.Greater) }, { RenderState.ZWrite(ZWrite.Off) }, }; public static RenderStateCollection ScreenSpaceProjector = new RenderStateCollection { { RenderState.Blend("Blend SrcAlpha OneMinusSrcAlpha") }, { RenderState.Cull(Cull.Front) }, { RenderState.ZTest(ZTest.Greater) }, { RenderState.ZWrite(ZWrite.Off) }, }; public static RenderStateCollection GBufferProjector = new RenderStateCollection { { RenderState.Blend(s_GBufferBlends[0]) }, { RenderState.Blend(s_GBufferBlends[1]) }, { RenderState.Blend(s_GBufferBlends[2]) }, { RenderState.Blend(s_GBufferBlends[3]) }, { RenderState.Cull(Cull.Front) }, { RenderState.ZTest(ZTest.Greater) }, { RenderState.ZWrite(ZWrite.Off) }, }; public static RenderStateCollection DBufferMesh = new RenderStateCollection { { RenderState.Blend(s_DBufferBlends[0]) }, { RenderState.Blend(s_DBufferBlends[1]) }, { RenderState.Blend(s_DBufferBlends[2]) }, { RenderState.ZTest(ZTest.LEqual) }, { RenderState.ZWrite(ZWrite.Off) }, }; public static RenderStateCollection ForwardEmissiveMesh = new RenderStateCollection { { RenderState.Blend("Blend 0 SrcAlpha One") }, { RenderState.ZTest(ZTest.LEqual) }, { RenderState.ZWrite(ZWrite.Off) }, }; public static RenderStateCollection ScreenSpaceMesh = new RenderStateCollection { { RenderState.Blend("Blend SrcAlpha OneMinusSrcAlpha") }, { RenderState.ZTest(ZTest.LEqual) }, { RenderState.ZWrite(ZWrite.Off) }, }; public static RenderStateCollection GBufferMesh = new RenderStateCollection { { RenderState.Blend(s_GBufferBlends[0]) }, { RenderState.Blend(s_GBufferBlends[1]) }, { RenderState.Blend(s_GBufferBlends[2]) }, { RenderState.Blend(s_GBufferBlends[3]) }, { RenderState.ZWrite(ZWrite.Off) }, }; } #endregion #region Pragmas static class DecalPragmas { public static PragmaCollection ScreenSpace = new PragmaCollection { { Pragma.Target(ShaderModel.Target25) }, // Derivatives { Pragma.Vertex("Vert") }, { Pragma.Fragment("Frag") }, { Pragma.MultiCompileInstancing }, { Pragma.MultiCompileFog }, { Pragma.EditorSyncCompilation }, }; public static PragmaCollection GBuffer = new PragmaCollection { { Pragma.Target(ShaderModel.Target35) }, // MRT4 { Pragma.Vertex("Vert") }, { Pragma.Fragment("Frag") }, { Pragma.MultiCompileInstancing }, { Pragma.MultiCompileFog }, { Pragma.EditorSyncCompilation }, }; public static PragmaCollection MultipleRenderTargets = new PragmaCollection { { Pragma.Target(ShaderModel.Target35) }, // MRT4 { Pragma.Vertex("Vert") }, { Pragma.Fragment("Frag") }, { Pragma.MultiCompileInstancing }, { Pragma.EditorSyncCompilation }, }; } #endregion #region Defines static class DecalDefines { private static class Descriptors { public static KeywordDescriptor AffectsAlbedo = new KeywordDescriptor() { displayName = "Affects Albedo", referenceName = "_MATERIAL_AFFECTS_ALBEDO", type = KeywordType.Boolean, }; public static KeywordDescriptor AffectsNormal = new KeywordDescriptor() { displayName = "Affects Normal", referenceName = "_MATERIAL_AFFECTS_NORMAL", type = KeywordType.Boolean, }; public static KeywordDescriptor AffectsNormalBlend = new KeywordDescriptor() { displayName = "Affects Normal Blend", referenceName = "_MATERIAL_AFFECTS_NORMAL_BLEND", type = KeywordType.Boolean, }; public static KeywordDescriptor AffectsMAOS = new KeywordDescriptor() { displayName = "Affects Metal", referenceName = "_MATERIAL_AFFECTS_MAOS", type = KeywordType.Boolean, }; public static KeywordDescriptor AffectsEmission = new KeywordDescriptor() { displayName = "Affects Emission", referenceName = "_MATERIAL_AFFECTS_EMISSION", type = KeywordType.Boolean, }; public static KeywordDescriptor AngleFade = new KeywordDescriptor() { displayName = "Angle Fade", referenceName = "DECAL_ANGLE_FADE", type = KeywordType.Boolean, }; public static KeywordDescriptor ScenePickingPass = new KeywordDescriptor() { displayName = "Scene Picking Pass", referenceName = "SCENEPICKINGPASS", type = KeywordType.Boolean, }; } public static DefineCollection Projector = new DefineCollection { { Descriptors.AffectsAlbedo, 1, new FieldCondition(AffectsAlbedo, true) }, { Descriptors.AffectsNormal, 1, new FieldCondition(AffectsNormal, true) }, { Descriptors.AffectsNormalBlend, 1, new FieldCondition(AffectsNormalBlend, true) }, { Descriptors.AffectsMAOS, 1, new FieldCondition(AffectsMAOS, true) }, { Descriptors.AngleFade, 1, new FieldCondition(AngleFade, true) } }; public static DefineCollection ProjectorEmission = new DefineCollection { { Descriptors.AngleFade, 1, new FieldCondition(AngleFade, true) }, { Descriptors.AffectsEmission, 1, new FieldCondition(AffectsEmission, true) }, }; public static DefineCollection ProjectorWithEmission = new DefineCollection { { Projector }, { Descriptors.AffectsEmission, 1, new FieldCondition(AffectsEmission, true) }, }; public static DefineCollection Mesh = new DefineCollection { { Descriptors.AffectsAlbedo, 1, new FieldCondition(AffectsAlbedo, true) }, { Descriptors.AffectsNormal, 1, new FieldCondition(AffectsNormal, true) }, { Descriptors.AffectsNormalBlend, 1, new FieldCondition(AffectsNormalBlend, true) }, { Descriptors.AffectsMAOS, 1, new FieldCondition(AffectsMAOS, true) }, }; public static DefineCollection MeshEmission = new DefineCollection { { Descriptors.AffectsEmission, 1, new FieldCondition(AffectsEmission, true) }, }; public static DefineCollection MeshWithEmission = new DefineCollection { { Mesh }, { Descriptors.AffectsEmission, 1, new FieldCondition(AffectsEmission, true) }, }; public static DefineCollection ScenePicking = new DefineCollection { { Descriptors.ScenePickingPass, 1 }, }; } #endregion #region Keywords static class DecalKeywords { static class Descriptors { public static KeywordDescriptor DecalsNormalBlend = new KeywordDescriptor() { displayName = "Decal Normal Blend", referenceName = "_DECAL_NORMAL_BLEND", type = KeywordType.Enum, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, entries = new KeywordEntry[] { new KeywordEntry() { displayName = "LOW", referenceName = "LOW" }, new KeywordEntry() { displayName = "MEDIUM", referenceName = "MEDIUM" }, new KeywordEntry() { displayName = "HIGH", referenceName = "HIGH" }, } }; public static readonly KeywordDescriptor LodCrossFade = new KeywordDescriptor() { displayName = "LOD Cross Fade", referenceName = "LOD_FADE_CROSSFADE", type = KeywordType.Boolean, definition = KeywordDefinition.MultiCompile, scope = KeywordScope.Global, }; } public static KeywordCollection DBufferMesh = new KeywordCollection { { CoreKeywordDescriptors.DBuffer }, { Descriptors.LodCrossFade, new FieldCondition(Fields.LodCrossFade, true) }, }; public static KeywordCollection DBufferProjector = new KeywordCollection { { CoreKeywordDescriptors.DBuffer }, }; public static readonly KeywordCollection ScreenSpaceMesh = new KeywordCollection { { CoreKeywordDescriptors.StaticLightmap }, { CoreKeywordDescriptors.DynamicLightmap }, { CoreKeywordDescriptors.DirectionalLightmapCombined }, { CoreKeywordDescriptors.MainLightShadows }, { CoreKeywordDescriptors.AdditionalLights }, { CoreKeywordDescriptors.AdditionalLightShadows }, { CoreKeywordDescriptors.ShadowsSoft }, { CoreKeywordDescriptors.LightmapShadowMixing }, { CoreKeywordDescriptors.ShadowsShadowmask }, { CoreKeywordDescriptors.ClusteredRendering }, { Descriptors.DecalsNormalBlend }, { Descriptors.LodCrossFade, new FieldCondition(Fields.LodCrossFade, true) }, }; public static readonly KeywordCollection ScreenSpaceProjector = new KeywordCollection { { CoreKeywordDescriptors.MainLightShadows }, { CoreKeywordDescriptors.AdditionalLights }, { CoreKeywordDescriptors.AdditionalLightShadows }, { CoreKeywordDescriptors.ShadowsSoft }, { CoreKeywordDescriptors.ClusteredRendering }, { Descriptors.DecalsNormalBlend }, }; public static readonly KeywordCollection GBufferMesh = new KeywordCollection { { CoreKeywordDescriptors.StaticLightmap }, { CoreKeywordDescriptors.DynamicLightmap }, { CoreKeywordDescriptors.DirectionalLightmapCombined }, { CoreKeywordDescriptors.MainLightShadows }, { CoreKeywordDescriptors.ShadowsSoft }, { CoreKeywordDescriptors.LightmapShadowMixing }, { CoreKeywordDescriptors.MixedLightingSubtractive }, { Descriptors.DecalsNormalBlend }, { CoreKeywordDescriptors.GBufferNormalsOct }, { Descriptors.LodCrossFade, new FieldCondition(Fields.LodCrossFade, true) }, }; public static readonly KeywordCollection GBufferProjector = new KeywordCollection { { CoreKeywordDescriptors.MainLightShadows }, { CoreKeywordDescriptors.ShadowsSoft }, { Descriptors.DecalsNormalBlend }, { CoreKeywordDescriptors.GBufferNormalsOct }, }; } #endregion #region Includes static class DecalIncludes { const string kDecalInput = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DecalInput.hlsl"; const string kShaderVariablesDecal = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderVariablesDecal.hlsl"; const string kPassDecal = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPassDecal.hlsl"; const string kShaderPass = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"; const string kVaryings = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl"; const string kDBuffer = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"; const string kGBuffer = "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityGBuffer.hlsl"; public static IncludeCollection DecalPregraph = new IncludeCollection { { kShaderPass, IncludeLocation.Pregraph }, { kDecalInput, IncludeLocation.Pregraph }, { kShaderVariablesDecal, IncludeLocation.Pregraph }, }; public static IncludeCollection DecalPostgraph = new IncludeCollection { { kVaryings, IncludeLocation.Postgraph }, { kPassDecal, IncludeLocation.Postgraph }, }; public static IncludeCollection DBuffer = new IncludeCollection { // Pre-graph { CoreIncludes.CorePregraph }, { CoreIncludes.ShaderGraphPregraph }, { DecalPregraph }, { kDBuffer, IncludeLocation.Pregraph }, // Post-graph { DecalPostgraph }, }; public static IncludeCollection ScreenSpace = new IncludeCollection { // Pre-graph { CoreIncludes.CorePregraph }, { CoreIncludes.ShaderGraphPregraph }, { DecalPregraph }, // Post-graph { DecalPostgraph }, }; public static IncludeCollection GBuffer = new IncludeCollection { // Pre-graph { CoreIncludes.CorePregraph }, { CoreIncludes.ShaderGraphPregraph }, { kGBuffer, IncludeLocation.Pregraph }, { DecalPregraph }, // Post-graph { DecalPostgraph }, }; public static IncludeCollection ScenePicking = new IncludeCollection { // Pre-graph { CoreIncludes.CorePregraph }, { CoreIncludes.ShaderGraphPregraph }, { DecalPregraph }, // Post-graph { DecalPostgraph }, }; } #endregion } }