ActiveFields GetActiveFieldsFromMasterNode(PBRMasterNode masterNode, ShaderPass pass) { var activeFields = new ActiveFields(); var baseActiveFields = activeFields.baseInstance; // Graph Vertex if (masterNode.IsSlotConnected(PBRMasterNode.PositionSlotId) || masterNode.IsSlotConnected(PBRMasterNode.VertNormalSlotId) || masterNode.IsSlotConnected(PBRMasterNode.VertTangentSlotId)) { baseActiveFields.Add("features.graphVertex"); } // Graph Pixel (always enabled) baseActiveFields.Add("features.graphPixel"); if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) || masterNode.GetInputSlots <Vector1MaterialSlot>().First(x => x.id == PBRMasterNode.AlphaThresholdSlotId).value > 0.0f) { baseActiveFields.Add("AlphaClip"); } if (masterNode.model == PBRMasterNode.Model.Specular) { baseActiveFields.Add("SpecularSetup"); } if (masterNode.IsSlotConnected(PBRMasterNode.NormalSlotId)) { baseActiveFields.Add("Normal"); } // Keywords for transparent // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT if (masterNode.surfaceType != ShaderGraph.SurfaceType.Opaque) { // transparent-only defines baseActiveFields.Add("SurfaceType.Transparent"); // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY if (masterNode.alphaMode == AlphaMode.Alpha) { baseActiveFields.Add("BlendMode.Alpha"); } else if (masterNode.alphaMode == AlphaMode.Additive) { baseActiveFields.Add("BlendMode.Add"); } else if (masterNode.alphaMode == AlphaMode.Premultiply) { baseActiveFields.Add("BlendMode.Premultiply"); } } return(activeFields); }
private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass) { HashSet <string> activeFields = new HashSet <string>(); PBRMasterNode masterNode = iMasterNode as PBRMasterNode; if (masterNode == null) { return(activeFields); } if (masterNode.twoSided.isOn) { activeFields.Add("DoubleSided"); if (pass.ShaderPassName != "SHADERPASS_VELOCITY") // HACK to get around lack of a good interpolator dependency system { // we need to be able to build interpolators using multiple input structs // also: should only require isFrontFace if Normals are required... activeFields.Add("DoubleSided.Mirror"); // TODO: change this depending on what kind of normal flip you want.. activeFields.Add("FragInputs.isFrontFace"); // will need this for determining normal flip mode } } switch (masterNode.model) { case PBRMasterNode.Model.Metallic: break; case PBRMasterNode.Model.Specular: activeFields.Add("Material.SpecularColor"); break; default: // TODO: error! break; } if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) || masterNode.GetInputSlots <Vector1MaterialSlot>().First(x => x.id == PBRMasterNode.AlphaThresholdSlotId).value > 0.0f) { activeFields.Add("AlphaTest"); } if (masterNode.surfaceType != SurfaceType.Opaque) { activeFields.Add("SurfaceType.Transparent"); if (masterNode.alphaMode == AlphaMode.Alpha) { activeFields.Add("BlendMode.Alpha"); } else if (masterNode.alphaMode == AlphaMode.Additive) { activeFields.Add("BlendMode.Add"); } // By default PBR node will take the fog activeFields.Add("AlphaFog"); } else { // opaque-only defines } return(activeFields); }
private static ActiveFields GetActiveFieldsFromMasterNode(AbstractMaterialNode iMasterNode, Pass pass) { var activeFields = new ActiveFields(); var baseActiveFields = activeFields.baseInstance; PBRMasterNode masterNode = iMasterNode as PBRMasterNode; if (masterNode == null) { return(activeFields); } if (masterNode.twoSided.isOn) { baseActiveFields.Add("DoubleSided"); if (pass.ShaderPassName != "SHADERPASS_MOTION_VECTORS") // HACK to get around lack of a good interpolator dependency system { // we need to be able to build interpolators using multiple input structs // also: should only require isFrontFace if Normals are required... baseActiveFields.Add("DoubleSided.Mirror"); // TODO: change this depending on what kind of normal flip you want.. baseActiveFields.Add("FragInputs.isFrontFace"); // will need this for determining normal flip mode } } switch (masterNode.model) { case PBRMasterNode.Model.Metallic: break; case PBRMasterNode.Model.Specular: baseActiveFields.Add("Material.SpecularColor"); break; default: // TODO: error! break; } if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) || masterNode.GetInputSlots <Vector1MaterialSlot>().First(x => x.id == PBRMasterNode.AlphaThresholdSlotId).value > 0.0f) { baseActiveFields.Add("AlphaTest"); } switch (masterNode.normalDropOffSpace) { case NormalDropOffSpace.Tangent: baseActiveFields.AddAll("features.NormalDropOffTS"); break; case NormalDropOffSpace.Object: baseActiveFields.AddAll("features.NormalDropOffOS"); break; case NormalDropOffSpace.World: baseActiveFields.AddAll("features.NormalDropOffWS"); break; default: UnityEngine.Debug.LogError("Unknown normal drop off space: " + masterNode.normalDropOffSpace); break; } if (masterNode.surfaceType != UnityEditor.ShaderGraph.SurfaceType.Opaque) { baseActiveFields.Add("SurfaceType.Transparent"); if (masterNode.alphaMode == AlphaMode.Alpha) { baseActiveFields.Add("BlendMode.Alpha"); } else if (masterNode.alphaMode == AlphaMode.Additive) { baseActiveFields.Add("BlendMode.Add"); } // By default PBR node will take the fog baseActiveFields.Add("AlphaFog"); } else { // opaque-only defines } return(activeFields); }
private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass) { HashSet <string> activeFields = new HashSet <string>(); PBRMasterNode masterNode = iMasterNode as PBRMasterNode; if (masterNode == null) { return(activeFields); } if (masterNode.twoSided.isOn) { activeFields.Add("DoubleSided"); if (pass.ShaderPassName != "SHADERPASS_VELOCITY") // HACK to get around lack of a good interpolator dependency system { // we need to be able to build interpolators using multiple input structs // also: should only require isFrontFace if Normals are required... activeFields.Add("DoubleSided.Mirror"); // TODO: change this depending on what kind of normal flip you want.. activeFields.Add("FragInputs.isFrontFace"); // will need this for determining normal flip mode } } switch (masterNode.model) { case PBRMasterNode.Model.Metallic: break; case PBRMasterNode.Model.Specular: activeFields.Add("Material.SpecularColor"); break; default: // TODO: error! break; } float constantAlpha = 0.0f; if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) || (float.TryParse(masterNode.GetSlotValue(PBRMasterNode.AlphaThresholdSlotId, GenerationMode.ForReals), out constantAlpha) && (constantAlpha > 0.0f))) { activeFields.Add("AlphaTest"); } // if (kTesselationMode != TessellationMode.None) // { // defines.AddShaderChunk("#define _TESSELLATION_PHONG 1", true); // } // #pragma shader_feature _ _VERTEX_DISPLACEMENT _PIXEL_DISPLACEMENT // switch (kDisplacementMode) // { // case DisplacementMode.None: // break; // case DisplacementMode.Vertex: // defines.AddShaderChunk("#define _VERTEX_DISPLACEMENT 1", true); // break; // case DisplacementMode.Pixel: // defines.AddShaderChunk("#define _PIXEL_DISPLACEMENT 1", true); // Depth offset is only enabled if per pixel displacement is // if (kDepthOffsetEnable) // { // // #pragma shader_feature _DEPTHOFFSET_ON // defines.AddShaderChunk("#define _DEPTHOFFSET_ON 1", true); // } // break; // case DisplacementMode.Tessellation: // if (kTessellationEnabled) // { // defines.AddShaderChunk("#define _TESSELLATION_DISPLACEMENT 1", true); // } // break; // } // #pragma shader_feature _VERTEX_DISPLACEMENT_LOCK_OBJECT_SCALE // #pragma shader_feature _DISPLACEMENT_LOCK_TILING_SCALE // #pragma shader_feature _PIXEL_DISPLACEMENT_LOCK_OBJECT_SCALE // #pragma shader_feature _VERTEX_WIND // #pragma shader_feature _ _REFRACTION_PLANE _REFRACTION_SPHERE // // #pragma shader_feature _ _MAPPING_PLANAR _MAPPING_TRIPLANAR // MOVE to a node // #pragma shader_feature _NORMALMAP_TANGENT_SPACE // #pragma shader_feature _ _REQUIRE_UV2 _REQUIRE_UV3 // #pragma shader_feature _MASKMAP // #pragma shader_feature _BENTNORMALMAP // #pragma shader_feature _EMISSIVE_COLOR_MAP // #pragma shader_feature _ENABLESPECULAROCCLUSION // #pragma shader_feature _HEIGHTMAP // #pragma shader_feature _TANGENTMAP // #pragma shader_feature _ANISOTROPYMAP // #pragma shader_feature _SUBSURFACE_RADIUS_MAP // #pragma shader_feature _THICKNESSMAP // #pragma shader_feature _SPECULARCOLORMAP // #pragma shader_feature _TRANSMITTANCECOLORMAP // Keywords for transparent // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT if (masterNode.surfaceType != SurfaceType.Opaque) { // transparent-only defines activeFields.Add("SurfaceType.Transparent"); // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY if (masterNode.alphaMode == AlphaMode.Alpha) { activeFields.Add("BlendMode.Alpha"); } else if (masterNode.alphaMode == AlphaMode.Additive) { activeFields.Add("BlendMode.Add"); } // else if (masterNode.alphaMode == PBRMasterNode.AlphaMode.PremultiplyAlpha) // TODO // { // defines.AddShaderChunk("#define _BLENDMODE_PRE_MULTIPLY 1", true); // } // #pragma shader_feature _BLENDMODE_PRESERVE_SPECULAR_LIGHTING // if (kEnableBlendModePreserveSpecularLighting) // { // defines.AddShaderChunk("#define _BLENDMODE_PRESERVE_SPECULAR_LIGHTING 1", true); // } // #pragma shader_feature _ENABLE_FOG_ON_TRANSPARENT // if (kEnableFogOnTransparent) // { // defines.AddShaderChunk("#define _ENABLE_FOG_ON_TRANSPARENT 1", true); // } } else { // opaque-only defines } // enable dithering LOD crossfade // #pragma multi_compile _ LOD_FADE_CROSSFADE // TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ? //#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON return(activeFields); }
static string GetShaderPassFromTemplate(string template, PBRMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // String builders var shaderProperties = new PropertyCollector(); var functionBuilder = new ShaderStringBuilder(1); var functionRegistry = new FunctionRegistry(functionBuilder); var defines = new ShaderStringBuilder(1); var graph = new ShaderStringBuilder(0); var vertexDescriptionInputStruct = new ShaderStringBuilder(1); var vertexDescriptionStruct = new ShaderStringBuilder(1); var vertexDescriptionFunction = new ShaderStringBuilder(1); var surfaceDescriptionInputStruct = new ShaderStringBuilder(1); var surfaceDescriptionStruct = new ShaderStringBuilder(1); var surfaceDescriptionFunction = new ShaderStringBuilder(1); var vertexInputStruct = new ShaderStringBuilder(1); var vertexOutputStruct = new ShaderStringBuilder(2); var vertexShader = new ShaderStringBuilder(2); var vertexShaderDescriptionInputs = new ShaderStringBuilder(2); var vertexShaderOutputs = new ShaderStringBuilder(2); var pixelShader = new ShaderStringBuilder(2); var pixelShaderSurfaceInputs = new ShaderStringBuilder(2); var pixelShaderSurfaceRemap = new ShaderStringBuilder(2); // ------------------------------------- // Get Slot and Node lists per stage var vertexSlots = pass.VertexShaderSlots.Select(masterNode.FindSlot <MaterialSlot>).ToList(); var vertexNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots); var pixelSlots = pass.PixelShaderSlots.Select(masterNode.FindSlot <MaterialSlot>).ToList(); var pixelNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(pixelNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots); // ------------------------------------- // Get Requirements var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false); var pixelRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment); var graphRequirements = pixelRequirements.Union(vertexRequirements); var surfaceRequirements = ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false); var modelRequiements = ShaderGraphRequirements.none; modelRequiements.requiresNormal |= m_PixelCoordinateSpace; modelRequiements.requiresTangent |= m_PixelCoordinateSpace; modelRequiements.requiresBitangent |= m_PixelCoordinateSpace; modelRequiements.requiresPosition |= m_PixelCoordinateSpace; modelRequiements.requiresViewDir |= m_PixelCoordinateSpace; modelRequiements.requiresMeshUVs.Add(UVChannel.UV1); // ----------------------------------------------------- // // START SHADER GENERATION // // ----------------------------------------------------- // // ------------------------------------- // Calculate material options var blendingBuilder = new ShaderStringBuilder(1); var cullingBuilder = new ShaderStringBuilder(1); var zTestBuilder = new ShaderStringBuilder(1); var zWriteBuilder = new ShaderStringBuilder(1); materialOptions.GetBlend(blendingBuilder); materialOptions.GetCull(cullingBuilder); materialOptions.GetDepthTest(zTestBuilder); materialOptions.GetDepthWrite(zWriteBuilder); // ------------------------------------- // Generate defines if (masterNode.IsSlotConnected(PBRMasterNode.NormalSlotId)) { defines.AppendLine("#define _NORMALMAP 1"); } if (masterNode.model == PBRMasterNode.Model.Specular) { defines.AppendLine("#define _SPECULAR_SETUP 1"); } if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId)) { defines.AppendLine("#define _AlphaClip 1"); } if (masterNode.surfaceType == SurfaceType.Transparent && masterNode.alphaMode == AlphaMode.Premultiply) { defines.AppendLine("#define _ALPHAPREMULTIPLY_ON 1"); } if (graphRequirements.requiresDepthTexture) { defines.AppendLine("#define REQUIRE_DEPTH_TEXTURE"); } if (graphRequirements.requiresCameraOpaqueTexture) { defines.AppendLine("#define REQUIRE_OPAQUE_TEXTURE"); } // ----------------------------------------------------- // // START VERTEX DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex Description function // TODO - Vertex Description Input requirements are needed to exclude intermediate translation spaces vertexDescriptionInputStruct.AppendLine("struct VertexDescriptionInputs"); using (vertexDescriptionInputStruct.BlockSemicolonScope()) { ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexDescriptionInputStruct); if (vertexRequirements.requiresVertexColor) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (vertexRequirements.requiresScreenPosition) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct()) { vertexDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Vertex Description function GraphUtil.GenerateVertexDescriptionStruct(vertexDescriptionStruct, vertexSlots); // ------------------------------------- // Generate Vertex Description function GraphUtil.GenerateVertexDescriptionFunction( masterNode.owner as AbstractMaterialGraph, vertexDescriptionFunction, functionRegistry, shaderProperties, mode, vertexNodes, vertexSlots); // ----------------------------------------------------- // // START SURFACE DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Surface Description function // Surface Description Input requirements are needed to exclude intermediate translation spaces surfaceDescriptionInputStruct.AppendLine("struct SurfaceDescriptionInputs"); using (surfaceDescriptionInputStruct.BlockSemicolonScope()) { ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresNormal, InterpolatorType.Normal, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresTangent, InterpolatorType.Tangent, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresBitangent, InterpolatorType.BiTangent, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresViewDir, InterpolatorType.ViewDirection, surfaceDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresPosition, InterpolatorType.Position, surfaceDescriptionInputStruct); if (surfaceRequirements.requiresVertexColor) { surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (surfaceRequirements.requiresScreenPosition) { surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } if (surfaceRequirements.requiresFaceSign) { surfaceDescriptionInputStruct.AppendLine("float {0};", ShaderGeneratorNames.FaceSign); } foreach (var channel in surfaceRequirements.requiresMeshUVs.Distinct()) { surfaceDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Surface Description function GraphUtil.GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, pixelSlots, true); // ------------------------------------- // Generate Surface Description function GraphUtil.GenerateSurfaceDescriptionFunction( pixelNodes, masterNode, masterNode.owner as AbstractMaterialGraph, surfaceDescriptionFunction, functionRegistry, shaderProperties, pixelRequirements, mode, "PopulateSurfaceData", "SurfaceDescription", null, pixelSlots); // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex shader GraphUtil.GenerateApplicationVertexInputs(vertexRequirements.Union(pixelRequirements.Union(modelRequiements)), vertexInputStruct); // ------------------------------------- // Generate standard transformations // This method ensures all required transform data is available in vertex and pixel stages ShaderGenerator.GenerateStandardTransforms( 3, 10, vertexOutputStruct, vertexShader, vertexShaderDescriptionInputs, vertexShaderOutputs, pixelShader, pixelShaderSurfaceInputs, pixelRequirements, surfaceRequirements, modelRequiements, vertexRequirements, CoordinateSpace.World); // ------------------------------------- // Generate pixel shader surface remap foreach (var slot in pixelSlots) { pixelShaderSurfaceRemap.AppendLine("{0} = surf.{0};", slot.shaderOutputName); } // ------------------------------------- // Extra pixel shader work var faceSign = new ShaderStringBuilder(); if (pixelRequirements.requiresFaceSign) { faceSign.AppendLine(", half FaceSign : VFACE"); } // ----------------------------------------------------- // // FINALIZE // // ----------------------------------------------------- // // ------------------------------------- // Combine Graph sections graph.AppendLine(shaderProperties.GetPropertiesDeclaration(1)); graph.AppendLine(vertexDescriptionInputStruct.ToString()); graph.AppendLine(surfaceDescriptionInputStruct.ToString()); graph.AppendLine(functionBuilder.ToString()); graph.AppendLine(vertexDescriptionStruct.ToString()); graph.AppendLine(vertexDescriptionFunction.ToString()); graph.AppendLine(surfaceDescriptionStruct.ToString()); graph.AppendLine(surfaceDescriptionFunction.ToString()); graph.AppendLine(vertexInputStruct.ToString()); // ------------------------------------- // Generate final subshader var resultPass = template.Replace("${Tags}", string.Empty); resultPass = resultPass.Replace("${Blending}", blendingBuilder.ToString()); resultPass = resultPass.Replace("${Culling}", cullingBuilder.ToString()); resultPass = resultPass.Replace("${ZTest}", zTestBuilder.ToString()); resultPass = resultPass.Replace("${ZWrite}", zWriteBuilder.ToString()); resultPass = resultPass.Replace("${Defines}", defines.ToString()); resultPass = resultPass.Replace("${Graph}", graph.ToString()); resultPass = resultPass.Replace("${VertexOutputStruct}", vertexOutputStruct.ToString()); resultPass = resultPass.Replace("${VertexShader}", vertexShader.ToString()); resultPass = resultPass.Replace("${VertexShaderDescriptionInputs}", vertexShaderDescriptionInputs.ToString()); resultPass = resultPass.Replace("${VertexShaderOutputs}", vertexShaderOutputs.ToString()); resultPass = resultPass.Replace("${FaceSign}", faceSign.ToString()); resultPass = resultPass.Replace("${PixelShader}", pixelShader.ToString()); resultPass = resultPass.Replace("${PixelShaderSurfaceInputs}", pixelShaderSurfaceInputs.ToString()); resultPass = resultPass.Replace("${PixelShaderSurfaceRemap}", pixelShaderSurfaceRemap.ToString()); return(resultPass); }
static string GetExtraPassesFromTemplate(string template, PBRMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // String builders var dummyBuilder = new ShaderStringBuilder(0); var shaderProperties = new PropertyCollector(); var functionBuilder = new ShaderStringBuilder(1); var functionRegistry = new FunctionRegistry(functionBuilder); var defines = new ShaderStringBuilder(2); var graph = new ShaderStringBuilder(0); var vertexDescriptionInputStruct = new ShaderStringBuilder(1); var vertexDescriptionStruct = new ShaderStringBuilder(1); var vertexDescriptionFunction = new ShaderStringBuilder(1); var vertexInputStruct = new ShaderStringBuilder(1); var vertexShader = new ShaderStringBuilder(2); var vertexDescriptionInputs = new ShaderStringBuilder(2); // ------------------------------------- // Get Slot and Node lists per stage var vertexSlots = pass.VertexShaderSlots.Select(masterNode.FindSlot <MaterialSlot>).ToList(); var vertexNodes = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots); // ------------------------------------- // Get requirements var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false); var modelRequiements = ShaderGraphRequirements.none; modelRequiements.requiresNormal |= m_VertexCoordinateSpace; modelRequiements.requiresPosition |= m_VertexCoordinateSpace; modelRequiements.requiresMeshUVs.Add(UVChannel.UV1); // ----------------------------------------------------- // // START SHADER GENERATION // // ----------------------------------------------------- // // ------------------------------------- // Calculate material options var cullingBuilder = new ShaderStringBuilder(1); materialOptions.GetCull(cullingBuilder); // ------------------------------------- // Generate defines if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId)) { defines.AppendLine("#define _AlphaClip 1"); } // ----------------------------------------------------- // // START VERTEX DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex Description function // TODO - Vertex Description Input requirements are needed to exclude intermediate translation spaces vertexDescriptionInputStruct.AppendLine("struct VertexDescriptionInputs"); using (vertexDescriptionInputStruct.BlockSemicolonScope()) { ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexDescriptionInputStruct); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexDescriptionInputStruct); if (vertexRequirements.requiresVertexColor) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor); } if (vertexRequirements.requiresScreenPosition) { vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition); } foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct()) { vertexDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName()); } } // ------------------------------------- // Generate Output structure for Vertex Description function GraphUtil.GenerateVertexDescriptionStruct(vertexDescriptionStruct, vertexSlots); // ------------------------------------- // Generate Vertex Description function GraphUtil.GenerateVertexDescriptionFunction( masterNode.owner as AbstractMaterialGraph, vertexDescriptionFunction, functionRegistry, shaderProperties, mode, vertexNodes, vertexSlots); // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // Generate Input structure for Vertex shader GraphUtil.GenerateApplicationVertexInputs(vertexRequirements.Union(modelRequiements), vertexInputStruct); // ------------------------------------- // Generate standard transformations // This method ensures all required transform data is available in vertex and pixel stages ShaderGenerator.GenerateStandardTransforms( 3, 10, dummyBuilder, vertexShader, vertexDescriptionInputs, dummyBuilder, dummyBuilder, dummyBuilder, ShaderGraphRequirements.none, ShaderGraphRequirements.none, modelRequiements, vertexRequirements, CoordinateSpace.World); // ----------------------------------------------------- // // FINALIZE // // ----------------------------------------------------- // // ------------------------------------- // Combine Graph sections graph.AppendLine(shaderProperties.GetPropertiesDeclaration(1)); graph.AppendLine(vertexDescriptionInputStruct.ToString()); graph.AppendLine(functionBuilder.ToString()); graph.AppendLine(vertexDescriptionStruct.ToString()); graph.AppendLine(vertexDescriptionFunction.ToString()); graph.AppendLine(vertexInputStruct.ToString()); // ------------------------------------- // Generate final subshader var resultPass = template.Replace("${Culling}", cullingBuilder.ToString()); resultPass = resultPass.Replace("${Defines}", defines.ToString()); resultPass = resultPass.Replace("${Graph}", graph.ToString()); resultPass = resultPass.Replace("${VertexShader}", vertexShader.ToString()); resultPass = resultPass.Replace("${VertexShaderDescriptionInputs}", vertexDescriptionInputs.ToString()); return(resultPass); }
private static string GetVariantDefines(PBRMasterNode masterNode) { ShaderGenerator defines = new ShaderGenerator(); // TODO: // _MATERIAL_FEATURE_SUBSURFACE_SCATTERING // _MATERIAL_FEATURE_TRANSMISSION // _MATERIAL_FEATURE_ANISOTROPY // _MATERIAL_FEATURE_CLEAR_COAT // _MATERIAL_FEATURE_IRIDESCENCE switch (masterNode.model) { case PBRMasterNode.Model.Metallic: break; case PBRMasterNode.Model.Specular: defines.AddShaderChunk("#define _MATERIAL_FEATURE_SPECULAR_COLOR 1", true); break; default: // TODO: error! break; } // #pragma shader_feature _ALPHATEST_ON float constantAlpha = 0.0f; if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) || (float.TryParse(masterNode.GetSlotValue(PBRMasterNode.AlphaThresholdSlotId, GenerationMode.ForReals), out constantAlpha) && (constantAlpha > 0.0f))) { defines.AddShaderChunk("#define _ALPHATEST_ON 1", true); } // if (kTesselationMode != TessellationMode.None) // { // defines.AddShaderChunk("#define _TESSELLATION_PHONG 1", true); // } // #pragma shader_feature _ _VERTEX_DISPLACEMENT _PIXEL_DISPLACEMENT // switch (kDisplacementMode) // { // case DisplacementMode.None: // break; // case DisplacementMode.Vertex: // defines.AddShaderChunk("#define _VERTEX_DISPLACEMENT 1", true); // break; // case DisplacementMode.Pixel: // defines.AddShaderChunk("#define _PIXEL_DISPLACEMENT 1", true); // Depth offset is only enabled if per pixel displacement is // if (kDepthOffsetEnable) // { // // #pragma shader_feature _DEPTHOFFSET_ON // defines.AddShaderChunk("#define _DEPTHOFFSET_ON 1", true); // } // break; // case DisplacementMode.Tessellation: // if (kTessellationEnabled) // { // defines.AddShaderChunk("#define _TESSELLATION_DISPLACEMENT 1", true); // } // break; // } // #pragma shader_feature _VERTEX_DISPLACEMENT_LOCK_OBJECT_SCALE // #pragma shader_feature _DISPLACEMENT_LOCK_TILING_SCALE // #pragma shader_feature _PIXEL_DISPLACEMENT_LOCK_OBJECT_SCALE // #pragma shader_feature _VERTEX_WIND // #pragma shader_feature _ _REFRACTION_PLANE _REFRACTION_SPHERE // // #pragma shader_feature _ _MAPPING_PLANAR _MAPPING_TRIPLANAR // MOVE to a node // #pragma shader_feature _NORMALMAP_TANGENT_SPACE // #pragma shader_feature _ _REQUIRE_UV2 _REQUIRE_UV3 // // #pragma shader_feature _NORMALMAP if (masterNode.IsSlotConnected(PBRMasterNode.NormalSlotId)) { defines.AddShaderChunk("#define _NORMALMAP 1", true); } // #pragma shader_feature _MASKMAP // #pragma shader_feature _BENTNORMALMAP // #pragma shader_feature _EMISSIVE_COLOR_MAP // #pragma shader_feature _ENABLESPECULAROCCLUSION // #pragma shader_feature _HEIGHTMAP // #pragma shader_feature _TANGENTMAP // #pragma shader_feature _ANISOTROPYMAP // #pragma shader_feature _DETAIL_MAP // MOVE to a node // #pragma shader_feature _SUBSURFACE_RADIUS_MAP // #pragma shader_feature _THICKNESSMAP // #pragma shader_feature _SPECULARCOLORMAP // #pragma shader_feature _TRANSMITTANCECOLORMAP // Keywords for transparent // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT if (masterNode.surfaceType != SurfaceType.Opaque) { // transparent-only defines defines.AddShaderChunk("#define _SURFACE_TYPE_TRANSPARENT 1", true); // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY if (masterNode.alphaMode == AlphaMode.Alpha) { defines.AddShaderChunk("#define _BLENDMODE_ALPHA 1", true); } else if (masterNode.alphaMode == AlphaMode.Additive) { defines.AddShaderChunk("#define _BLENDMODE_ADD 1", true); } // else if (masterNode.alphaMode == PBRMasterNode.AlphaMode.PremultiplyAlpha) // TODO // { // defines.AddShaderChunk("#define _BLENDMODE_PRE_MULTIPLY 1", true); // } // #pragma shader_feature _BLENDMODE_PRESERVE_SPECULAR_LIGHTING // if (kEnableBlendModePreserveSpecularLighting) // { // defines.AddShaderChunk("#define _BLENDMODE_PRESERVE_SPECULAR_LIGHTING 1", true); // } // #pragma shader_feature _ENABLE_FOG_ON_TRANSPARENT // if (kEnableFogOnTransparent) // { // defines.AddShaderChunk("#define _ENABLE_FOG_ON_TRANSPARENT 1", true); // } } else { // opaque-only defines } // MaterialId are used as shader feature to allow compiler to optimize properly // Note _MATID_STANDARD is not define as there is always the default case "_". We assign default as _MATID_STANDARD, so we never test _MATID_STANDARD // #pragma shader_feature _ _MATID_SSS _MATID_ANISO _MATID_SPECULAR _MATID_CLEARCOAT // enable dithering LOD crossfade // #pragma multi_compile _ LOD_FADE_CROSSFADE // TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ? //#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON return(defines.GetShaderString(2)); }
private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass) { HashSet <string> activeFields = new HashSet <string>(); PBRMasterNode masterNode = iMasterNode as PBRMasterNode; if (masterNode == null) { return(activeFields); } if (masterNode.twoSided.isOn) { activeFields.Add("DoubleSided"); if (pass.ShaderPassName != "SHADERPASS_VELOCITY") // HACK to get around lack of a good interpolator dependency system { // we need to be able to build interpolators using multiple input structs // also: should only require isFrontFace if Normals are required... activeFields.Add("DoubleSided.Mirror"); // TODO: change this depending on what kind of normal flip you want.. activeFields.Add("FragInputs.isFrontFace"); // will need this for determining normal flip mode } } switch (masterNode.model) { case PBRMasterNode.Model.Metallic: break; case PBRMasterNode.Model.Specular: activeFields.Add("Material.SpecularColor"); break; default: // TODO: error! break; } float constantAlpha = 0.0f; if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) || (float.TryParse(masterNode.GetSlotValue(PBRMasterNode.AlphaThresholdSlotId, GenerationMode.ForReals), out constantAlpha) && (constantAlpha > 0.0f))) { activeFields.Add("AlphaTest"); } // Keywords for transparent // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT if (masterNode.surfaceType != SurfaceType.Opaque) { // transparent-only defines activeFields.Add("SurfaceType.Transparent"); // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY if (masterNode.alphaMode == AlphaMode.Alpha) { activeFields.Add("BlendMode.Alpha"); } else if (masterNode.alphaMode == AlphaMode.Additive) { activeFields.Add("BlendMode.Add"); } // else if (masterNode.alphaMode == PBRMasterNode.AlphaMode.PremultiplyAlpha) // TODO // { // defines.AddShaderChunk("#define _BLENDMODE_PRE_MULTIPLY 1", true); // } } else { // opaque-only defines } // enable dithering LOD crossfade // #pragma multi_compile _ LOD_FADE_CROSSFADE // TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ? //#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON return(activeFields); }
private static string GetShaderPassFromTemplate(string template, PBRMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions) { var builder = new ShaderStringBuilder(); builder.IncreaseIndent(); builder.IncreaseIndent(); var vertexInputs = new ShaderGenerator(); var surfaceVertexShader = new ShaderGenerator(); var surfaceDescriptionFunction = new ShaderGenerator(); var surfaceDescriptionStruct = new ShaderGenerator(); var functionRegistry = new FunctionRegistry(builder); var surfaceInputs = new ShaderGenerator(); var shaderProperties = new PropertyCollector(); surfaceInputs.AddShaderChunk("struct SurfaceInputs{", false); surfaceInputs.Indent(); var activeNodeList = ListPool <INode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots); var requirements = ShaderGraphRequirements.FromNodes(activeNodeList); var modelRequiements = ShaderGraphRequirements.none; modelRequiements.requiresNormal |= NeededCoordinateSpace.World; modelRequiements.requiresTangent |= NeededCoordinateSpace.World; modelRequiements.requiresBitangent |= NeededCoordinateSpace.World; modelRequiements.requiresPosition |= NeededCoordinateSpace.World; modelRequiements.requiresViewDir |= NeededCoordinateSpace.World; modelRequiements.requiresMeshUVs.Add(UVChannel.UV1); GraphUtil.GenerateApplicationVertexInputs(requirements.Union(modelRequiements), vertexInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, surfaceInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, surfaceInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, surfaceInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, surfaceInputs); ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, surfaceInputs); if (requirements.requiresVertexColor) { surfaceInputs.AddShaderChunk(string.Format("float4 {0};", ShaderGeneratorNames.VertexColor), false); } if (requirements.requiresScreenPosition) { surfaceInputs.AddShaderChunk(string.Format("float4 {0};", ShaderGeneratorNames.ScreenPosition), false); } foreach (var channel in requirements.requiresMeshUVs.Distinct()) { surfaceInputs.AddShaderChunk(string.Format("half4 {0};", channel.GetUVName()), false); } surfaceInputs.Deindent(); surfaceInputs.AddShaderChunk("};", false); surfaceVertexShader.AddShaderChunk("GraphVertexInput PopulateVertexData(GraphVertexInput v){", false); surfaceVertexShader.Indent(); surfaceVertexShader.AddShaderChunk("return v;", false); surfaceVertexShader.Deindent(); surfaceVertexShader.AddShaderChunk("}", false); var slots = new List <MaterialSlot>(); foreach (var id in pass.PixelShaderSlots) { slots.Add(masterNode.FindSlot <MaterialSlot>(id)); } GraphUtil.GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, true); var usedSlots = new List <MaterialSlot>(); foreach (var id in pass.PixelShaderSlots) { usedSlots.Add(masterNode.FindSlot <MaterialSlot>(id)); } GraphUtil.GenerateSurfaceDescription( activeNodeList, masterNode, masterNode.owner as AbstractMaterialGraph, surfaceDescriptionFunction, functionRegistry, shaderProperties, requirements, mode, "PopulateSurfaceData", "SurfaceDescription", null, usedSlots); var graph = new ShaderGenerator(); graph.AddShaderChunk(shaderProperties.GetPropertiesDeclaration(2), false); graph.AddShaderChunk(surfaceInputs.GetShaderString(2), false); graph.AddShaderChunk(builder.ToString(), false); graph.AddShaderChunk(vertexInputs.GetShaderString(2), false); graph.AddShaderChunk(surfaceDescriptionStruct.GetShaderString(2), false); graph.AddShaderChunk(surfaceVertexShader.GetShaderString(2), false); graph.AddShaderChunk(surfaceDescriptionFunction.GetShaderString(2), false); var blendingVisitor = new ShaderGenerator(); var cullingVisitor = new ShaderGenerator(); var zTestVisitor = new ShaderGenerator(); var zWriteVisitor = new ShaderGenerator(); materialOptions.GetBlend(blendingVisitor); materialOptions.GetCull(cullingVisitor); materialOptions.GetDepthTest(zTestVisitor); materialOptions.GetDepthWrite(zWriteVisitor); var interpolators = new ShaderGenerator(); var localVertexShader = new ShaderGenerator(); var localPixelShader = new ShaderGenerator(); var localSurfaceInputs = new ShaderGenerator(); var surfaceOutputRemap = new ShaderGenerator(); ShaderGenerator.GenerateStandardTransforms( 3, 10, interpolators, localVertexShader, localPixelShader, localSurfaceInputs, requirements, modelRequiements, CoordinateSpace.World); ShaderGenerator defines = new ShaderGenerator(); if (masterNode.IsSlotConnected(PBRMasterNode.NormalSlotId)) { defines.AddShaderChunk("#define _NORMALMAP 1", true); } if (masterNode.model == PBRMasterNode.Model.Specular) { defines.AddShaderChunk("#define _SPECULAR_SETUP 1", true); } if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId)) { defines.AddShaderChunk("#define _AlphaClip 1", true); } if (masterNode.surfaceType == SurfaceType.Transparent && masterNode.alphaMode == AlphaMode.Premultiply) { defines.AddShaderChunk("#define _ALPHAPREMULTIPLY_ON 1", true); } var templateLocation = GetTemplatePath(template); foreach (var slot in usedSlots) { surfaceOutputRemap.AddShaderChunk(string.Format("{0} = surf.{0};", slot.shaderOutputName), true); } if (!File.Exists(templateLocation)) { return(string.Empty); } var subShaderTemplate = File.ReadAllText(templateLocation); var resultPass = subShaderTemplate.Replace("${Defines}", defines.GetShaderString(3)); resultPass = resultPass.Replace("${Graph}", graph.GetShaderString(3)); resultPass = resultPass.Replace("${Interpolators}", interpolators.GetShaderString(3)); resultPass = resultPass.Replace("${VertexShader}", localVertexShader.GetShaderString(3)); resultPass = resultPass.Replace("${LocalPixelShader}", localPixelShader.GetShaderString(3)); resultPass = resultPass.Replace("${SurfaceInputs}", localSurfaceInputs.GetShaderString(3)); resultPass = resultPass.Replace("${SurfaceOutputRemap}", surfaceOutputRemap.GetShaderString(3)); resultPass = resultPass.Replace("${Tags}", string.Empty); resultPass = resultPass.Replace("${Blending}", blendingVisitor.GetShaderString(2)); resultPass = resultPass.Replace("${Culling}", cullingVisitor.GetShaderString(2)); resultPass = resultPass.Replace("${ZTest}", zTestVisitor.GetShaderString(2)); resultPass = resultPass.Replace("${ZWrite}", zWriteVisitor.GetShaderString(2)); return(resultPass); }