public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode) { visitor.AddShaderChunk(string.Format("{0}3 {1} = {0}3{2};", precision, GetVariableNameForSlot(kOutputSlotId), m_MaterialList[material].ToString(CultureInfo.InvariantCulture)), true); }
public static void GenerateStandardTransforms( int interpolatorStartIndex, int maxInterpolators, ShaderGenerator interpolators, ShaderGenerator vertexShader, ShaderGenerator pixelShader, ShaderGenerator surfaceInputs, ShaderGraphRequirements graphRequiements, ShaderGraphRequirements modelRequiements, CoordinateSpace preferedCoordinateSpace) { if (preferedCoordinateSpace == CoordinateSpace.Tangent) { preferedCoordinateSpace = CoordinateSpace.World; } // step 1: // *generate needed interpolators // *generate output from the vertex shader that writes into these interpolators // *generate the pixel shader code that declares needed variables in the local scope var combinedRequierments = graphRequiements.Union(modelRequiements); int interpolatorIndex = interpolatorStartIndex; // bitangent needs normal for x product if (combinedRequierments.requiresNormal > 0 || combinedRequierments.requiresBitangent > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.Normal); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = {1};", name, ConvertBetweenSpace("v.normal", CoordinateSpace.Object, preferedCoordinateSpace, InputType.Normal)), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = normalize(IN.{0});", name), false); interpolatorIndex++; } if (combinedRequierments.requiresTangent > 0 || combinedRequierments.requiresBitangent > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.Tangent); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = {1};", name, ConvertBetweenSpace("v.tangent", CoordinateSpace.Object, preferedCoordinateSpace, InputType.Vector)), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = IN.{0};", name), false); interpolatorIndex++; } if (combinedRequierments.requiresBitangent > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.BiTangent); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = normalize(cross(o.{1}, o.{2}.xyz) * {3});", name, preferedCoordinateSpace.ToVariableName(InterpolatorType.Normal), preferedCoordinateSpace.ToVariableName(InterpolatorType.Tangent), "v.tangent.w"), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = IN.{0};", name), false); interpolatorIndex++; } if (combinedRequierments.requiresViewDir > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.ViewDirection); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); var worldSpaceViewDir = "SafeNormalize(_WorldSpaceCameraPos.xyz - mul(GetObjectToWorldMatrix(), float4(v.vertex.xyz, 1.0)).xyz)"; vertexShader.AddShaderChunk(string.Format("o.{0} = {1};", name, ConvertBetweenSpace(worldSpaceViewDir, CoordinateSpace.World, preferedCoordinateSpace, InputType.Vector)), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = normalize(IN.{0});", name), false); interpolatorIndex++; } if (combinedRequierments.requiresPosition > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.Position); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = {1};", name, ConvertBetweenSpace("v.vertex", CoordinateSpace.Object, preferedCoordinateSpace, InputType.Position)), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = IN.{0};", name), false); interpolatorIndex++; } if (combinedRequierments.NeedsTangentSpace()) { pixelShader.AddShaderChunk(string.Format("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});", preferedCoordinateSpace.ToVariableName(InterpolatorType.Tangent), preferedCoordinateSpace.ToVariableName(InterpolatorType.BiTangent), preferedCoordinateSpace.ToVariableName(InterpolatorType.Normal)), false); } ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresNormal, InterpolatorType.Normal, preferedCoordinateSpace, InputType.Normal, pixelShader, Dimension.Three); ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresTangent, InterpolatorType.Tangent, preferedCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresBitangent, InterpolatorType.BiTangent, preferedCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresViewDir, InterpolatorType.ViewDirection, preferedCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresPosition, InterpolatorType.Position, preferedCoordinateSpace, InputType.Position, pixelShader, Dimension.Three); if (combinedRequierments.requiresVertexColor) { interpolators.AddShaderChunk(string.Format("float4 {0} : COLOR;", ShaderGeneratorNames.VertexColor), false); vertexShader.AddShaderChunk(string.Format("o.{0} = v.color;", ShaderGeneratorNames.VertexColor), false); pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor), false); } if (combinedRequierments.requiresScreenPosition) { interpolators.AddShaderChunk(string.Format("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ScreenPosition, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = ComputeScreenPos(mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), v.vertex)), _ProjectionParams.x);", ShaderGeneratorNames.ScreenPosition), false); pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition), false); interpolatorIndex++; } foreach (var channel in combinedRequierments.requiresMeshUVs.Distinct()) { interpolators.AddShaderChunk(string.Format("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString()), false); vertexShader.AddShaderChunk(string.Format("o.{0} = v.texcoord{1};", channel.GetUVName(), (int)channel), false); pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", channel.GetUVName()), false); interpolatorIndex++; } // step 2 // copy the locally defined values into the surface description // structure using the requirements for ONLY the shader graph // additional requirements have come from the lighting model // and are not needed in the shader graph var replaceString = "surfaceInput.{0} = {0};"; GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresNormal, InterpolatorType.Normal, surfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresTangent, InterpolatorType.Tangent, surfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresBitangent, InterpolatorType.BiTangent, surfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresViewDir, InterpolatorType.ViewDirection, surfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresPosition, InterpolatorType.Position, surfaceInputs, replaceString); if (graphRequiements.requiresVertexColor) { surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", ShaderGeneratorNames.VertexColor), false); } if (graphRequiements.requiresScreenPosition) { surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", ShaderGeneratorNames.ScreenPosition), false); } foreach (var channel in graphRequiements.requiresMeshUVs.Distinct()) { surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", channel.GetUVName()), false); } }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { visitor.AddShaderChunk(precision + " " + GetVariableNameForNode() + " = " + m_constantList[constant].ToString(CultureInfo.InvariantCulture) + ";", true); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { visitor.AddShaderChunk(string.Format("{0}4 {1} = IN.{2};", precision, GetVariableNameForSlot(OutputSlotId), m_OutputChannel.GetUVName()), true); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { var sb = new ShaderStringBuilder(); if (subGraphData == null || hasError) { var outputSlots = new List <MaterialSlot>(); GetOutputSlots(outputSlots); foreach (var slot in outputSlots) { visitor.AddShaderChunk($"{NodeUtils.ConvertConcreteSlotValueTypeToString(precision, slot.concreteValueType)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};"); } return; } var inputVariableName = $"_{GetVariableNameForNode()}"; GraphUtil.GenerateSurfaceInputTransferCode(sb, subGraphData.requirements, subGraphData.inputStructName, inputVariableName); visitor.AddShaderChunk(sb.ToString()); foreach (var outSlot in subGraphData.outputs) { visitor.AddShaderChunk(string.Format("{0} {1};", NodeUtils.ConvertConcreteSlotValueTypeToString(precision, outSlot.concreteValueType), GetVariableNameForSlot(outSlot.id))); } var arguments = new List <string>(); foreach (var prop in subGraphData.inputs) { var inSlotId = m_PropertyIds[m_PropertyGuids.IndexOf(prop.guid.ToString())]; if (prop is TextureShaderProperty) { arguments.Add(string.Format("TEXTURE2D_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode))); } else if (prop is Texture2DArrayShaderProperty) { arguments.Add(string.Format("TEXTURE2D_ARRAY_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode))); } else if (prop is Texture3DShaderProperty) { arguments.Add(string.Format("TEXTURE3D_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode))); } else if (prop is CubemapShaderProperty) { arguments.Add(string.Format("TEXTURECUBE_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode))); } else { arguments.Add(GetSlotValue(inSlotId, generationMode)); } } // pass surface inputs through arguments.Add(inputVariableName); foreach (var outSlot in subGraphData.outputs) { arguments.Add(GetVariableNameForSlot(outSlot.id)); } visitor.AddShaderChunk( string.Format("{0}({1});" , subGraphData.functionName , arguments.Aggregate((current, next) => string.Format("{0}, {1}", current, next)))); }
public static void GenerateSurfaceDescriptionFunction( List <INode> activeNodeList, AbstractMaterialNode masterNode, AbstractMaterialGraph graph, ShaderStringBuilder surfaceDescriptionFunction, FunctionRegistry functionRegistry, PropertyCollector shaderProperties, ShaderGraphRequirements requirements, GenerationMode mode, string functionName = "PopulateSurfaceData", string surfaceDescriptionName = "SurfaceDescription", Vector1ShaderProperty outputIdProperty = null, IEnumerable <MaterialSlot> slots = null, string graphInputStructName = "SurfaceDescriptionInputs") { if (graph == null) { return; } GraphContext graphContext = new GraphContext(graphInputStructName); graph.CollectShaderProperties(shaderProperties, mode); surfaceDescriptionFunction.AppendLine(String.Format("{0} {1}(SurfaceDescriptionInputs IN)", surfaceDescriptionName, functionName), false); using (surfaceDescriptionFunction.BlockScope()) { ShaderGenerator sg = new ShaderGenerator(); surfaceDescriptionFunction.AppendLine("{0} surface = ({0})0;", surfaceDescriptionName); foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { if (activeNode is IGeneratesFunction) { functionRegistry.builder.currentNode = activeNode; (activeNode as IGeneratesFunction).GenerateNodeFunction(functionRegistry, graphContext, mode); } if (activeNode is IGeneratesBodyCode) { (activeNode as IGeneratesBodyCode).GenerateNodeCode(sg, mode); } if (masterNode == null && activeNode.hasPreview) { var outputSlot = activeNode.GetOutputSlots <MaterialSlot>().FirstOrDefault(); if (outputSlot != null) { sg.AddShaderChunk(String.Format("if ({0} == {1}) {{ surface.PreviewOutput = {2}; return surface; }}", outputIdProperty.referenceName, activeNode.tempId.index, ShaderGenerator.AdaptNodeOutputForPreview(activeNode, outputSlot.id, activeNode.GetVariableNameForSlot(outputSlot.id))), false); } } // In case of the subgraph output node, the preview is generated // from the first input to the node. if (activeNode is SubGraphOutputNode) { var inputSlot = activeNode.GetInputSlots <MaterialSlot>().FirstOrDefault(); if (inputSlot != null) { var foundEdges = graph.GetEdges(inputSlot.slotReference).ToArray(); string slotValue = foundEdges.Any() ? activeNode.GetSlotValue(inputSlot.id, mode) : inputSlot.GetDefaultValue(mode); sg.AddShaderChunk(String.Format("if ({0} == {1}) {{ surface.PreviewOutput = {2}; return surface; }}", outputIdProperty.referenceName, activeNode.tempId.index, slotValue), false); } } activeNode.CollectShaderProperties(shaderProperties, mode); } surfaceDescriptionFunction.AppendLines(sg.GetShaderString(0)); functionRegistry.builder.currentNode = null; if (masterNode != null) { if (masterNode is IMasterNode) { var usedSlots = slots ?? masterNode.GetInputSlots <MaterialSlot>(); foreach (var input in usedSlots) { var foundEdges = graph.GetEdges(input.slotReference).ToArray(); if (foundEdges.Any()) { surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), masterNode.GetSlotValue(input.id, mode)); } else { surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), input.GetDefaultValue(mode)); } } } else if (masterNode.hasPreview) { foreach (var slot in masterNode.GetOutputSlots <MaterialSlot>()) { surfaceDescriptionFunction.AppendLine("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(slot.shaderOutputName), masterNode.GetSlotValue(slot.id, mode)); } } } surfaceDescriptionFunction.AppendLine("return surface;"); } }
// Node generations public virtual void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { var sb = new ShaderStringBuilder(); sb.AppendLine("{0}3 {1}_UV = {2} * {3};", precision, GetVariableNameForNode(), GetSlotValue(PositionInputId, generationMode), GetSlotValue(TileInputId, generationMode)); //Sampler input slot var samplerSlot = FindInputSlot <MaterialSlot>(SamplerInputId); var edgesSampler = owner.GetEdges(samplerSlot.slotReference); var id = GetSlotValue(TextureInputId, generationMode); switch (textureType) { // Whiteout blend method // https://medium.com/@bgolus/normal-mapping-for-a-triplanar-shader-10bf39dca05a case TextureType.Normal: sb.AppendLine("{0}3 {1}_Blend = max(pow(abs({2}), {3}), 0);", precision, GetVariableNameForNode(), GetSlotValue(NormalInputId, generationMode), GetSlotValue(BlendInputId, generationMode)); sb.AppendLine("{0}_Blend /= ({0}_Blend.x + {0}_Blend.y + {0}_Blend.z ).xxx;", GetVariableNameForNode()); sb.AppendLine("{0}3 {1}_X = UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D({2}, {3}, {1}_UV.zy));" , precision , GetVariableNameForNode() , id , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id); sb.AppendLine("{0}3 {1}_Y = UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D({2}, {3}, {1}_UV.xz));" , precision , GetVariableNameForNode() , id , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id); sb.AppendLine("{0}3 {1}_Z = UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D({2}, {3}, {1}_UV.xy));" , precision , GetVariableNameForNode() , id , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id); sb.AppendLine("{0}_X = {1}3({0}_X.xy + {2}.zy, abs({0}_X.z) * {2}.x);" , GetVariableNameForNode() , precision , GetSlotValue(NormalInputId, generationMode)); sb.AppendLine("{0}_Y = {1}3({0}_Y.xy + {2}.xz, abs({0}_Y.z) * {2}.y);" , GetVariableNameForNode() , precision , GetSlotValue(NormalInputId, generationMode)); sb.AppendLine("{0}_Z = {1}3({0}_Z.xy + {2}.xy, abs({0}_Z.z) * {2}.z);" , GetVariableNameForNode() , precision , GetSlotValue(NormalInputId, generationMode)); sb.AppendLine("{0}4 {1} = {0}4(normalize({2}_X.zyx * {2}_Blend.x + {2}_Y.xzy * {2}_Blend.y + {2}_Z.xyz * {2}_Blend.z), 1);" , precision , GetVariableNameForSlot(OutputSlotId) , GetVariableNameForNode()); sb.AppendLine("float3x3 {0}_Transform = float3x3(IN.WorldSpaceTangent, IN.WorldSpaceBiTangent, IN.WorldSpaceNormal);", GetVariableNameForNode()); sb.AppendLine("{0}.rgb = TransformWorldToTangent({0}.rgb, {1}_Transform);" , GetVariableNameForSlot(OutputSlotId) , GetVariableNameForNode()); break; default: sb.AppendLine("{0}3 {1}_Blend = pow(abs({2}), {3});", precision, GetVariableNameForNode(), GetSlotValue(NormalInputId, generationMode), GetSlotValue(BlendInputId, generationMode)); sb.AppendLine("{0}_Blend /= dot({0}_Blend, 1.0);", GetVariableNameForNode()); sb.AppendLine("{0}4 {1}_X = SAMPLE_TEXTURE2D({2}, {3}, {1}_UV.zy);" , precision , GetVariableNameForNode() , id , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id); sb.AppendLine("{0}4 {1}_Y = SAMPLE_TEXTURE2D({2}, {3}, {1}_UV.xz);" , precision , GetVariableNameForNode() , id , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id); sb.AppendLine("{0}4 {1}_Z = SAMPLE_TEXTURE2D({2}, {3}, {1}_UV.xy);" , precision , GetVariableNameForNode() , id , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id); sb.AppendLine("{0}4 {1} = {2}_X * {2}_Blend.x + {2}_Y * {2}_Blend.y + {2}_Z * {2}_Blend.z;" , precision , GetVariableNameForSlot(OutputSlotId) , GetVariableNameForNode()); break; } visitor.AddShaderChunk(sb.ToString(), false); }
private static string GetShaderPassFromTemplate(UnlitMasterNode masterNode, Pass pass, GenerationMode mode) { var builder = new ShaderStringBuilder(); builder.IncreaseIndent(); builder.IncreaseIndent(); var surfaceDescriptionFunction = new ShaderGenerator(); var surfaceDescriptionStruct = new ShaderGenerator(); var surfaceInputs = new ShaderGenerator(); var functionRegistry = new FunctionRegistry(builder); 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); 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); ShaderGenerator defines = new ShaderGenerator(); defines.AddShaderChunk(string.Format("#define SHADERPASS {0}", pass.ShaderPassName), true); 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); defines.AddShaderChunk(string.Format("#define ATTRIBUTES_NEED_TEXCOORD{0}", (int)channel), true); defines.AddShaderChunk(string.Format("#define VARYINGS_NEED_TEXCOORD{0}", (int)channel), true); } surfaceInputs.Deindent(); surfaceInputs.AddShaderChunk("};", false); var slots = new List <MaterialSlot>(); foreach (var id in pass.PixelShaderSlots) { var slot = masterNode.FindSlot <MaterialSlot>(id); if (slot != null) { slots.Add(slot); } } 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(surfaceDescriptionStruct.GetShaderString(2), false); graph.AddShaderChunk(surfaceDescriptionFunction.GetShaderString(2), false); var tagsVisitor = new ShaderGenerator(); var blendingVisitor = new ShaderGenerator(); var cullingVisitor = new ShaderGenerator(); var zTestVisitor = new ShaderGenerator(); var zWriteVisitor = new ShaderGenerator(); var materialOptions = new SurfaceMaterialOptions(); materialOptions.GetTags(tagsVisitor); materialOptions.GetBlend(blendingVisitor); materialOptions.GetCull(cullingVisitor); materialOptions.GetDepthTest(zTestVisitor); materialOptions.GetDepthWrite(zWriteVisitor); var localPixelShader = new ShaderGenerator(); var localSurfaceInputs = new ShaderGenerator(); var surfaceOutputRemap = new ShaderGenerator(); foreach (var channel in requirements.requiresMeshUVs.Distinct()) { localSurfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {1};", channel.GetUVName(), string.Format("half4(input.texCoord{0}, 0, 0)", (int)channel)), false); } var templateLocation = ShaderGenerator.GetTemplatePath("HDUnlitPassForward.template"); foreach (var slot in usedSlots) { surfaceOutputRemap.AddShaderChunk(slot.shaderOutputName + " = surf." + 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("${LocalPixelShader}", localPixelShader.GetShaderString(3)); resultPass = resultPass.Replace("${SurfaceInputs}", localSurfaceInputs.GetShaderString(3)); resultPass = resultPass.Replace("${SurfaceOutputRemap}", surfaceOutputRemap.GetShaderString(3)); resultPass = resultPass.Replace("${LightMode}", pass.Name); resultPass = resultPass.Replace("${ShaderPassInclude}", pass.ShaderPassInclude); resultPass = resultPass.Replace("${Tags}", tagsVisitor.GetShaderString(2)); 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)); resultPass = resultPass.Replace("${LOD}", "" + materialOptions.lod); return(resultPass); }
public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode) { visitor.AddShaderChunk(string.Format("{0} {1} = max(0, IN.{2});", precision, GetVariableNameForSlot(OutputSlotId), ShaderGeneratorNames.FaceSign), true); }
public IEnumerable <string> GetSubshader(PBRMasterNode masterNode, GenerationMode mode) { var subShader = new ShaderGenerator(); subShader.AddShaderChunk("SubShader", true); subShader.AddShaderChunk("{", true); subShader.Indent(); subShader.AddShaderChunk("Tags{ \"RenderPipeline\" = \"LightweightPipeline\"}", true); var materialOptions = new SurfaceMaterialOptions(); switch (masterNode.alphaMode) { case PBRMasterNode.AlphaMode.Opaque: materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.One; materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.Zero; materialOptions.cullMode = SurfaceMaterialOptions.CullMode.Back; materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual; materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.On; materialOptions.renderQueue = SurfaceMaterialOptions.RenderQueue.Geometry; materialOptions.renderType = SurfaceMaterialOptions.RenderType.Opaque; break; case PBRMasterNode.AlphaMode.AlphaBlend: materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.SrcAlpha; materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha; materialOptions.cullMode = SurfaceMaterialOptions.CullMode.Back; materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual; materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off; materialOptions.renderQueue = SurfaceMaterialOptions.RenderQueue.Transparent; materialOptions.renderType = SurfaceMaterialOptions.RenderType.Transparent; break; case PBRMasterNode.AlphaMode.AdditiveBlend: materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.One; materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.One; materialOptions.cullMode = SurfaceMaterialOptions.CullMode.Back; materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual; materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off; materialOptions.renderQueue = SurfaceMaterialOptions.RenderQueue.Transparent; materialOptions.renderType = SurfaceMaterialOptions.RenderType.Transparent; break; } var tagsVisitor = new ShaderGenerator(); materialOptions.GetTags(tagsVisitor); subShader.AddShaderChunk(tagsVisitor.GetShaderString(0), true); subShader.AddShaderChunk( GetShaderPassFromTemplate( "lightweightPBRForwardPass.template", masterNode, masterNode.model == PBRMasterNode.Model.Metallic ? m_ForwardPassMetallic : m_ForwardPassSpecular, mode, materialOptions), true); var extraPassesTemplateLocation = ShaderGenerator.GetTemplatePath("lightweightPBRExtraPasses.template"); if (File.Exists(extraPassesTemplateLocation)) { subShader.AddShaderChunk(File.ReadAllText(extraPassesTemplateLocation), true); } subShader.Deindent(); subShader.AddShaderChunk("}", true); return(new[] { subShader.GetShaderString(0) }); }
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); 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); } switch (masterNode.alphaMode) { case PBRMasterNode.AlphaMode.AlphaBlend: case PBRMasterNode.AlphaMode.AdditiveBlend: defines.AddShaderChunk("#define _AlphaOut 1", true); break; } if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId)) { defines.AddShaderChunk("#define _AlphaClip 1", true); } var templateLocation = ShaderGenerator.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); }
public static bool GenerateShaderPass(AbstractMaterialNode masterNode, ShaderPass pass, GenerationMode mode, ActiveFields activeFields, ShaderGenerator result, List <string> sourceAssetDependencyPaths, List <Dependency[]> dependencies, string resourceClassName, string assemblyName) { // -------------------------------------------------- // Debug // Get scripting symbols BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup); bool isDebug = defines.Contains(kDebugSymbol); // -------------------------------------------------- // Setup // Initiailize Collectors var propertyCollector = new PropertyCollector(); var keywordCollector = new KeywordCollector(); masterNode.owner.CollectShaderKeywords(keywordCollector, mode); // Get upstream nodes from ShaderPass port mask List <AbstractMaterialNode> vertexNodes; List <AbstractMaterialNode> pixelNodes; GetUpstreamNodesForShaderPass(masterNode, pass, out vertexNodes, out pixelNodes); // Track permutation indices for all nodes List <int>[] vertexNodePermutations = new List <int> [vertexNodes.Count]; List <int>[] pixelNodePermutations = new List <int> [pixelNodes.Count]; // Get active fields from upstream Node requirements ShaderGraphRequirementsPerKeyword graphRequirements; GetActiveFieldsAndPermutationsForNodes(masterNode, pass, keywordCollector, vertexNodes, pixelNodes, vertexNodePermutations, pixelNodePermutations, activeFields, out graphRequirements); // GET CUSTOM ACTIVE FIELDS HERE! // Get active fields from ShaderPass AddRequiredFields(pass.requiredAttributes, activeFields.baseInstance); AddRequiredFields(pass.requiredVaryings, activeFields.baseInstance); // Get Port references from ShaderPass var pixelSlots = FindMaterialSlotsOnNode(pass.pixelPorts, masterNode); var vertexSlots = FindMaterialSlotsOnNode(pass.vertexPorts, masterNode); // Function Registry var functionBuilder = new ShaderStringBuilder(); var functionRegistry = new FunctionRegistry(functionBuilder); // Hash table of named $splice(name) commands // Key: splice token // Value: string to splice Dictionary <string, string> spliceCommands = new Dictionary <string, string>(); // -------------------------------------------------- // Dependencies // Propagate active field requirements using dependencies // Must be executed before types are built foreach (var instance in activeFields.all.instances) { ShaderSpliceUtil.ApplyDependencies(instance, dependencies); } // -------------------------------------------------- // Pass Setup // Name if (!string.IsNullOrEmpty(pass.displayName)) { spliceCommands.Add("PassName", $"Name \"{pass.displayName}\""); } else { spliceCommands.Add("PassName", "// Name: <None>"); } // Tags if (!string.IsNullOrEmpty(pass.lightMode)) { spliceCommands.Add("LightMode", $"\"LightMode\" = \"{pass.lightMode}\""); } else { spliceCommands.Add("LightMode", "// LightMode: <None>"); } // Render state BuildRenderStatesFromPass(pass, ref spliceCommands); // -------------------------------------------------- // Pass Code // Pragmas using (var passPragmaBuilder = new ShaderStringBuilder()) { if (pass.pragmas != null) { foreach (string pragma in pass.pragmas) { passPragmaBuilder.AppendLine($"#pragma {pragma}"); } } if (passPragmaBuilder.length == 0) { passPragmaBuilder.AppendLine("// PassPragmas: <None>"); } spliceCommands.Add("PassPragmas", passPragmaBuilder.ToCodeBlack()); } // Includes using (var passIncludeBuilder = new ShaderStringBuilder()) { if (pass.includes != null) { foreach (string include in pass.includes) { passIncludeBuilder.AppendLine($"#include \"{include}\""); } } if (passIncludeBuilder.length == 0) { passIncludeBuilder.AppendLine("// PassIncludes: <None>"); } spliceCommands.Add("PassIncludes", passIncludeBuilder.ToCodeBlack()); } // Keywords using (var passKeywordBuilder = new ShaderStringBuilder()) { if (pass.keywords != null) { foreach (KeywordDescriptor keyword in pass.keywords) { passKeywordBuilder.AppendLine(keyword.ToDeclarationString()); } } if (passKeywordBuilder.length == 0) { passKeywordBuilder.AppendLine("// PassKeywords: <None>"); } spliceCommands.Add("PassKeywords", passKeywordBuilder.ToCodeBlack()); } // -------------------------------------------------- // Graph Vertex var vertexBuilder = new ShaderStringBuilder(); // If vertex modification enabled if (activeFields.baseInstance.Contains("features.graphVertex")) { // Setup string vertexGraphInputName = "VertexDescriptionInputs"; string vertexGraphOutputName = "VertexDescription"; string vertexGraphFunctionName = "VertexDescriptionFunction"; var vertexGraphInputGenerator = new ShaderGenerator(); var vertexGraphFunctionBuilder = new ShaderStringBuilder(); var vertexGraphOutputBuilder = new ShaderStringBuilder(); // Build vertex graph inputs ShaderSpliceUtil.BuildType(GetTypeForStruct("VertexDescriptionInputs", resourceClassName, assemblyName), activeFields, vertexGraphInputGenerator, isDebug); // Build vertex graph outputs // Add struct fields to active fields SubShaderGenerator.GenerateVertexDescriptionStruct(vertexGraphOutputBuilder, vertexSlots, vertexGraphOutputName, activeFields.baseInstance); // Build vertex graph functions from ShaderPass vertex port mask SubShaderGenerator.GenerateVertexDescriptionFunction( masterNode.owner as GraphData, vertexGraphFunctionBuilder, functionRegistry, propertyCollector, keywordCollector, mode, masterNode, vertexNodes, vertexNodePermutations, vertexSlots, vertexGraphInputName, vertexGraphFunctionName, vertexGraphOutputName); // Generate final shader strings vertexBuilder.AppendLines(vertexGraphInputGenerator.GetShaderString(0, false)); vertexBuilder.AppendNewLine(); vertexBuilder.AppendLines(vertexGraphOutputBuilder.ToString()); vertexBuilder.AppendNewLine(); vertexBuilder.AppendLines(vertexGraphFunctionBuilder.ToString()); } // Add to splice commands if (vertexBuilder.length == 0) { vertexBuilder.AppendLine("// GraphVertex: <None>"); } spliceCommands.Add("GraphVertex", vertexBuilder.ToCodeBlack()); // -------------------------------------------------- // Graph Pixel // Setup string pixelGraphInputName = "SurfaceDescriptionInputs"; string pixelGraphOutputName = "SurfaceDescription"; string pixelGraphFunctionName = "SurfaceDescriptionFunction"; var pixelGraphInputGenerator = new ShaderGenerator(); var pixelGraphOutputBuilder = new ShaderStringBuilder(); var pixelGraphFunctionBuilder = new ShaderStringBuilder(); // Build pixel graph inputs ShaderSpliceUtil.BuildType(GetTypeForStruct("SurfaceDescriptionInputs", resourceClassName, assemblyName), activeFields, pixelGraphInputGenerator, isDebug); // Build pixel graph outputs // Add struct fields to active fields SubShaderGenerator.GenerateSurfaceDescriptionStruct(pixelGraphOutputBuilder, pixelSlots, pixelGraphOutputName, activeFields.baseInstance); // Build pixel graph functions from ShaderPass pixel port mask SubShaderGenerator.GenerateSurfaceDescriptionFunction( pixelNodes, pixelNodePermutations, masterNode, masterNode.owner as GraphData, pixelGraphFunctionBuilder, functionRegistry, propertyCollector, keywordCollector, mode, pixelGraphFunctionName, pixelGraphOutputName, null, pixelSlots, pixelGraphInputName); using (var pixelBuilder = new ShaderStringBuilder()) { // Generate final shader strings pixelBuilder.AppendLines(pixelGraphInputGenerator.GetShaderString(0, false)); pixelBuilder.AppendNewLine(); pixelBuilder.AppendLines(pixelGraphOutputBuilder.ToString()); pixelBuilder.AppendNewLine(); pixelBuilder.AppendLines(pixelGraphFunctionBuilder.ToString()); // Add to splice commands if (pixelBuilder.length == 0) { pixelBuilder.AppendLine("// GraphPixel: <None>"); } spliceCommands.Add("GraphPixel", pixelBuilder.ToCodeBlack()); } // -------------------------------------------------- // Graph Functions if (functionBuilder.length == 0) { functionBuilder.AppendLine("// GraphFunctions: <None>"); } spliceCommands.Add("GraphFunctions", functionBuilder.ToCodeBlack()); // -------------------------------------------------- // Graph Keywords using (var keywordBuilder = new ShaderStringBuilder()) { keywordCollector.GetKeywordsDeclaration(keywordBuilder, mode); if (keywordBuilder.length == 0) { keywordBuilder.AppendLine("// GraphKeywords: <None>"); } spliceCommands.Add("GraphKeywords", keywordBuilder.ToCodeBlack()); } // -------------------------------------------------- // Graph Properties using (var propertyBuilder = new ShaderStringBuilder()) { propertyCollector.GetPropertiesDeclaration(propertyBuilder, mode, masterNode.owner.concretePrecision); if (propertyBuilder.length == 0) { propertyBuilder.AppendLine("// GraphProperties: <None>"); } spliceCommands.Add("GraphProperties", propertyBuilder.ToCodeBlack()); } // -------------------------------------------------- // Graph Defines using (var graphDefines = new ShaderStringBuilder()) { graphDefines.AppendLine("#define {0}", pass.referenceName); if (graphRequirements.permutationCount > 0) { List <int> activePermutationIndices; // Depth Texture activePermutationIndices = graphRequirements.allPermutations.instances .Where(p => p.requirements.requiresDepthTexture) .Select(p => p.permutationIndex) .ToList(); if (activePermutationIndices.Count > 0) { graphDefines.AppendLine(KeywordUtil.GetKeywordPermutationSetConditional(activePermutationIndices)); graphDefines.AppendLine("#define REQUIRE_DEPTH_TEXTURE"); graphDefines.AppendLine("#endif"); } // Opaque Texture activePermutationIndices = graphRequirements.allPermutations.instances .Where(p => p.requirements.requiresCameraOpaqueTexture) .Select(p => p.permutationIndex) .ToList(); if (activePermutationIndices.Count > 0) { graphDefines.AppendLine(KeywordUtil.GetKeywordPermutationSetConditional(activePermutationIndices)); graphDefines.AppendLine("#define REQUIRE_OPAQUE_TEXTURE"); graphDefines.AppendLine("#endif"); } } else { // Depth Texture if (graphRequirements.baseInstance.requirements.requiresDepthTexture) { graphDefines.AppendLine("#define REQUIRE_DEPTH_TEXTURE"); } // Opaque Texture if (graphRequirements.baseInstance.requirements.requiresCameraOpaqueTexture) { graphDefines.AppendLine("#define REQUIRE_OPAQUE_TEXTURE"); } } // Add to splice commands spliceCommands.Add("GraphDefines", graphDefines.ToCodeBlack()); } // -------------------------------------------------- // Main // Main include is expected to contain vert/frag definitions for the pass // This must be defined after all graph code using (var mainBuilder = new ShaderStringBuilder()) { mainBuilder.AppendLine($"#include \"{pass.varyingsInclude}\""); mainBuilder.AppendLine($"#include \"{pass.passInclude}\""); // Add to splice commands spliceCommands.Add("MainInclude", mainBuilder.ToCodeBlack()); } // -------------------------------------------------- // Debug // Debug output all active fields using (var debugBuilder = new ShaderStringBuilder()) { if (isDebug) { // Active fields debugBuilder.AppendLine("// ACTIVE FIELDS:"); foreach (string field in activeFields.baseInstance.fields) { debugBuilder.AppendLine("// " + field); } } if (debugBuilder.length == 0) { debugBuilder.AppendLine("// <None>"); } // Add to splice commands spliceCommands.Add("Debug", debugBuilder.ToCodeBlack()); } // -------------------------------------------------- // Finalize // Get Template string templateLocation = GetTemplatePath("PassMesh.template"); if (!File.Exists(templateLocation)) { return(false); } // Get Template preprocessor string templatePath = "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Templates"; var templatePreprocessor = new ShaderSpliceUtil.TemplatePreprocessor(activeFields, spliceCommands, isDebug, templatePath, sourceAssetDependencyPaths, assemblyName, resourceClassName); // Process Template templatePreprocessor.ProcessTemplateFile(templateLocation); result.AddShaderChunk(templatePreprocessor.GetShaderCode().ToString(), false); return(true); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { visitor.AddShaderChunk(precision + " " + GetVariableNameForSlot(0) + " = " + m_DiffusionProfile.selectedEntry + ";", true); }
public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode) { var graph = owner as AbstractMaterialGraph; var property = graph.properties.FirstOrDefault(x => x.guid == propertyGuid); if (property == null) { return; } if (property is FloatShaderProperty) { var result = string.Format("{0} {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Vector2ShaderProperty) { var result = string.Format("{0}2 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Vector3ShaderProperty) { var result = string.Format("{0}3 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Vector4ShaderProperty) { var result = string.Format("{0}4 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is ColorShaderProperty) { var result = string.Format("{0}4 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is IntegerShaderProperty) { var result = string.Format("{0} {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is SliderShaderProperty) { var result = string.Format("{0} {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is BooleanShaderProperty) { var result = string.Format("{0} {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } }
public static GenerationResults GetShader(this AbstractMaterialGraph graph, AbstractMaterialNode node, GenerationMode mode, string name) { var results = new GenerationResults(); bool isUber = node == null; var vertexInputs = new ShaderGenerator(); var vertexShader = new ShaderGenerator(); var surfaceDescriptionFunction = new ShaderGenerator(); var surfaceDescriptionStruct = new ShaderGenerator(); var functionBuilder = new ShaderStringBuilder(); var functionRegistry = new FunctionRegistry(functionBuilder); var surfaceInputs = new ShaderGenerator(); surfaceInputs.AddShaderChunk("struct SurfaceInputs{", false); surfaceInputs.Indent(); var activeNodeList = ListPool <INode> .Get(); if (isUber) { var unmarkedNodes = graph.GetNodes <INode>().Where(x => !(x is IMasterNode)).ToDictionary(x => x.guid); while (unmarkedNodes.Any()) { var unmarkedNode = unmarkedNodes.FirstOrDefault(); Visit(activeNodeList, unmarkedNodes, unmarkedNode.Value); } } else { NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node); } var requirements = ShaderGraphRequirements.FromNodes(activeNodeList); GenerateApplicationVertexInputs(requirements, 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); } results.previewMode = PreviewMode.Preview3D; if (!isUber) { foreach (var pNode in activeNodeList.OfType <AbstractMaterialNode>()) { if (pNode.previewMode == PreviewMode.Preview3D) { results.previewMode = PreviewMode.Preview3D; break; } } } foreach (var channel in requirements.requiresMeshUVs.Distinct()) { surfaceInputs.AddShaderChunk(String.Format("half4 {0};", channel.GetUVName()), false); } surfaceInputs.Deindent(); surfaceInputs.AddShaderChunk("};", false); vertexShader.AddShaderChunk("GraphVertexInput PopulateVertexData(GraphVertexInput v){", false); vertexShader.Indent(); vertexShader.AddShaderChunk("return v;", false); vertexShader.Deindent(); vertexShader.AddShaderChunk("}", false); var slots = new List <MaterialSlot>(); foreach (var activeNode in isUber ? activeNodeList.Where(n => ((AbstractMaterialNode)n).hasPreview) : ((INode)node).ToEnumerable()) { if (activeNode is IMasterNode || activeNode is SubGraphOutputNode) { slots.AddRange(activeNode.GetInputSlots <MaterialSlot>()); } else { slots.AddRange(activeNode.GetOutputSlots <MaterialSlot>()); } } GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, !isUber); var shaderProperties = new PropertyCollector(); results.outputIdProperty = new Vector1ShaderProperty { displayName = "OutputId", generatePropertyBlock = false, value = -1 }; if (isUber) { shaderProperties.AddShaderProperty(results.outputIdProperty); } GenerateSurfaceDescription( activeNodeList, node, graph, surfaceDescriptionFunction, functionRegistry, shaderProperties, requirements, mode, outputIdProperty: results.outputIdProperty); var finalBuilder = new ShaderStringBuilder(); finalBuilder.AppendLine(@"Shader ""{0}""", name); using (finalBuilder.BlockScope()) { finalBuilder.AppendLine("Properties"); using (finalBuilder.BlockScope()) { finalBuilder.AppendLines(shaderProperties.GetPropertiesBlock(0)); } finalBuilder.AppendLine(@"HLSLINCLUDE"); finalBuilder.AppendLine("#define USE_LEGACY_UNITY_MATRIX_VARIABLES"); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/Common.hlsl"""); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/Packing.hlsl"""); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/Color.hlsl"""); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/UnityInstancing.hlsl"""); finalBuilder.AppendLine(@"#include ""CoreRP/ShaderLibrary/EntityLighting.hlsl"""); finalBuilder.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariables.hlsl"""); finalBuilder.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariablesFunctions.hlsl"""); finalBuilder.AppendLine(@"#include ""ShaderGraphLibrary/Functions.hlsl"""); finalBuilder.AppendLines(shaderProperties.GetPropertiesDeclaration(0)); finalBuilder.AppendLines(surfaceInputs.GetShaderString(0)); finalBuilder.Concat(functionBuilder); finalBuilder.AppendLines(vertexInputs.GetShaderString(0)); finalBuilder.AppendLines(surfaceDescriptionStruct.GetShaderString(0)); finalBuilder.AppendLines(vertexShader.GetShaderString(0)); finalBuilder.AppendLines(surfaceDescriptionFunction.GetShaderString(0)); finalBuilder.AppendLine(@"ENDHLSL"); finalBuilder.AppendLines(ShaderGenerator.GetPreviewSubShader(node, requirements)); ListPool <INode> .Release(activeNodeList); } results.configuredTextures = shaderProperties.GetConfiguredTexutres(); ShaderSourceMap sourceMap; results.shader = finalBuilder.ToString(out sourceMap); results.sourceMap = sourceMap; return(results); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { var graph = owner as GraphData; var property = graph.properties.FirstOrDefault(x => x.guid == propertyGuid); if (property == null) { return; } if (property is Vector1ShaderProperty) { var result = string.Format("{0} {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Vector2ShaderProperty) { var result = string.Format("{0}2 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Vector3ShaderProperty) { var result = string.Format("{0}3 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Vector4ShaderProperty) { var result = string.Format("{0}4 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is ColorShaderProperty) { var result = string.Format("{0}4 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is BooleanShaderProperty) { var result = string.Format("{0} {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Matrix2ShaderProperty) { var result = string.Format("{0}2x2 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Matrix3ShaderProperty) { var result = string.Format("{0}3x3 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is Matrix4ShaderProperty) { var result = string.Format("{0}4x4 {1} = {2};" , precision , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } else if (property is SamplerStateShaderProperty) { SamplerStateShaderProperty samplerStateProperty = property as SamplerStateShaderProperty; var result = string.Format("SamplerState {0} = {1};" , GetVariableNameForSlot(OutputSlotId) , samplerStateProperty.referenceName); visitor.AddShaderChunk(result, true); } else if (property is GradientShaderProperty) { if (generationMode == GenerationMode.Preview) { var result = string.Format("Gradient {0} = {1};" , GetVariableNameForSlot(OutputSlotId) , GradientUtils.GetGradientForPreview(property.referenceName)); visitor.AddShaderChunk(result, true); } else { var result = string.Format("Gradient {0} = {1};" , GetVariableNameForSlot(OutputSlotId) , property.referenceName); visitor.AddShaderChunk(result, true); } } }
public static void BuildPackedType(System.Type unpacked, HashSet <string> activeFields, ShaderGenerator result) { // for each interpolator, the number of components used (up to 4 for a float4 interpolator) List <int> packedCounts = new List <int>(); ShaderGenerator packer = new ShaderGenerator(); ShaderGenerator unpacker = new ShaderGenerator(); ShaderGenerator structEnd = new ShaderGenerator(); string unpackedStruct = unpacked.Name.ToString(); string packedStruct = "Packed" + unpacked.Name; string packerFunction = "Pack" + unpacked.Name; string unpackerFunction = "Unpack" + unpacked.Name; // declare struct header: // struct packedStruct { result.AddShaderChunk("struct " + packedStruct + " {"); result.Indent(); // declare function headers: // packedStruct packerFunction(unpackedStruct input) // { // packedStruct output; packer.AddShaderChunk(packedStruct + " " + packerFunction + "(" + unpackedStruct + " input)"); packer.AddShaderChunk("{"); packer.Indent(); packer.AddShaderChunk(packedStruct + " output;"); // unpackedStruct unpackerFunction(packedStruct input) // { // unpackedStruct output; unpacker.AddShaderChunk(unpackedStruct + " " + unpackerFunction + "(" + packedStruct + " input)"); unpacker.AddShaderChunk("{"); unpacker.Indent(); unpacker.AddShaderChunk(unpackedStruct + " output;"); // TODO: this could do a better job packing // especially if we allowed breaking up fields across multiple interpolators (to pack them into remaining space...) // though we would want to only do this if it improves final interpolator count, and is worth it on the target machine foreach (FieldInfo field in unpacked.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { if (field.MemberType == MemberTypes.Field) { bool isOptional; if (ShouldSpliceField(unpacked, field, activeFields, out isOptional)) { string semanticString = GetFieldSemantic(field); int floatVectorCount; string fieldType = GetFieldType(field, out floatVectorCount); string conditional = GetFieldConditional(field); if ((semanticString != null) || (conditional != null) || (floatVectorCount == 0)) { // not a packed value if (conditional != null) { structEnd.AddShaderChunk("#if " + conditional); packer.AddShaderChunk("#if " + conditional); unpacker.AddShaderChunk("#if " + conditional); } structEnd.AddShaderChunk(fieldType + " " + field.Name + semanticString + "; // unpacked"); packer.AddShaderChunk("output." + field.Name + " = input." + field.Name + ";"); unpacker.AddShaderChunk("output." + field.Name + " = input." + field.Name + ";"); if (conditional != null) { structEnd.AddShaderChunk("#endif // " + conditional); packer.AddShaderChunk("#endif // " + conditional); unpacker.AddShaderChunk("#endif // " + conditional); } } else { // pack float field // super simple packing: use the first interpolator that has room for the whole value int interpIndex = packedCounts.FindIndex(x => (x + floatVectorCount <= 4)); int firstChannel; if (interpIndex < 0) { // allocate a new interpolator interpIndex = packedCounts.Count; firstChannel = 0; packedCounts.Add(floatVectorCount); } else { // pack into existing interpolator firstChannel = packedCounts[interpIndex]; packedCounts[interpIndex] += floatVectorCount; } // add code to packer and unpacker -- packed data declaration is handled later string packedChannels = GetChannelSwizzle(firstChannel, floatVectorCount); packer.AddShaderChunk(string.Format("output.interp{0:00}.{1} = input.{2};", interpIndex, packedChannels, field.Name)); unpacker.AddShaderChunk(string.Format("output.{0} = input.interp{1:00}.{2};", field.Name, interpIndex, packedChannels)); } } } } // add packed data declarations to struct, using the packedCounts for (int index = 0; index < packedCounts.Count; index++) { int count = packedCounts[index]; result.AddShaderChunk(string.Format("{0} interp{1:00} : TEXCOORD{1}; // auto-packed", vectorTypeNames[count], index)); } // add unpacked data declarations to struct (must be at end) result.AddGenerator(structEnd); // close declarations result.Deindent(); result.AddShaderChunk("};"); packer.AddShaderChunk("return output;"); packer.Deindent(); packer.AddShaderChunk("}"); unpacker.AddShaderChunk("return output;"); unpacker.Deindent(); unpacker.AddShaderChunk("}"); // combine all of the code into the result result.AddGenerator(packer); result.AddGenerator(unpacker); }
static void ProcessSubGraph(Dictionary <string, SubGraphData> subGraphMap, FunctionRegistry registry, SubGraphData subGraphData, GraphData graph) { registry.names.Clear(); subGraphData.functionNames.Clear(); subGraphData.nodeProperties.Clear(); subGraphData.isValid = true; graph.OnEnable(); graph.messageManager.ClearAll(); graph.ValidateGraph(); var assetPath = AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid); subGraphData.hlslName = NodeUtils.GetHLSLSafeName(Path.GetFileNameWithoutExtension(assetPath)); subGraphData.inputStructName = $"Bindings_{subGraphData.hlslName}_{subGraphData.assetGuid}"; subGraphData.functionName = $"SG_{subGraphData.hlslName}_{subGraphData.assetGuid}"; subGraphData.path = graph.path; var outputNode = (SubGraphOutputNode)graph.outputNode; subGraphData.outputs.Clear(); outputNode.GetInputSlots(subGraphData.outputs); List <AbstractMaterialNode> nodes = new List <AbstractMaterialNode>(); NodeUtils.DepthFirstCollectNodesFromNode(nodes, outputNode); subGraphData.effectiveShaderStage = ShaderStageCapability.All; foreach (var slot in subGraphData.outputs) { var stage = NodeUtils.GetEffectiveShaderStageCapability(slot, true); if (stage != ShaderStageCapability.All) { subGraphData.effectiveShaderStage = stage; break; } } subGraphData.requirements = ShaderGraphRequirements.FromNodes(nodes, subGraphData.effectiveShaderStage, false); subGraphData.inputs = graph.properties.ToList(); foreach (var node in nodes) { if (node.hasError) { subGraphData.isValid = false; registry.ProvideFunction(subGraphData.functionName, sb => { }); return; } } foreach (var node in nodes) { if (node is SubGraphNode subGraphNode) { var nestedData = subGraphMap[subGraphNode.subGraphGuid]; foreach (var functionName in nestedData.functionNames) { registry.names.Add(functionName); } } else if (node is IGeneratesFunction generatesFunction) { generatesFunction.GenerateNodeFunction(registry, new GraphContext(subGraphData.inputStructName), GenerationMode.ForReals); } } registry.ProvideFunction(subGraphData.functionName, sb => { var graphContext = new GraphContext(subGraphData.inputStructName); GraphUtil.GenerateSurfaceInputStruct(sb, subGraphData.requirements, subGraphData.inputStructName); sb.AppendNewLine(); // Generate arguments... first INPUTS var arguments = new List <string>(); foreach (var prop in subGraphData.inputs) { arguments.Add(string.Format("{0}", prop.GetPropertyAsArgumentString())); } // now pass surface inputs arguments.Add(string.Format("{0} IN", subGraphData.inputStructName)); // Now generate outputs foreach (var output in subGraphData.outputs) { arguments.Add($"out {output.concreteValueType.ToString(outputNode.precision)} {output.shaderOutputName}_{output.id}"); } // Create the function prototype from the arguments sb.AppendLine("void {0}({1})" , subGraphData.functionName , arguments.Aggregate((current, next) => $"{current}, {next}")); // now generate the function using (sb.BlockScope()) { // Just grab the body from the active nodes var bodyGenerator = new ShaderGenerator(); foreach (var node in nodes) { if (node is IGeneratesBodyCode) { (node as IGeneratesBodyCode).GenerateNodeCode(bodyGenerator, graphContext, GenerationMode.ForReals); } } foreach (var slot in subGraphData.outputs) { bodyGenerator.AddShaderChunk($"{slot.shaderOutputName}_{slot.id} = {outputNode.GetSlotValue(slot.id, GenerationMode.ForReals)};"); } sb.Append(bodyGenerator.GetShaderString(1)); } }); subGraphData.functionNames.AddRange(registry.names.Distinct()); var collector = new PropertyCollector(); subGraphData.nodeProperties = collector.properties; foreach (var node in nodes) { node.CollectShaderProperties(collector, GenerationMode.ForReals); } subGraphData.OnBeforeSerialize(); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { visitor.AddShaderChunk(string.Format("{0}4 {1} = {2};", precision, GetVariableNameForSlot(kOutputSlotId), m_ScreenSpaceType.ToValueAsVariable()), true); }
public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode) { visitor.AddShaderChunk(precision + " " + GetVariableNameForNode() + " = " + m_constantList[constant] + ";", true); }
// Node generations public virtual void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { visitor.AddShaderChunk(string.Format("{0} {1} = {2}_TexelSize.z;", precision, GetVariableNameForSlot(OutputSlotWId), GetSlotValue(TextureInputId, generationMode)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}_TexelSize.w;", precision, GetVariableNameForSlot(OutputSlotHId), GetSlotValue(TextureInputId, generationMode)), true); }
// Node generations public virtual void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { var uvName = GetSlotValue(UVInput, generationMode); //Sampler input slot var samplerSlot = FindInputSlot <MaterialSlot>(SamplerInput); var edgesSampler = owner.GetEdges(samplerSlot.slotReference); var lodSlot = GetSlotValue(LODInput, generationMode); var id = GetSlotValue(TextureInputId, generationMode); var result = string.Format("{0}4 {1} = SAMPLE_TEXTURE2D_LOD({2}, {3}, {4}, {5});" , precision , GetVariableNameForSlot(OutputSlotRGBAId) , id , edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : "sampler" + id , uvName , lodSlot); visitor.AddShaderChunk(result, true); if (textureType == TextureType.Normal) { if (normalMapSpace == NormalMapSpace.Tangent) { if (derivativeMap.isOn) { visitor.AddShaderChunk(string.Format("{0}2 deriv = UnpackDerivativeNormalRGorAG({1});", precision, GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0}.rgb = SurfaceGradientFromTBN(deriv, IN.WorldSpaceTangent, IN.WorldSpaceBiTangent);", GetVariableNameForSlot(OutputSlotRGBAId)), true); } else { visitor.AddShaderChunk(string.Format("{0}.rgb = UnpackNormalmapRGorAG({0});", GetVariableNameForSlot(OutputSlotRGBAId)), true); } } else { if (derivativeMap.isOn) { visitor.AddShaderChunk(string.Format("{0}2 deriv = UnpackDerivativeNormalRGB({1});", precision, GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0}.rgb = SurfaceGradientFromTBN(deriv, IN.WorldSpaceTangent, IN.WorldSpaceBiTangent);", GetVariableNameForSlot(OutputSlotRGBAId)), true); } else { visitor.AddShaderChunk(string.Format("{0}.rgb = UnpackNormalRGB({0});", GetVariableNameForSlot(OutputSlotRGBAId)), true); } } } visitor.AddShaderChunk(string.Format("{0} {1} = {2}.r;", precision, GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.g;", precision, GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.b;", precision, GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.a;", precision, GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId)), true); }
public static void BuildType(System.Type t, ActiveFields activeFields, ShaderGenerator result, bool isDebug) { result.AddShaderChunk("struct " + t.Name); result.AddShaderChunk("{"); result.Indent(); foreach (FieldInfo field in t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { if (field.MemberType == MemberTypes.Field) { bool isOptional = false; var fieldIsActive = false; var keywordIfdefs = string.Empty; if (activeFields.permutationCount > 0) { // Evaluate all activeFields instance var instances = activeFields .allPermutations.instances .Where(i => ShouldSpliceField(t, field, i, out isOptional)) .ToList(); fieldIsActive = instances.Count > 0; if (fieldIsActive) { keywordIfdefs = KeywordUtil.GetKeywordPermutationSetConditional(instances .Select(i => i.permutationIndex).ToList()); } } else { fieldIsActive = ShouldSpliceField(t, field, activeFields.baseInstance, out isOptional); } if (fieldIsActive) { // The field is used, so generate it var semanticString = GetFieldSemantic(field); int componentCount; var fieldType = GetFieldType(field, out componentCount); var conditional = GetFieldConditional(field); if (conditional != null) { result.AddShaderChunk("#if " + conditional); } if (!string.IsNullOrEmpty(keywordIfdefs)) { result.AddShaderChunk(keywordIfdefs); } var fieldDecl = fieldType + " " + field.Name + semanticString + ";" + (isOptional & isDebug ? " // optional" : string.Empty); result.AddShaderChunk(fieldDecl); if (!string.IsNullOrEmpty(keywordIfdefs)) { result.AddShaderChunk("#endif" + (isDebug ? " // Shader Graph Keywords" : string.Empty)); } if (conditional != null) { result.AddShaderChunk("#endif" + (isDebug ? $" // {conditional}" : string.Empty)); } } } } result.Deindent(); result.AddShaderChunk("};"); object[] packAttributes = t.GetCustomAttributes(typeof(InterpolatorPack), false); if (packAttributes.Length > 0) { result.AddNewLine(); if (activeFields.permutationCount > 0) { var generatedPackedTypes = new Dictionary <string, (ShaderGenerator, List <int>)>(); foreach (var instance in activeFields.allPermutations.instances) { var instanceGenerator = new ShaderGenerator(); BuildPackedType(t, instance, instanceGenerator, isDebug); var key = instanceGenerator.GetShaderString(0); if (generatedPackedTypes.TryGetValue(key, out var value)) { value.Item2.Add(instance.permutationIndex); } else { generatedPackedTypes.Add(key, (instanceGenerator, new List <int> { instance.permutationIndex }));
internal static void GenerateSurfaceDescription( List <INode> activeNodeList, AbstractMaterialNode masterNode, AbstractMaterialGraph graph, ShaderGenerator surfaceDescriptionFunction, FunctionRegistry functionRegistry, PropertyCollector shaderProperties, ShaderGraphRequirements requirements, GenerationMode mode, string functionName = "PopulateSurfaceData", string surfaceDescriptionName = "SurfaceDescription", FloatShaderProperty outputIdProperty = null, IEnumerable <MaterialSlot> slots = null) { if (graph == null) { return; } surfaceDescriptionFunction.AddShaderChunk(String.Format("{0} {1}(SurfaceInputs IN) {{", surfaceDescriptionName, functionName), false); surfaceDescriptionFunction.Indent(); surfaceDescriptionFunction.AddShaderChunk(String.Format("{0} surface = ({0})0;", surfaceDescriptionName), false); graph.CollectShaderProperties(shaderProperties, mode); foreach (var activeNode in activeNodeList.OfType <AbstractMaterialNode>()) { if (activeNode is IGeneratesFunction) { functionRegistry.builder.currentNode = activeNode; (activeNode as IGeneratesFunction).GenerateNodeFunction(functionRegistry, mode); } if (activeNode is IGeneratesBodyCode) { (activeNode as IGeneratesBodyCode).GenerateNodeCode(surfaceDescriptionFunction, mode); } if (masterNode == null && activeNode.hasPreview) { var outputSlot = activeNode.GetOutputSlots <MaterialSlot>().FirstOrDefault(); if (outputSlot != null) { surfaceDescriptionFunction.AddShaderChunk(String.Format("if ({0} == {1}) {{ surface.PreviewOutput = {2}; return surface; }}", outputIdProperty.referenceName, activeNode.tempId.index, ShaderGenerator.AdaptNodeOutputForPreview(activeNode, outputSlot.id, activeNode.GetVariableNameForSlot(outputSlot.id))), false); } } activeNode.CollectShaderProperties(shaderProperties, mode); } functionRegistry.builder.currentNode = null; if (masterNode != null) { if (masterNode is IMasterNode) { var usedSlots = slots ?? masterNode.GetInputSlots <MaterialSlot>(); foreach (var input in usedSlots) { var foundEdges = graph.GetEdges(input.slotReference).ToArray(); if (foundEdges.Any()) { surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), masterNode.GetSlotValue(input.id, mode)), true); } else { surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(input.shaderOutputName), input.GetDefaultValue(mode)), true); } } } else if (masterNode.hasPreview) { foreach (var slot in masterNode.GetOutputSlots <MaterialSlot>()) { surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", NodeUtils.GetHLSLSafeName(slot.shaderOutputName), masterNode.GetSlotValue(slot.id, mode)), true); } } } surfaceDescriptionFunction.AddShaderChunk("return surface;", false); surfaceDescriptionFunction.Deindent(); surfaceDescriptionFunction.AddShaderChunk("}", false); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { var inputValue = GetSlotValue(InputSlotXId, generationMode); visitor.AddShaderChunk(precision + " " + GetVariableNameForSlot(OutputSlotId) + " = " + inputValue + ";", false); }
public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode) { var inputValue = GetSlotValue(InputSlotId, generationMode); var inputSlot = FindInputSlot <MaterialSlot>(InputSlotId); var numInputRows = 0; bool useIndentity = false; if (inputSlot != null) { numInputRows = SlotValueHelper.GetMatrixDimension(inputSlot.concreteValueType); if (numInputRows > 4) { numInputRows = 0; } if (!owner.GetEdges(inputSlot.slotReference).Any()) { numInputRows = 0; useIndentity = true; } } int concreteRowCount = useIndentity ? 2 : numInputRows; for (var r = 0; r < 4; r++) { string outputValue; if (r >= numInputRows) { outputValue = string.Format("{0}{1}(", precision, concreteRowCount); for (int c = 0; c < concreteRowCount; c++) { if (c != 0) { outputValue += ", "; } outputValue += Matrix4x4.identity.GetRow(r)[c]; } outputValue += ")"; } else { switch (m_Axis) { case MatrixAxis.Column: outputValue = string.Format("{0}{1}(", precision, numInputRows); for (int c = 0; c < numInputRows; c++) { if (c != 0) { outputValue += ", "; } outputValue += string.Format("{0}[{1}].{2}", inputValue, c, s_ComponentList[r]); } outputValue += ")"; break; default: outputValue = string.Format("{0}[{1}]", inputValue, r); break; } } visitor.AddShaderChunk(string.Format("{0}{1} {2} = {3};", precision, concreteRowCount, GetVariableNameForSlot(s_OutputSlots[r]), outputValue), true); } }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { NodeUtils.SlotConfigurationExceptionIfBadConfiguration(this, new[] { InputSlotId }, new[] { OutputSlotId }); string inputValue = string.Format("{0}.xyz", GetSlotValue(InputSlotId, generationMode)); string targetTransformString = "tangentTransform_" + conversion.from.ToString(); string transposeTargetTransformString = "transposeTangent"; string transformString = ""; string tangentTransformSpace = conversion.from.ToString(); bool requiresTangentTransform = false; bool requiresTransposeTangentTransform = false; if (conversion.from == CoordinateSpace.World) { if (conversion.to == CoordinateSpace.World) { transformString = inputValue; } else if (conversion.to == CoordinateSpace.Object) { transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToObjectDir({0})" : "TransformWorldToObject({0})", inputValue); } else if (conversion.to == CoordinateSpace.Tangent) { requiresTangentTransform = true; transformString = string.Format("TransformWorldToTangent({0}, {1})", inputValue, targetTransformString); } else if (conversion.to == CoordinateSpace.View) { transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToViewDir({0})" : "TransformWorldToView({0})", inputValue); } } else if (conversion.from == CoordinateSpace.Object) { if (conversion.to == CoordinateSpace.World) { transformString = string.Format(conversionType == ConversionType.Direction ? "TransformObjectToWorldDir({0})" : "TransformObjectToWorld({0})", inputValue); } else if (conversion.to == CoordinateSpace.Object) { transformString = inputValue; } else if (conversion.to == CoordinateSpace.Tangent) { requiresTangentTransform = true; transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToTangent(TransformObjectToWorldDir({0}), {1})" : "TransformWorldToTangent(TransformObjectToWorld({0}), {1})", inputValue, targetTransformString); } else if (conversion.to == CoordinateSpace.View) { transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToViewDir(TransformObjectToWorldDir({0}))" : "TransformWorldToView(TransformObjectToWorld({0}))", inputValue); } } else if (conversion.from == CoordinateSpace.Tangent) { if (conversion.to == CoordinateSpace.World) { requiresTransposeTangentTransform = true; transformString = string.Format("mul({0}, {1}).xyz", inputValue, transposeTargetTransformString); } else if (conversion.to == CoordinateSpace.Object) { requiresTransposeTangentTransform = true; transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToObjectDir(mul({0}, {1}).xyz)" : "TransformWorldToObject(mul({0}, {1}).xyz)", inputValue, transposeTargetTransformString); } else if (conversion.to == CoordinateSpace.Tangent) { transformString = inputValue; } else if (conversion.to == CoordinateSpace.View) { requiresTransposeTangentTransform = true; transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToViewDir(mul({0}, {1}).xyz)" : "TransformWorldToView(mul({0}, {1}).xyz)", inputValue, transposeTargetTransformString); } } else if (conversion.from == CoordinateSpace.View) { if (conversion.to == CoordinateSpace.World) { transformString = string.Format("mul(UNITY_MATRIX_I_V, float4({0}, 1)).xyz", inputValue); } else if (conversion.to == CoordinateSpace.Object) { transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToObjectDir(mul(UNITY_MATRIX_I_V, float4({0}, 1) ).xyz)" : "TransformWorldToObject(mul(UNITY_MATRIX_I_V, float4({0}, 1) ).xyz)", inputValue); } else if (conversion.to == CoordinateSpace.Tangent) { requiresTangentTransform = true; tangentTransformSpace = CoordinateSpace.World.ToString(); transformString = string.Format("TransformWorldToTangent(mul(UNITY_MATRIX_I_V, float4({0}, 1) ).xyz, {1})", inputValue, targetTransformString); } else if (conversion.to == CoordinateSpace.View) { transformString = inputValue; } } if (requiresTransposeTangentTransform) { visitor.AddShaderChunk(string.Format("float3x3 {0} = transpose(float3x3(IN.{1}SpaceTangent, IN.{1}SpaceBiTangent, IN.{1}SpaceNormal));", transposeTargetTransformString, CoordinateSpace.World.ToString()), true); } else if (requiresTangentTransform) { visitor.AddShaderChunk(string.Format("float3x3 {0} = float3x3(IN.{1}SpaceTangent, IN.{1}SpaceBiTangent, IN.{1}SpaceNormal);", targetTransformString, tangentTransformSpace), true); } visitor.AddShaderChunk(string.Format("{0} {1} = {2};", NodeUtils.ConvertConcreteSlotValueTypeToString(precision, FindOutputSlot <MaterialSlot>(OutputSlotId).concreteValueType), GetVariableNameForSlot(OutputSlotId), transformString), true); }
// Node generations public virtual void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { ProceduralTexture2DInputMaterialSlot slot = FindInputSlot <ProceduralTexture2DInputMaterialSlot>(ProceduralTexture2DId); // Find Procedural Texture 2D Asset ProceduralTexture2D proceduralTexture2D = slot.proceduralTexture2D; var edges = owner.GetEdges(slot.slotReference).ToArray(); if (edges.Any()) { var fromSocketRef = edges[0].outputSlot; var fromNode = owner.GetNodeFromGuid <ProceduralTexture2DNode>(fromSocketRef.nodeGuid); if (fromNode != null) { proceduralTexture2D = fromNode.proceduralTexture2D; } } // No Procedural Texture 2D Asset found, break and initialize output values to default white if (proceduralTexture2D == null || proceduralTexture2D.Tinput == null || proceduralTexture2D.invT == null) { visitor.AddShaderChunk(string.Format("{0}4 {1} = float4(1, 1, 1, 1);", precision, GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.r;", precision, GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.g;", precision, GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.b;", precision, GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.a;", precision, GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId)), true); return; } // Apply hidden inputs stored in Procedural Texture 2D Asset to shader FindInputSlot <Texture2DInputMaterialSlot>(TinputId).texture = proceduralTexture2D.Tinput; FindInputSlot <Texture2DInputMaterialSlot>(InvTinputId).texture = proceduralTexture2D.invT; FindInputSlot <Vector4MaterialSlot>(CompressionScalersId).value = proceduralTexture2D.compressionScalers; FindInputSlot <Vector3MaterialSlot>(ColorSpaceOriginId).value = proceduralTexture2D.colorSpaceOrigin; FindInputSlot <Vector3MaterialSlot>(ColorSpaceVector1Id).value = proceduralTexture2D.colorSpaceVector1; FindInputSlot <Vector3MaterialSlot>(ColorSpaceVector2Id).value = proceduralTexture2D.colorSpaceVector2; FindInputSlot <Vector3MaterialSlot>(ColorSpaceVector3Id).value = proceduralTexture2D.colorSpaceVector3; FindInputSlot <Vector3MaterialSlot>(InputSizeId).value = new Vector3( proceduralTexture2D.Tinput.width, proceduralTexture2D.Tinput.height, proceduralTexture2D.invT.height); string code = @" float4 {9} = float4(0, 0, 0, 0); { float2 uvScaled = {0} * 3.464; // 2 * sqrt(3) const float2x2 gridToSkewedGrid = float2x2(1.0, 0.0, -0.57735027, 1.15470054); float2 skewedCoord = mul(gridToSkewedGrid, uvScaled); int2 baseId = int2(floor(skewedCoord)); float3 temp = float3(frac(skewedCoord), 0); temp.z = 1.0 - temp.x - temp.y; float w1, w2, w3; int2 vertex1, vertex2, vertex3; if (temp.z > 0.0) { w1 = temp.z; w2 = temp.y; w3 = temp.x; vertex1 = baseId; vertex2 = baseId + int2(0, 1); vertex3 = baseId + int2(1, 0); } else { w1 = -temp.z; w2 = 1.0 - temp.y; w3 = 1.0 - temp.x; vertex1 = baseId + int2(1, 1); vertex2 = baseId + int2(1, 0); vertex3 = baseId + int2(0, 1); } float2 uv1 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), (float2)vertex1)) * 43758.5453); float2 uv2 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), (float2)vertex2)) * 43758.5453); float2 uv3 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), (float2)vertex3)) * 43758.5453); float2 duvdx = ddx({0}); float2 duvdy = ddy({0}); float4 G1 = {1}.SampleGrad({10}, uv1, duvdx, duvdy); float4 G2 = {1}.SampleGrad({10}, uv2, duvdx, duvdy); float4 G3 = {1}.SampleGrad({10}, uv3, duvdx, duvdy); float exponent = 1.0 + {11} * 15.0; w1 = pow(w1, exponent); w2 = pow(w2, exponent); w3 = pow(w3, exponent); float sum = w1 + w2 + w3; w1 = w1 / sum; w2 = w2 / sum; w3 = w3 / sum; float4 G = w1 * G1 + w2 * G2 + w3 * G3; G = G - 0.5; G = G * rsqrt(w1 * w1 + w2 * w2 + w3 * w3); G = G * {3}; G = G + 0.5; duvdx *= {8}.xy; duvdy *= {8}.xy; float delta_max_sqr = max(dot(duvdx, duvdx), dot(duvdy, duvdy)); float mml = 0.5 * log2(delta_max_sqr); float LOD = max(0, mml) / {8}.z; {9}.r = {2}.SampleLevel(sampler{2}, float2(G.r, LOD), 0).r; {9}.g = {2}.SampleLevel(sampler{2}, float2(G.g, LOD), 0).g; {9}.b = {2}.SampleLevel(sampler{2}, float2(G.b, LOD), 0).b; {9}.a = {2}.SampleLevel(sampler{2}, float2(G.a, LOD), 0).a; } " ; if (proceduralTexture2D != null && proceduralTexture2D.type != ProceduralTexture2D.TextureType.Other) { code += "{9}.rgb = {4} + {5} * {9}.r + {6} * {9}.g + {7} * {9}.b;"; } if (proceduralTexture2D != null && proceduralTexture2D.type == ProceduralTexture2D.TextureType.Normal) { code += "{9}.rgb = UnpackNormalmapRGorAG({9});"; } code = code.Replace("{0}", GetSlotValue(UVInput, generationMode)); code = code.Replace("{1}", GetSlotValue(TinputId, generationMode)); code = code.Replace("{2}", GetSlotValue(InvTinputId, generationMode)); code = code.Replace("{3}", GetSlotValue(CompressionScalersId, generationMode)); code = code.Replace("{4}", GetSlotValue(ColorSpaceOriginId, generationMode)); code = code.Replace("{5}", GetSlotValue(ColorSpaceVector1Id, generationMode)); code = code.Replace("{6}", GetSlotValue(ColorSpaceVector2Id, generationMode)); code = code.Replace("{7}", GetSlotValue(ColorSpaceVector3Id, generationMode)); code = code.Replace("{8}", GetSlotValue(InputSizeId, generationMode)); code = code.Replace("{9}", GetVariableNameForSlot(OutputSlotRGBAId)); var edgesSampler = owner.GetEdges(FindInputSlot <MaterialSlot>(SamplerInput).slotReference); code = code.Replace("{10}", edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : "sampler" + GetSlotValue(TinputId, generationMode)); code = code.Replace("{11}", GetSlotValue(BlendId, generationMode)); visitor.AddShaderChunk(code, true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.r;", precision, GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.g;", precision, GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.b;", precision, GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId)), true); visitor.AddShaderChunk(string.Format("{0} {1} = {2}.a;", precision, GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId)), true); }