public void GenerateNodeCode(ShaderStringBuilder sb, GraphContext graphContext, GenerationMode generationMode) { if (subGraphData == null || hasError) { var outputSlots = new List <MaterialSlot>(); GetOutputSlots(outputSlots); foreach (var slot in outputSlots) { sb.AppendLine($"{slot.concreteValueType.ToShaderString(subGraphData.outputPrecision)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};"); } return; } var inputVariableName = $"_{GetVariableNameForNode()}"; GraphUtil.GenerateSurfaceInputTransferCode(sb, subGraphData.requirements, subGraphData.inputStructName, inputVariableName); foreach (var outSlot in subGraphData.outputs) { sb.AppendLine("{0} {1};", outSlot.concreteValueType.ToShaderString(subGraphData.outputPrecision), GetVariableNameForSlot(outSlot.id)); } var arguments = new List <string>(); foreach (var prop in subGraphData.inputs) { prop.SetConcretePrecision(subGraphData.graphPrecision); 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, prop.concretePrecision))); } else if (prop is Texture2DArrayShaderProperty) { arguments.Add(string.Format("TEXTURE2D_ARRAY_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision))); } else if (prop is Texture3DShaderProperty) { arguments.Add(string.Format("TEXTURE3D_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision))); } else if (prop is CubemapShaderProperty) { arguments.Add(string.Format("TEXTURECUBE_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision))); } else { arguments.Add(string.Format("{0}", GetSlotValue(inSlotId, generationMode, prop.concretePrecision))); } } // pass surface inputs through arguments.Add(inputVariableName); foreach (var outSlot in subGraphData.outputs) { arguments.Add(GetVariableNameForSlot(outSlot.id)); } sb.AppendLine("{0}({1});", subGraphData.functionName, arguments.Aggregate((current, next) => string.Format("{0}, {1}", current, next))); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, 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 virtual void GenerateNodeFunction(FunctionRegistry registry, GraphContext graphContext, GenerationMode generationMode) { if (subGraphAsset == null || referencedGraph == null) { return; } List <AbstractMaterialNode> nodes = new List <AbstractMaterialNode>(); NodeUtils.DepthFirstCollectNodesFromNode(nodes, referencedGraph.outputNode); foreach (var node in nodes.OfType <AbstractMaterialNode>()) { node.ValidateNode(); if (node is IGeneratesFunction) { (node as IGeneratesFunction).GenerateNodeFunction(registry, graphContext, generationMode); } } string functionName = SubGraphFunctionName(graphContext); ShaderGraphRequirements reqs = ShaderGraphRequirements.FromNodes(new List <AbstractMaterialNode> { this }); registry.ProvideFunction(functionName, s => { s.AppendLine("// Subgraph function"); // Generate arguments... first INPUTS var arguments = new List <string>(); foreach (var prop in referencedGraph.properties) { arguments.Add(string.Format("{0}", prop.GetPropertyAsArgumentString())); } // now pass surface inputs arguments.Add(string.Format("{0} IN", graphContext.graphInputStructName)); // Now generate outputs foreach (var slot in outputNode.graphOutputs) { arguments.Add(string.Format("out {0} {1}", slot.concreteValueType.ToString(referencedGraph.outputNode.precision), slot.shaderOutputName)); } // Create the function protoype from the arguments s.AppendLine("void {0}({1})" , functionName , arguments.Aggregate((current, next) => string.Format("{0}, {1}", current, next))); // now generate the function using (s.BlockScope()) { // Just grab the body from the active nodes var bodyGenerator = new ShaderGenerator(); foreach (var node in nodes.OfType <AbstractMaterialNode>()) { if (node is IGeneratesBodyCode) { (node as IGeneratesBodyCode).GenerateNodeCode(bodyGenerator, graphContext, generationMode); } } outputNode.RemapOutputs(bodyGenerator, generationMode); s.Append(bodyGenerator.GetShaderString(1)); } }); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { visitor.AddShaderChunk(string.Format("{0}3 {1} = {0}3{2};", precision, GetVariableNameForSlot(kOutputSlotId), m_MaterialList[material].ToString(CultureInfo.InvariantCulture)), 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); }
private string SubGraphFunctionName(GraphContext graphContext) { var functionName = subGraphAsset != null?NodeUtils.GetHLSLSafeName(subGraphAsset.name) : "ERROR"; return(string.Format("sg_{0}_{1}_{2}", functionName, graphContext.graphInputStructName, GuidEncoder.Encode(referencedGraph.guid))); }
public void GenerateNodeCode(ShaderStringBuilder sb, GraphContext graphContext, GenerationMode generationMode) { sb.AppendLine(string.Format("$precision {0} = max(0, IN.{1});", GetVariableNameForSlot(OutputSlotId), ShaderGeneratorNames.FaceSign)); }
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}"); } // 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} = {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(ShaderStringBuilder sb, GraphContext graphContext, GenerationMode generationMode) { sb.AppendLine(string.Format("$precision4 {0} = IN.{1};", GetVariableNameForSlot(OutputSlotId), m_OutputChannel.GetUVName())); }
public void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode) { visitor.AddShaderChunk(precision + " " + GetVariableNameForNode() + " = " + m_constantList[constant].ToString(CultureInfo.InvariantCulture) + ";", true); }
public void GenerateNodeCode(ShaderStringBuilder sb, GraphContext graphContext, GenerationMode generationMode) { sb.AppendLine(string.Format("$precision3 {0} = $precision3{1};", GetVariableNameForSlot(kOutputSlotId), m_MaterialList[material].ToString(CultureInfo.InvariantCulture))); }