public static string GetPreviewSubShader(AbstractMaterialNode node, ShaderGraphRequirements shaderGraphRequirements) { // Should never be called without a node Debug.Assert(node != null); var vertexOutputStruct = new ShaderStringBuilder(2); var vertexShader = new ShaderStringBuilder(2); var vertexShaderDescriptionInputs = new ShaderStringBuilder(2); var vertexShaderOutputs = new ShaderStringBuilder(1); var pixelShader = new ShaderStringBuilder(2); var pixelShaderSurfaceInputs = new ShaderStringBuilder(2); var pixelShaderSurfaceRemap = new ShaderStringBuilder(2); ShaderGenerator.GenerateStandardTransforms( 0, 16, vertexOutputStruct, vertexShader, vertexShaderDescriptionInputs, vertexShaderOutputs, pixelShader, pixelShaderSurfaceInputs, shaderGraphRequirements, shaderGraphRequirements, ShaderGraphRequirements.none, ShaderGraphRequirements.none, CoordinateSpace.World); vertexShader.AppendLines(vertexShaderDescriptionInputs.ToString()); vertexShader.AppendLines(vertexShaderOutputs.ToString()); var outputSlot = node.GetOutputSlots <MaterialSlot>().FirstOrDefault(); // Sub Graph Output uses first input slot if (node is SubGraphOutputNode) { outputSlot = node.GetInputSlots <MaterialSlot>().FirstOrDefault(); } if (outputSlot != null) { var result = $"surf.{NodeUtils.GetHLSLSafeName(outputSlot.shaderOutputName)}_{outputSlot.id}"; pixelShaderSurfaceRemap.AppendLine("return all(isfinite({0})) ? {1} : {2};", result, AdaptNodeOutputForPreview(node, outputSlot.id, result), nanOutput); } else { // No valid slots to display, so just show black. // It's up to each node to error or warn as appropriate. pixelShaderSurfaceRemap.AppendLine("return 0;"); } // ------------------------------------- // Extra pixel shader work var faceSign = new ShaderStringBuilder(); if (shaderGraphRequirements.requiresFaceSign) { faceSign.AppendLine(", half FaceSign : VFACE"); } var res = subShaderTemplate.Replace("${Interpolators}", vertexOutputStruct.ToString()); res = res.Replace("${VertexShader}", vertexShader.ToString()); res = res.Replace("${FaceSign}", faceSign.ToString()); res = res.Replace("${LocalPixelShader}", pixelShader.ToString()); res = res.Replace("${SurfaceInputs}", pixelShaderSurfaceInputs.ToString()); res = res.Replace("${SurfaceOutputRemap}", pixelShaderSurfaceRemap.ToString()); return(res); }
static void AddActiveFieldsFromGraphRequirements(IActiveFields activeFields, ShaderGraphRequirements requirements, string structName) { if (requirements.requiresScreenPosition) { activeFields.Add($"{structName}.ScreenPosition"); } if (requirements.requiresVertexColor) { activeFields.Add($"{structName}.VertexColor"); } if (requirements.requiresFaceSign) { activeFields.Add($"{structName}.FaceSign"); } if (requirements.requiresNormal != 0) { if ((requirements.requiresNormal & NeededCoordinateSpace.Object) > 0) { activeFields.Add($"{structName}.ObjectSpaceNormal"); } if ((requirements.requiresNormal & NeededCoordinateSpace.View) > 0) { activeFields.Add($"{structName}.ViewSpaceNormal"); } if ((requirements.requiresNormal & NeededCoordinateSpace.World) > 0) { activeFields.Add($"{structName}.WorldSpaceNormal"); } if ((requirements.requiresNormal & NeededCoordinateSpace.Tangent) > 0) { activeFields.Add($"{structName}.TangentSpaceNormal"); } } if (requirements.requiresTangent != 0) { if ((requirements.requiresTangent & NeededCoordinateSpace.Object) > 0) { activeFields.Add($"{structName}.ObjectSpaceTangent"); } if ((requirements.requiresTangent & NeededCoordinateSpace.View) > 0) { activeFields.Add($"{structName}.ViewSpaceTangent"); } if ((requirements.requiresTangent & NeededCoordinateSpace.World) > 0) { activeFields.Add($"{structName}.WorldSpaceTangent"); } if ((requirements.requiresTangent & NeededCoordinateSpace.Tangent) > 0) { activeFields.Add($"{structName}.TangentSpaceTangent"); } } if (requirements.requiresBitangent != 0) { if ((requirements.requiresBitangent & NeededCoordinateSpace.Object) > 0) { activeFields.Add($"{structName}.ObjectSpaceBiTangent"); } if ((requirements.requiresBitangent & NeededCoordinateSpace.View) > 0) { activeFields.Add($"{structName}.ViewSpaceBiTangent"); } if ((requirements.requiresBitangent & NeededCoordinateSpace.World) > 0) { activeFields.Add($"{structName}.WorldSpaceBiTangent"); } if ((requirements.requiresBitangent & NeededCoordinateSpace.Tangent) > 0) { activeFields.Add($"{structName}.TangentSpaceBiTangent"); } } if (requirements.requiresViewDir != 0) { if ((requirements.requiresViewDir & NeededCoordinateSpace.Object) > 0) { activeFields.Add($"{structName}.ObjectSpaceViewDirection"); } if ((requirements.requiresViewDir & NeededCoordinateSpace.View) > 0) { activeFields.Add($"{structName}.ViewSpaceViewDirection"); } if ((requirements.requiresViewDir & NeededCoordinateSpace.World) > 0) { activeFields.Add($"{structName}.WorldSpaceViewDirection"); } if ((requirements.requiresViewDir & NeededCoordinateSpace.Tangent) > 0) { activeFields.Add($"{structName}.TangentSpaceViewDirection"); } } if (requirements.requiresPosition != 0) { if ((requirements.requiresPosition & NeededCoordinateSpace.Object) > 0) { activeFields.Add($"{structName}.ObjectSpacePosition"); } if ((requirements.requiresPosition & NeededCoordinateSpace.View) > 0) { activeFields.Add($"{structName}.ViewSpacePosition"); } if ((requirements.requiresPosition & NeededCoordinateSpace.World) > 0) { activeFields.Add($"{structName}.WorldSpacePosition"); } if ((requirements.requiresPosition & NeededCoordinateSpace.Tangent) > 0) { activeFields.Add($"{structName}.TangentSpacePosition"); } if ((requirements.requiresPosition & NeededCoordinateSpace.AbsoluteWorld) > 0) { activeFields.Add($"{structName}.AbsoluteWorldSpacePosition"); } } foreach (var channel in requirements.requiresMeshUVs.Distinct()) { activeFields.Add($"{structName}.{channel.GetUVName()}"); } if (requirements.requiresTime) { activeFields.Add($"{structName}.TimeParameters"); } if (requirements.requiresVertexSkinning) { activeFields.Add($"{structName}.BoneWeights"); activeFields.Add($"{structName}.BoneIndices"); } }
public static void GenerateStandardTransforms( int interpolatorStartIndex, int maxInterpolators, ShaderStringBuilder vertexOutputStruct, ShaderStringBuilder vertexShader, ShaderStringBuilder vertexShaderDescriptionInputs, ShaderStringBuilder vertexShaderOutputs, ShaderStringBuilder pixelShader, ShaderStringBuilder pixelShaderSurfaceInputs, ShaderGraphRequirements pixelRequirements, ShaderGraphRequirements surfaceRequirements, ShaderGraphRequirements modelRequiements, ShaderGraphRequirements vertexRequirements, CoordinateSpace preferredCoordinateSpace) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // Tangent space requires going via World space if (preferredCoordinateSpace == CoordinateSpace.Tangent) { preferredCoordinateSpace = CoordinateSpace.World; } // ------------------------------------- // Generate combined graph requirements var graphModelRequirements = pixelRequirements.Union(modelRequiements); var combinedRequirements = vertexRequirements.Union(graphModelRequirements); int interpolatorIndex = interpolatorStartIndex; // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // If any stage requires component write into vertex stage // If model or pixel requires component write into interpolators and pixel stage // ------------------------------------- // Position if (combinedRequirements.requiresPosition > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Position); var preferredSpacePosition = ConvertBetweenSpace("v.vertex", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Position); vertexShader.AppendLine("float3 {0} = {1}.xyz;", name, preferredSpacePosition); if (graphModelRequirements.requiresPosition > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // Normal // Bitangent needs Normal for x product if (combinedRequirements.requiresNormal > 0 || combinedRequirements.requiresBitangent > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal); vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.normal", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Normal)); if (graphModelRequirements.requiresNormal > 0 || graphModelRequirements.requiresBitangent > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // Tangent if (combinedRequirements.requiresTangent > 0 || combinedRequirements.requiresBitangent > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent); vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.tangent.xyz", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Vector)); if (graphModelRequirements.requiresTangent > 0 || graphModelRequirements.requiresBitangent > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // Bitangent if (combinedRequirements.requiresBitangent > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent); vertexShader.AppendLine("float3 {0} = cross({1}, {2}.xyz) * {3};", name, preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal), preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent), "v.tangent.w"); if (graphModelRequirements.requiresBitangent > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // View Direction if (combinedRequirements.requiresViewDir > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.ViewDirection); const string worldSpaceViewDir = "_WorldSpaceCameraPos.xyz - mul(GetObjectToWorldMatrix(), float4(v.vertex.xyz, 1.0)).xyz"; var preferredSpaceViewDir = ConvertBetweenSpace(worldSpaceViewDir, CoordinateSpace.World, preferredCoordinateSpace, InputType.Vector); vertexShader.AppendLine("float3 {0} = {1};", name, preferredSpaceViewDir); if (graphModelRequirements.requiresViewDir > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // Tangent space transform matrix if (combinedRequirements.NeedsTangentSpace()) { var tangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent); var bitangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent); var normal = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal); if (vertexRequirements.NeedsTangentSpace()) { vertexShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});", tangent, bitangent, normal); } if (graphModelRequirements.NeedsTangentSpace()) { pixelShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});", tangent, bitangent, normal); } } // ------------------------------------- // Vertex Color if (combinedRequirements.requiresVertexColor) { var vertexColor = "v.color"; vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.VertexColor, vertexColor); if (graphModelRequirements.requiresVertexColor) { vertexOutputStruct.AppendLine("float4 {0} : COLOR;", ShaderGeneratorNames.VertexColor); vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.VertexColor); pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor); } } // ------------------------------------- // Screen Position if (combinedRequirements.requiresScreenPosition) { var screenPosition = "ComputeScreenPos(mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), v.vertex)), _ProjectionParams.x)"; vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.ScreenPosition, screenPosition); if (graphModelRequirements.requiresScreenPosition) { vertexOutputStruct.AppendLine("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ScreenPosition, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.ScreenPosition); pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition); interpolatorIndex++; } } // ------------------------------------- // UV foreach (var channel in combinedRequirements.requiresMeshUVs.Distinct()) { vertexShader.AppendLine("float4 {0} = v.texcoord{1};", channel.GetUVName(), (int)channel); } foreach (var channel in graphModelRequirements.requiresMeshUVs.Distinct()) { vertexOutputStruct.AppendLine("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString()); vertexShaderOutputs.AppendLine("o.{0} = {0};", channel.GetUVName()); pixelShader.AppendLine("float4 {0} = IN.{0};", channel.GetUVName()); interpolatorIndex++; } // ----------------------------------------------------- // // TRANSLATE NEEDED SPACES // // ----------------------------------------------------- // // ------------------------------------- // Generate the space translations needed by the vertex description GenerateSpaceTranslations(vertexRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace, InputType.Normal, vertexShader, Dimension.Three); GenerateSpaceTranslations(vertexRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace, InputType.Vector, vertexShader, Dimension.Three); GenerateSpaceTranslations(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace, InputType.Vector, vertexShader, Dimension.Three); GenerateSpaceTranslations(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace, InputType.Vector, vertexShader, Dimension.Three); GenerateSpaceTranslations(vertexRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace, InputType.Position, vertexShader, Dimension.Three); // ------------------------------------- // Generate the space translations needed by the surface description and model GenerateSpaceTranslations(graphModelRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace, InputType.Normal, pixelShader, Dimension.Three); GenerateSpaceTranslations(graphModelRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); GenerateSpaceTranslations(graphModelRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); GenerateSpaceTranslations(graphModelRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); GenerateSpaceTranslations(graphModelRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace, InputType.Position, pixelShader, Dimension.Three); // ----------------------------------------------------- // // START SURFACE DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Copy the locally defined values into the surface description // structure using the requirements for ONLY the shader graph pixel stage // additional requirements have come from the lighting model // and are not needed in the shader graph { var replaceString = "surfaceInput.{0} = {0};"; GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresNormal, InterpolatorType.Normal, pixelShaderSurfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresTangent, InterpolatorType.Tangent, pixelShaderSurfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresBitangent, InterpolatorType.BiTangent, pixelShaderSurfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresViewDir, InterpolatorType.ViewDirection, pixelShaderSurfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresPosition, InterpolatorType.Position, pixelShaderSurfaceInputs, replaceString); } if (pixelRequirements.requiresVertexColor) { pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.VertexColor); } if (pixelRequirements.requiresScreenPosition) { pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.ScreenPosition); } if (pixelRequirements.requiresFaceSign) { pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.FaceSign); } foreach (var channel in pixelRequirements.requiresMeshUVs.Distinct()) { pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.GetUVName(channel)); } // ----------------------------------------------------- // // START VERTEX DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Copy the locally defined values into the vertex description // structure using the requirements for ONLY the shader graph vertex stage // additional requirements have come from the lighting model // and are not needed in the shader graph { var replaceString = "vdi.{0} = {0};"; GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexShaderDescriptionInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexShaderDescriptionInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexShaderDescriptionInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexShaderDescriptionInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexShaderDescriptionInputs, replaceString); } if (vertexRequirements.requiresVertexColor) { vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.VertexColor); } if (vertexRequirements.requiresScreenPosition) { vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.ScreenPosition); } foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct()) { vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", channel.GetUVName(), (int)channel); } }
static void GetActiveFieldsAndPermutationsForNodes(AbstractMaterialNode masterNode, ShaderPass pass, KeywordCollector keywordCollector, List <AbstractMaterialNode> vertexNodes, List <AbstractMaterialNode> pixelNodes, List <int>[] vertexNodePermutations, List <int>[] pixelNodePermutations, ActiveFields activeFields, out ShaderGraphRequirementsPerKeyword graphRequirements) { // Initialize requirements ShaderGraphRequirementsPerKeyword pixelRequirements = new ShaderGraphRequirementsPerKeyword(); ShaderGraphRequirementsPerKeyword vertexRequirements = new ShaderGraphRequirementsPerKeyword(); graphRequirements = new ShaderGraphRequirementsPerKeyword(); // Evaluate all Keyword permutations if (keywordCollector.permutations.Count > 0) { for (int i = 0; i < keywordCollector.permutations.Count; i++) { // Get active nodes for this permutation var localVertexNodes = Graphing.ListPool <AbstractMaterialNode> .Get(); var localPixelNodes = Graphing.ListPool <AbstractMaterialNode> .Get(); NodeUtils.DepthFirstCollectNodesFromNode(localVertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.vertexPorts, keywordCollector.permutations[i]); NodeUtils.DepthFirstCollectNodesFromNode(localPixelNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.pixelPorts, keywordCollector.permutations[i]); // Track each vertex node in this permutation foreach (AbstractMaterialNode vertexNode in localVertexNodes) { int nodeIndex = vertexNodes.IndexOf(vertexNode); if (vertexNodePermutations[nodeIndex] == null) { vertexNodePermutations[nodeIndex] = new List <int>(); } vertexNodePermutations[nodeIndex].Add(i); } // Track each pixel node in this permutation foreach (AbstractMaterialNode pixelNode in localPixelNodes) { int nodeIndex = pixelNodes.IndexOf(pixelNode); if (pixelNodePermutations[nodeIndex] == null) { pixelNodePermutations[nodeIndex] = new List <int>(); } pixelNodePermutations[nodeIndex].Add(i); } // Get requirements for this permutation vertexRequirements[i].SetRequirements(ShaderGraphRequirements.FromNodes(localVertexNodes, ShaderStageCapability.Vertex, false)); pixelRequirements[i].SetRequirements(ShaderGraphRequirements.FromNodes(localPixelNodes, ShaderStageCapability.Fragment, false)); // Add active fields AddActiveFieldsFromGraphRequirements(activeFields[i], vertexRequirements[i].requirements, "VertexDescriptionInputs"); AddActiveFieldsFromGraphRequirements(activeFields[i], pixelRequirements[i].requirements, "SurfaceDescriptionInputs"); } } // No Keywords else { // Get requirements vertexRequirements.baseInstance.SetRequirements(ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false)); pixelRequirements.baseInstance.SetRequirements(ShaderGraphRequirements.FromNodes(pixelNodes, ShaderStageCapability.Fragment, false)); // Add active fields AddActiveFieldsFromGraphRequirements(activeFields.baseInstance, vertexRequirements.baseInstance.requirements, "VertexDescriptionInputs"); AddActiveFieldsFromGraphRequirements(activeFields.baseInstance, pixelRequirements.baseInstance.requirements, "SurfaceDescriptionInputs"); } // Build graph requirements graphRequirements.UnionWith(pixelRequirements); graphRequirements.UnionWith(vertexRequirements); }