Exemple #1
0
        // TODO: could get rid of this if we could run a codegen prepass (with proper keyword #ifdef)
        public static void GenerateVirtualTextureFeedback(
            List <AbstractMaterialNode> downstreamNodesIncludingRoot,
            List <int>[] keywordPermutationsPerNode,
            ShaderStringBuilder surfaceDescriptionFunction,
            KeywordCollector shaderKeywords)
        {
            // A note on how we handle vt feedback in combination with keywords:
            // We essentially generate a fully separate feedback path for each permutation of keywords
            // so per permutation we gather variables contribution to feedback and we generate
            // feedback gathering for each permutation individually.

            var feedbackVariablesPerPermutation = PooledList <PooledList <string> > .Get();

            try
            {
                if (shaderKeywords.permutations.Count >= 1)
                {
                    for (int i = 0; i < shaderKeywords.permutations.Count; i++)
                    {
                        feedbackVariablesPerPermutation.Add(PooledList <string> .Get());
                    }
                }
                else
                {
                    // Create a dummy single permutation
                    feedbackVariablesPerPermutation.Add(PooledList <string> .Get());
                }

                int index = 0; //for keywordPermutationsPerNode
                foreach (var node in downstreamNodesIncludingRoot)
                {
                    if (node is SampleVirtualTextureNode vtNode)
                    {
                        if (vtNode.noFeedback)
                        {
                            continue;
                        }
                        if (keywordPermutationsPerNode[index] == null)
                        {
                            Debug.Assert(shaderKeywords.permutations.Count == 0, $"Shader has {shaderKeywords.permutations.Count} permutations but keywordPermutationsPerNode of some nodes are null.");
                            feedbackVariablesPerPermutation[0].Add(vtNode.GetFeedbackVariableName());
                        }
                        else
                        {
                            foreach (int perm in keywordPermutationsPerNode[index])
                            {
                                feedbackVariablesPerPermutation[perm].Add(vtNode.GetFeedbackVariableName());
                            }
                        }
                    }

                    if (node is SubGraphNode sgNode)
                    {
                        if (sgNode.asset == null)
                        {
                            continue;
                        }
                        if (keywordPermutationsPerNode[index] == null)
                        {
                            Debug.Assert(shaderKeywords.permutations.Count == 0, $"Shader has {shaderKeywords.permutations.Count} permutations but keywordPermutationsPerNode of some nodes are null.");
                            foreach (var feedbackSlot in sgNode.asset.vtFeedbackVariables)
                            {
                                feedbackVariablesPerPermutation[0].Add(node.GetVariableNameForNode() + "_" + feedbackSlot);
                            }
                        }
                        else
                        {
                            foreach (var feedbackSlot in sgNode.asset.vtFeedbackVariables)
                            {
                                foreach (int perm in keywordPermutationsPerNode[index])
                                {
                                    feedbackVariablesPerPermutation[perm].Add(node.GetVariableNameForNode() + "_" + feedbackSlot);
                                }
                            }
                        }
                    }

                    index++;
                }

                index = 0;
                foreach (var feedbackVariables in feedbackVariablesPerPermutation)
                {
                    // If it's a dummy single always-on permutation don't put an ifdef around the code
                    if (shaderKeywords.permutations.Count >= 1)
                    {
                        surfaceDescriptionFunction.AppendLine(KeywordUtil.GetKeywordPermutationConditional(index));
                    }

                    using (surfaceDescriptionFunction.BlockScope())
                    {
                        if (feedbackVariables.Count == 0)
                        {
                            string feedBackCode = "surface.VTPackedFeedback = float4(1.0f,1.0f,1.0f,1.0f);";
                            surfaceDescriptionFunction.AppendLine(feedBackCode);
                        }
                        else if (feedbackVariables.Count == 1)
                        {
                            string feedBackCode = "surface.VTPackedFeedback = GetPackedVTFeedback(" + feedbackVariables[0] + ");";
                            surfaceDescriptionFunction.AppendLine(feedBackCode);
                        }
                        else if (feedbackVariables.Count > 1)
                        {
                            surfaceDescriptionFunction.AppendLine("float4 VTFeedback_array[" + feedbackVariables.Count + "];");

                            int arrayIndex = 0;
                            foreach (var variable in feedbackVariables)
                            {
                                surfaceDescriptionFunction.AppendLine("VTFeedback_array[" + arrayIndex + "] = " + variable + ";");
                                arrayIndex++;
                            }

                            // TODO: should read from NDCPosition instead...
                            surfaceDescriptionFunction.AppendLine("uint pixelColumn = (IN.ScreenPosition.x / IN.ScreenPosition.w) * _ScreenParams.x;");
                            surfaceDescriptionFunction.AppendLine(
                                "surface.VTPackedFeedback = GetPackedVTFeedback(VTFeedback_array[(pixelColumn + _FrameCount) % (uint)" + feedbackVariables.Count + "]);");
                        }
                    }

                    if (shaderKeywords.permutations.Count >= 1)
                    {
                        surfaceDescriptionFunction.AppendLine("#endif");
                    }

                    index++;
                }
            }
            finally
            {
                foreach (var list in feedbackVariablesPerPermutation)
                {
                    list.Dispose();
                }
                feedbackVariablesPerPermutation.Dispose();
            }
        }
Exemple #2
0
        public static void GetKeywordPermutationDeclarations(ShaderStringBuilder sb, List <List <KeyValuePair <ShaderKeyword, int> > > permutations)
        {
            if (permutations.Count == 0)
            {
                return;
            }

            for (int p = 0; p < permutations.Count; p++)
            {
                // ShaderStringBuilder.Append doesnt apply indentation
                sb.AppendIndentation();

                // Append correct if
                bool isLast = false;
                if (p == 0)
                {
                    sb.Append("#if ");
                }
                else if (p == permutations.Count - 1)
                {
                    sb.Append("#else");
                    isLast = true;
                }
                else
                {
                    sb.Append("#elif ");
                }

                // Last permutation is always #else
                if (!isLast)
                {
                    // Track whether && is required
                    bool appendAnd = false;

                    // Iterate all keywords that are part of the permutation
                    for (int i = 0; i < permutations[p].Count; i++)
                    {
                        // When previous keyword was inserted subsequent requires &&
                        string and = appendAnd ? " && " : string.Empty;

                        switch (permutations[p][i].Key.keywordType)
                        {
                        case KeywordType.Enum:
                        {
                            sb.Append($"{and}defined({permutations[p][i].Key.referenceName}_{permutations[p][i].Key.entries[permutations[p][i].Value].referenceName})");
                            appendAnd = true;
                            break;
                        }

                        case KeywordType.Boolean:
                        {
                            // HLSL does not support a !value predicate
                            if (permutations[p][i].Value != 0)
                            {
                                continue;
                            }

                            sb.Append($"{and}defined({permutations[p][i].Key.referenceName})");
                            appendAnd = true;
                            break;
                        }

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                }
                sb.AppendNewLine();

                // Define the matching permutation keyword
                sb.IncreaseIndent();
                sb.AppendLine($"#define KEYWORD_PERMUTATION_{p}");
                sb.DecreaseIndent();
            }

            // End statement
            sb.AppendLine("#endif");
        }
        public static GenerationResults GetShader(this AbstractMaterialGraph graph, AbstractMaterialNode node, GenerationMode mode, string name)
        {
            // ----------------------------------------------------- //
            //                         SETUP                         //
            // ----------------------------------------------------- //

            // -------------------------------------
            // String builders

            var  finalShader = new ShaderStringBuilder();
            var  results     = new GenerationResults();
            bool isUber      = node == null;

            var shaderProperties = new PropertyCollector();
            var functionBuilder  = new ShaderStringBuilder();
            var functionRegistry = new FunctionRegistry(functionBuilder);

            var vertexDescriptionFunction = new ShaderStringBuilder(0);

            var surfaceDescriptionInputStruct = new ShaderStringBuilder(0);
            var surfaceDescriptionStruct      = new ShaderStringBuilder(0);
            var surfaceDescriptionFunction    = new ShaderStringBuilder(0);

            var vertexInputs = new ShaderStringBuilder(0);

            // -------------------------------------
            // Get Slot and Node lists

            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 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>());
                }
            }

            // -------------------------------------
            // Get Requirements

            var requirements = ShaderGraphRequirements.FromNodes(activeNodeList, ShaderStageCapability.Fragment);

            // -------------------------------------
            // Add preview shader output property

            results.outputIdProperty = new Vector1ShaderProperty
            {
                displayName           = "OutputId",
                generatePropertyBlock = false,
                value = -1
            };
            if (isUber)
            {
                shaderProperties.AddShaderProperty(results.outputIdProperty);
            }

            // ----------------------------------------------------- //
            //                START VERTEX DESCRIPTION               //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Generate Vertex Description function

            vertexDescriptionFunction.AppendLine("GraphVertexInput PopulateVertexData(GraphVertexInput v)");
            using (vertexDescriptionFunction.BlockScope())
            {
                vertexDescriptionFunction.AppendLine("return v;");
            }

            // ----------------------------------------------------- //
            //               START SURFACE DESCRIPTION               //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Generate Input structure for Surface Description function
            // Surface Description Input requirements are needed to exclude intermediate translation spaces

            surfaceDescriptionInputStruct.AppendLine("struct SurfaceDescriptionInputs");
            using (surfaceDescriptionInputStruct.BlockSemicolonScope())
            {
                ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, surfaceDescriptionInputStruct);
                ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, surfaceDescriptionInputStruct);
                ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, surfaceDescriptionInputStruct);
                ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, surfaceDescriptionInputStruct);
                ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, surfaceDescriptionInputStruct);

                if (requirements.requiresVertexColor)
                {
                    surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor);
                }

                if (requirements.requiresScreenPosition)
                {
                    surfaceDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition);
                }

                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())
                {
                    surfaceDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName());
                }
            }

            // -------------------------------------
            // Generate Output structure for Surface Description function

            GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, !isUber);

            // -------------------------------------
            // Generate Surface Description function

            GenerateSurfaceDescriptionFunction(
                activeNodeList,
                node,
                graph,
                surfaceDescriptionFunction,
                functionRegistry,
                shaderProperties,
                requirements,
                mode,
                outputIdProperty: results.outputIdProperty);

            // ----------------------------------------------------- //
            //           GENERATE VERTEX > PIXEL PIPELINE            //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Generate Input structure for Vertex shader

            GenerateApplicationVertexInputs(requirements, vertexInputs);

            // ----------------------------------------------------- //
            //                      FINALIZE                         //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Build final shader

            finalShader.AppendLine(@"Shader ""{0}""", name);
            using (finalShader.BlockScope())
            {
                finalShader.AppendLine("Properties");
                using (finalShader.BlockScope())
                {
                    finalShader.AppendLines(shaderProperties.GetPropertiesBlock(0));
                }
                finalShader.AppendNewLine();

                finalShader.AppendLine(@"HLSLINCLUDE");
                finalShader.AppendLine("#define USE_LEGACY_UNITY_MATRIX_VARIABLES");
                finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/Common.hlsl""");
                finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/Packing.hlsl""");
                finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/Color.hlsl""");
                finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/UnityInstancing.hlsl""");
                finalShader.AppendLine(@"#include ""CoreRP/ShaderLibrary/EntityLighting.hlsl""");
                finalShader.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariables.hlsl""");
                finalShader.AppendLine(@"#include ""ShaderGraphLibrary/ShaderVariablesFunctions.hlsl""");
                finalShader.AppendLine(@"#include ""ShaderGraphLibrary/Functions.hlsl""");
                finalShader.AppendNewLine();

                finalShader.AppendLines(shaderProperties.GetPropertiesDeclaration(0));

                finalShader.AppendLines(surfaceDescriptionInputStruct.ToString());
                finalShader.AppendNewLine();

                finalShader.Concat(functionBuilder);
                finalShader.AppendNewLine();

                finalShader.AppendLines(surfaceDescriptionStruct.ToString());
                finalShader.AppendNewLine();
                finalShader.AppendLines(surfaceDescriptionFunction.ToString());
                finalShader.AppendNewLine();

                finalShader.AppendLines(vertexInputs.ToString());
                finalShader.AppendNewLine();
                finalShader.AppendLines(vertexDescriptionFunction.ToString());
                finalShader.AppendNewLine();

                finalShader.AppendLine(@"ENDHLSL");

                finalShader.AppendLines(ShaderGenerator.GetPreviewSubShader(node, requirements));
                ListPool <INode> .Release(activeNodeList);
            }

            // -------------------------------------
            // Finalize

            results.configuredTextures = shaderProperties.GetConfiguredTexutres();
            ShaderSourceMap sourceMap;

            results.shader    = finalShader.ToString(out sourceMap);
            results.sourceMap = sourceMap;
            return(results);
        }
Exemple #4
0
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            var property = owner.properties.FirstOrDefault(x => x.guid == propertyGuid);

            if (property == null)
            {
                return;
            }

            switch (property.propertyType)
            {
            case PropertyType.Boolean:
                sb.AppendLine($"$precision {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Vector1:
                sb.AppendLine($"$precision {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Vector2:
                sb.AppendLine($"$precision2 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Vector3:
                sb.AppendLine($"$precision3 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Vector4:
                sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Color:
                sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Matrix2:
                sb.AppendLine($"$precision2x2 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Matrix3:
                sb.AppendLine($"$precision3x3 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Matrix4:
                sb.AppendLine($"$precision4x4 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.SamplerState:
                sb.AppendLine($"SamplerState {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Gradient:
                if (generationMode == GenerationMode.Preview)
                {
                    sb.AppendLine($"Gradient {GetVariableNameForSlot(OutputSlotId)} = {GradientUtil.GetGradientForPreview(property.referenceName)};");
                }
                else
                {
                    sb.AppendLine($"Gradient {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                }
                break;
            }
        }
Exemple #5
0
        public static string GetPreviewSubShader(AbstractMaterialNode node, ShaderGraphRequirements shaderGraphRequirements)
        {
            // Should never be called without a node
            Debug.Assert(node != null);

            var vertexOutputStruct = new ShaderStringBuilder(2);

            var vertexShader = new ShaderStringBuilder(2);
            var vertexShaderDescriptionInputs = new ShaderStringBuilder(2);
            var vertexShaderOutputs           = new ShaderStringBuilder(1);

            var pixelShader = new ShaderStringBuilder(2);
            var pixelShaderSurfaceInputs = new ShaderStringBuilder(2);
            var pixelShaderSurfaceRemap  = new ShaderStringBuilder(2);

            ShaderGenerator.GenerateStandardTransforms(
                0,
                16,
                vertexOutputStruct,
                vertexShader,
                vertexShaderDescriptionInputs,
                vertexShaderOutputs,
                pixelShader,
                pixelShaderSurfaceInputs,
                shaderGraphRequirements,
                shaderGraphRequirements,
                ShaderGraphRequirements.none,
                ShaderGraphRequirements.none,
                CoordinateSpace.World);

            vertexShader.AppendLines(vertexShaderDescriptionInputs.ToString());
            vertexShader.AppendLines(vertexShaderOutputs.ToString());

            var outputSlot = node.GetOutputSlots <MaterialSlot>().FirstOrDefault();

            // Sub Graph Output uses first input slot
            if (node is SubGraphOutputNode)
            {
                outputSlot = node.GetInputSlots <MaterialSlot>().FirstOrDefault();
            }

            if (outputSlot != null)
            {
                var result = string.Format("surf.{0}", NodeUtils.GetHLSLSafeName(outputSlot.shaderOutputName));
                pixelShaderSurfaceRemap.AppendLine("return all(isfinite({0})) ? {1} : {2};",
                                                   result, AdaptNodeOutputForPreview(node, outputSlot.id, result), nanOutput);
            }
            else
            {
                // No valid slots to display, so just show black.
                // It's up to each node to error or warn as appropriate.
                pixelShaderSurfaceRemap.AppendLine("return 0;");
            }

            // -------------------------------------
            // Extra pixel shader work

            var faceSign = new ShaderStringBuilder();

            if (shaderGraphRequirements.requiresFaceSign)
            {
                faceSign.AppendLine(", half FaceSign : VFACE");
            }

            var res = subShaderTemplate.Replace("${Interpolators}", vertexOutputStruct.ToString());

            res = res.Replace("${VertexShader}", vertexShader.ToString());
            res = res.Replace("${FaceSign}", faceSign.ToString());
            res = res.Replace("${LocalPixelShader}", pixelShader.ToString());
            res = res.Replace("${SurfaceInputs}", pixelShaderSurfaceInputs.ToString());
            res = res.Replace("${SurfaceOutputRemap}", pixelShaderSurfaceRemap.ToString());
            return(res);
        }
Exemple #6
0
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            // }
            //
            // // 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;
                #if UNITY_2020_2_OR_NEWER
                var fromNode = owner.GetNodeFromId <ProceduralTexture2DNode>(fromSocketRef.node.objectId);
                                #else
                var fromNode = owner.GetNodeFromGuid <ProceduralTexture2DNode>(fromSocketRef.nodeGuid);
                                #endif
                if (fromNode != null)
                {
                    proceduralTexture2D = fromNode.proceduralTexture2D;
                }
            }

            var precision = concretePrecision.ToShaderString();

            // No Procedural Texture 2D Asset found, break and initialize output values to default white
            if (proceduralTexture2D == null || proceduralTexture2D.Tinput == null || proceduralTexture2D.invT == null)
            {
                sb.AppendLine("{0}4 {1} = float4(1, 1, 1, 1);", precision, GetVariableNameForSlot(OutputSlotRGBAId));
                sb.AppendLine("{0} {1} = {2}.r;", precision, GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId));
                sb.AppendLine("{0} {1} = {2}.g;", precision, GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId));
                sb.AppendLine("{0} {1} = {2}.b;", precision, GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId));
                sb.AppendLine("{0} {1} = {2}.a;", precision, GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId));
                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));

            sb.AppendLine(code);

            sb.AppendLine("{0} {1} = {2}.r;", precision, GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId));
            sb.AppendLine("{0} {1} = {2}.g;", precision, GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId));
            sb.AppendLine("{0} {1} = {2}.b;", precision, GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId));
            sb.AppendLine("{0} {1} = {2}.a;", precision, GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId));
        }
 public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
 {
     sb.AppendLine(string.Format("$precision4 {0} = {1};", GetVariableNameForSlot(kOutputSlotId), m_ScreenSpaceType.ToValueAsVariable()));
 }
Exemple #8
0
        public static string GetPreviewSubShader(AbstractMaterialNode node, ShaderGraphRequirements shaderGraphRequirements)
        {
            var vertexOutputStruct = new ShaderStringBuilder(2);

            var vertexShader = new ShaderStringBuilder(2);
            var vertexShaderDescriptionInputs = new ShaderStringBuilder(2);
            var vertexShaderOutputs           = new ShaderStringBuilder(1);

            var pixelShader = new ShaderStringBuilder(2);
            var pixelShaderSurfaceInputs = new ShaderStringBuilder(2);
            var pixelShaderSurfaceRemap  = new ShaderStringBuilder(2);

            ShaderGenerator.GenerateStandardTransforms(
                0,
                16,
                vertexOutputStruct,
                vertexShader,
                vertexShaderDescriptionInputs,
                vertexShaderOutputs,
                pixelShader,
                pixelShaderSurfaceInputs,
                shaderGraphRequirements,
                shaderGraphRequirements,
                ShaderGraphRequirements.none,
                ShaderGraphRequirements.none,
                CoordinateSpace.World);

            vertexShader.AppendLines(vertexShaderDescriptionInputs.ToString());
            vertexShader.AppendLines(vertexShaderOutputs.ToString());

            if (node != null)
            {
                var outputSlot = node.GetOutputSlots <MaterialSlot>().FirstOrDefault();
                if (outputSlot != null)
                {
                    var result = string.Format("surf.{0}", node.GetVariableNameForSlot(outputSlot.id));
                    pixelShaderSurfaceRemap.AppendLine("return {0};", AdaptNodeOutputForPreview(node, outputSlot.id, result));
                }
                else
                {
                    pixelShaderSurfaceRemap.AppendLine("return 0;");
                }
            }
            else
            {
                pixelShaderSurfaceRemap.AppendLine("return all(isfinite(surf.PreviewOutput)) ? surf.PreviewOutput : float4(1.0f, 0.0f, 1.0f, 1.0f);");
            }

            // -------------------------------------
            // Extra pixel shader work

            var faceSign = new ShaderStringBuilder();

            if (shaderGraphRequirements.requiresFaceSign)
            {
                faceSign.AppendLine(", half FaceSign : VFACE");
            }

            var res = subShaderTemplate.Replace("${Interpolators}", vertexOutputStruct.ToString());

            res = res.Replace("${VertexShader}", vertexShader.ToString());
            res = res.Replace("${FaceSign}", faceSign.ToString());
            res = res.Replace("${LocalPixelShader}", pixelShader.ToString());
            res = res.Replace("${SurfaceInputs}", pixelShaderSurfaceInputs.ToString());
            res = res.Replace("${SurfaceOutputRemap}", pixelShaderSurfaceRemap.ToString());
            return(res);
        }
Exemple #9
0
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode mode)
        {
            // preview is always generating a full shader, even when previewing within a subgraph
            bool isGeneratingSubgraph = owner.isSubGraph && (mode != GenerationMode.Preview);

            switch (property.propertyType)
            {
            case PropertyType.Boolean:
                sb.AppendLine($"$precision {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
                break;

            case PropertyType.Float:
                sb.AppendLine($"$precision {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
                break;

            case PropertyType.Vector2:
                sb.AppendLine($"$precision2 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
                break;

            case PropertyType.Vector3:
                sb.AppendLine($"$precision3 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
                break;

            case PropertyType.Vector4:
                sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
                break;

            case PropertyType.Color:
                switch (property.sgVersion)
                {
                case 0:
                case 2:
                    sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
                    break;

                case 1:
                case 3:
                    //Exposed color properties get put into the correct space automagikally by Unity UNLESS tagged as HDR, then they just get passed in as is.
                    //for consistency with other places in the editor, we assume HDR colors are in linear space, and correct for gamma space here
                    if ((property as ColorShaderProperty).colorMode == ColorMode.HDR)
                    {
                        sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = IsGammaSpace() ? LinearToSRGB({property.GetHLSLVariableName(isGeneratingSubgraph, mode)}) : {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
                    }
                    else
                    {
                        sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph, mode)};");
                    }
                    break;

                default:
                    throw new Exception($"Unknown Color Property Version on property {property.displayName}");
                }
                break;

            case PropertyType.Matrix2:
                sb.AppendLine($"$precision2x2 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                break;

            case PropertyType.Matrix3:
                sb.AppendLine($"$precision3x3 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                break;

            case PropertyType.Matrix4:
                sb.AppendLine($"$precision4x4 {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                break;

            case PropertyType.Texture2D:
                sb.AppendLine($"UnityTexture2D {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                break;

            case PropertyType.Texture3D:
                sb.AppendLine($"UnityTexture3D {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                break;

            case PropertyType.Texture2DArray:
                sb.AppendLine($"UnityTexture2DArray {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                break;

            case PropertyType.Cubemap:
                sb.AppendLine($"UnityTextureCube {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                break;

            case PropertyType.SamplerState:
                sb.AppendLine($"UnitySamplerState {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                break;

            case PropertyType.Gradient:
                if (mode == GenerationMode.Preview)
                {
                    sb.AppendLine($"Gradient {GetVariableNameForSlot(OutputSlotId)} = {GradientUtil.GetGradientForPreview(property.GetHLSLVariableName(isGeneratingSubgraph))};");
                }
                else
                {
                    sb.AppendLine($"Gradient {GetVariableNameForSlot(OutputSlotId)} = {property.GetHLSLVariableName(isGeneratingSubgraph)};");
                }
                break;
            }
        }
Exemple #10
0
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            NodeUtils.SlotConfigurationExceptionIfBadConfiguration(this, new[] { InputSlotId }, new[] { OutputSlotId });
            string inputValue                        = string.Format("{0}.xyz", GetSlotValue(InputSlotId, generationMode));
            string targetTransformString             = GetVariableNameForNode() + "_tangentTransform_" + conversion.from.ToString();
            string transposeTargetTransformString    = GetVariableNameForNode() + "_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.to == CoordinateSpace.AbsoluteWorld)
                {
                    transformString = string.Format("GetAbsolutePositionWS({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);
                }
                if (conversion.to == CoordinateSpace.AbsoluteWorld)
                {
                    transformString = string.Format(conversionType == ConversionType.Direction ? "TransformObjectToWorldDir({0})" : "GetAbsolutePositionWS(TransformObjectToWorld({0}))", inputValue);
                }
            }
            else if (conversion.from == CoordinateSpace.Tangent)
            {
                if (conversion.to == CoordinateSpace.World)
                {
                    requiresTransposeTangentTransform = true;
                    transformString = string.Format("mul({0}, {1}).xyz", transposeTargetTransformString, inputValue);
                }
                else if (conversion.to == CoordinateSpace.Object)
                {
                    requiresTransposeTangentTransform = true;
                    transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToObjectDir(mul({0}, {1}).xyz)" : "TransformWorldToObject(mul({0}, {1}).xyz)", transposeTargetTransformString, inputValue);
                }
                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)", transposeTargetTransformString, inputValue);
                }
                if (conversion.to == CoordinateSpace.AbsoluteWorld)
                {
                    requiresTransposeTangentTransform = true;
                    transformString = string.Format("GetAbsolutePositionWS(mul({0}, {1})).xyz", transposeTargetTransformString, inputValue);
                }
            }
            else if (conversion.from == CoordinateSpace.View)
            {
                if (conversion.to == CoordinateSpace.World)
                {
                    transformString = string.Format("mul(UNITY_MATRIX_I_V, $precision4({0}, 1)).xyz", inputValue);
                }
                else if (conversion.to == CoordinateSpace.Object)
                {
                    transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToObjectDir(mul(UNITY_MATRIX_I_V, $precision4({0}, 1) ).xyz)" : "TransformWorldToObject(mul(UNITY_MATRIX_I_V, $precision4({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, $precision4({0}, 1) ).xyz, {1})", inputValue, targetTransformString);
                }
                else if (conversion.to == CoordinateSpace.View)
                {
                    transformString = inputValue;
                }
                else if (conversion.to == CoordinateSpace.AbsoluteWorld)
                {
                    transformString = string.Format("GetAbsolutePositionWS(mul(UNITY_MATRIX_I_V, $precision4({0}, 1))).xyz", inputValue);
                }
            }
            else if (conversion.from == CoordinateSpace.AbsoluteWorld)
            {
                if (conversion.to == CoordinateSpace.World)
                {
                    transformString = string.Format("GetCameraRelativePositionWS({0})", inputValue);
                }
                else if (conversion.to == CoordinateSpace.Object)
                {
                    transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToObjectDir(GetCameraRelativePositionWS({0}))" : "TransformWorldToObject(GetCameraRelativePositionWS({0}))", inputValue);
                }
                else if (conversion.to == CoordinateSpace.Tangent)
                {
                    requiresTangentTransform = true;
                    tangentTransformSpace    = CoordinateSpace.World.ToString();
                    transformString          = string.Format("TransformWorldToTangent(GetCameraRelativePositionWS({0}), {1})", inputValue, targetTransformString);
                }
                else if (conversion.to == CoordinateSpace.View)
                {
                    transformString = string.Format(conversionType == ConversionType.Direction ? "TransformWorldToViewDir(GetCameraRelativePositionWS({0}))" : "TransformWorldToView(GetCameraRelativePositionWS({0}))", inputValue);
                }
                else if (conversion.to == CoordinateSpace.AbsoluteWorld)
                {
                    transformString = inputValue;
                }
            }
            if (requiresTransposeTangentTransform)
            {
                sb.AppendLine(string.Format("$precision3x3 {0} = transpose($precision3x3(IN.{1}SpaceTangent, IN.{1}SpaceBiTangent, IN.{1}SpaceNormal));", transposeTargetTransformString, CoordinateSpace.World.ToString()));
            }
            else if (requiresTangentTransform)
            {
                sb.AppendLine(string.Format("$precision3x3 {0} = $precision3x3(IN.{1}SpaceTangent, IN.{1}SpaceBiTangent, IN.{1}SpaceNormal);", targetTransformString, tangentTransformSpace));
            }
            sb.AppendLine("{0} {1} = {2};", FindOutputSlot <MaterialSlot>(OutputSlotId).concreteValueType.ToShaderString(),
                          GetVariableNameForSlot(OutputSlotId),
                          transformString);
        }
        public void GenerateNodeCode(ShaderStringBuilder sb, 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("$precision{0}(", 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("$precision{0}(", 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;
                    }
                }
                sb.AppendLine(string.Format("$precision{0} {1} = {2};", concreteRowCount, GetVariableNameForSlot(s_OutputSlots[r]), outputValue));
            }
        }
        public void GenerateNodeCode(ShaderStringBuilder sb, GraphContext graphContext, GenerationMode generationMode)
        {
            if (asset == null || hasError)
            {
                var outputSlots = new List <MaterialSlot>();
                GetOutputSlots(outputSlots);
                var outputPrecision = asset != null ? asset.outputPrecision : ConcretePrecision.Float;
                foreach (var slot in outputSlots)
                {
                    sb.AppendLine($"{slot.concreteValueType.ToShaderString(outputPrecision)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};");
                }

                return;
            }

            var inputVariableName = $"_{GetVariableNameForNode()}";

            GraphUtil.GenerateSurfaceInputTransferCode(sb, asset.requirements, asset.inputStructName, inputVariableName);

            foreach (var outSlot in asset.outputs)
            {
                sb.AppendLine("{0} {1};", outSlot.concreteValueType.ToShaderString(asset.outputPrecision), GetVariableNameForSlot(outSlot.id));
            }

            var arguments = new List <string>();

            foreach (var prop in asset.inputs)
            {
                prop.SetConcretePrecision(asset.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 asset.outputs)
            {
                arguments.Add(GetVariableNameForSlot(outSlot.id));
            }

            sb.AppendLine("{0}({1});", asset.functionName, arguments.Aggregate((current, next) => string.Format("{0}, {1}", current, next)));
        }
Exemple #13
0
        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);
        }
Exemple #14
0
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            var inputValue = GetSlotValue(InputSlotXId, generationMode);

            sb.AppendLine(string.Format("$precision {0} = {1};", GetVariableNameForSlot(OutputSlotId), inputValue));
        }
Exemple #15
0
        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)
                {
                    slots.AddRange(activeNode.GetInputSlots <MaterialSlot>());
                }
                else
                {
                    slots.AddRange(activeNode.GetOutputSlots <MaterialSlot>());
                }
            }
            GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, !isUber);

            var shaderProperties = new PropertyCollector();

            results.outputIdProperty = new FloatShaderProperty
            {
                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);
        }
Exemple #16
0
        public void GetPropertiesDeclaration(ShaderStringBuilder builder, GenerationMode mode, ConcretePrecision inheritedPrecision)
        {
            foreach (var prop in properties)
            {
                prop.ValidateConcretePrecision(inheritedPrecision);
            }

            if (mode == GenerationMode.Preview)
            {
                builder.AppendLine("CBUFFER_START(UnityPerMaterial)");
                foreach (var prop in properties.Where(p => !p.gpuInstanced))    // all non-gpu instanced properties (even non-batchable ones) - preview is weird
                {
                    prop.AppendBatchablePropertyDeclarations(builder);
                    prop.AppendNonBatchablePropertyDeclarations(builder);
                }
                var GPUInstancedProperties = properties.Where(p => p.gpuInstanced);
                if (GPUInstancedProperties.Any())
                {
                    builder.AppendLine("#ifdef UNITY_HYBRID_V1_INSTANCING_ENABLED");
                    foreach (var prop in GPUInstancedProperties)
                    {
                        prop.AppendBatchablePropertyDeclarations(builder, "_dummy;");
                    }
                    builder.AppendLine("#else");
                    foreach (var prop in GPUInstancedProperties)
                    {
                        prop.AppendBatchablePropertyDeclarations(builder);
                    }
                    builder.AppendLine("#endif");
                }
                builder.AppendLine("CBUFFER_END");
                return;
            }

            // Hybrid V1 generates a special version of UnityPerMaterial, which has dummy constants for
            // instanced properties, and regular constants for other properties.
            // Hybrid V2 generates a perfectly normal UnityPerMaterial, but needs to append
            // a UNITY_DOTS_INSTANCING_START/END block after it that contains the instanced properties.

#if !ENABLE_HYBRID_RENDERER_V2
            builder.AppendLine("CBUFFER_START(UnityPerMaterial)");

            // non-GPU instanced properties go first in the UnityPerMaterial cbuffer
            var batchableProperties = properties.Where(n => n.generatePropertyBlock && n.hasBatchableProperties);
            foreach (var prop in batchableProperties)
            {
                if (!prop.gpuInstanced)
                {
                    prop.AppendBatchablePropertyDeclarations(builder);
                }
            }

            var batchableGPUInstancedProperties = batchableProperties.Where(p => p.gpuInstanced);
            if (batchableGPUInstancedProperties.Any())
            {
                builder.AppendLine("#ifdef UNITY_HYBRID_V1_INSTANCING_ENABLED");
                foreach (var prop in batchableGPUInstancedProperties)
                {
                    // TODO: why is this inserting a dummy value?  this won't work on complex properties...
                    prop.AppendBatchablePropertyDeclarations(builder, "_dummy;");
                }
                builder.AppendLine("#else");
                foreach (var prop in batchableGPUInstancedProperties)
                {
                    prop.AppendBatchablePropertyDeclarations(builder);
                }
                builder.AppendLine("#endif");
            }
            builder.AppendLine("CBUFFER_END");
#else
            // TODO: need to test this path with HYBRID_RENDERER_V2 ...

            builder.AppendLine("CBUFFER_START(UnityPerMaterial)");
            int instancedCount = 0;
            foreach (var prop in properties.Where(n => n.generatePropertyBlock && n.hasBatchableProperties))
            {
                if (!prop.gpuInstanced)
                {
                    prop.AppendBatchablePropertyDeclarations(builder);
                }
                else
                {
                    instancedCount++;
                }
            }

            if (instancedCount > 0)
            {
                builder.AppendLine("// Hybrid instanced properties");
                foreach (var prop in properties.Where(n => n.generatePropertyBlock && n.hasBatchableProperties))
                {
                    if (prop.gpuInstanced)
                    {
                        prop.AppendBatchablePropertyDeclarations(builder);
                    }
                }
            }
            builder.AppendLine("CBUFFER_END");

            if (instancedCount > 0)
            {
                builder.AppendLine("#if defined(UNITY_DOTS_INSTANCING_ENABLED)");

                builder.AppendLine("// DOTS instancing definitions");
                builder.AppendLine("UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)");
                foreach (var prop in properties.Where(n => n.generatePropertyBlock && n.hasBatchableProperties))
                {
                    if (prop.gpuInstanced)
                    {
                        var    n    = prop.referenceName;
                        string type = prop.concreteShaderValueType.ToShaderString(prop.concretePrecision);
                        builder.AppendLine($"    UNITY_DOTS_INSTANCED_PROP({type}, {n})");
                    }
                }
                builder.AppendLine("UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)");

                builder.AppendLine("// DOTS instancing usage macros");
                foreach (var prop in properties.Where(n => n.generatePropertyBlock && n.hasBatchableProperties))
                {
                    if (prop.gpuInstanced)
                    {
                        var    n    = prop.referenceName;
                        string type = prop.concreteShaderValueType.ToShaderString(prop.concretePrecision);
                        builder.AppendLine($"#define {n} UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO({type}, Metadata_{n})");
                    }
                }
                builder.AppendLine("#endif");
            }
#endif

            // declare non-batchable properties
            foreach (var prop in properties.Where(n => n.hasNonBatchableProperties || !n.generatePropertyBlock))
            {
                if (prop.hasBatchableProperties && !prop.generatePropertyBlock) // batchable properties that don't generate property block can't be instanced, get put here
                {
                    prop.AppendBatchablePropertyDeclarations(builder);
                }

                prop.AppendNonBatchablePropertyDeclarations(builder);
            }
        }
Exemple #17
0
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            switch (property.propertyType)
            {
            case PropertyType.Boolean:
                sb.AppendLine($"$precision {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Float:
                sb.AppendLine($"$precision {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Vector2:
                sb.AppendLine($"$precision2 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Vector3:
                sb.AppendLine($"$precision3 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Vector4:
                sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Color:
                switch (property.sgVersion)
                {
                case 0:
                case 2:
                    sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                    break;

                case 1:
                case 3:
                    //Exposed color properties get put into the correct space automagikally by Unity UNLESS tagged as HDR, then they just get passed in as is.
                    //for consistency with other places in the editor, we assume HDR colors are in linear space, and correct for gamma space here
                    if ((property as ColorShaderProperty).colorMode == ColorMode.HDR)
                    {
                        sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = IsGammaSpace() ? LinearToSRGB({property.referenceName}) : {property.referenceName};");
                    }
                    else
                    {
                        sb.AppendLine($"$precision4 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                    }
                    break;

                default:
                    throw new Exception($"Unknown Color Property Version on property {property.displayName}");
                }
                break;

            case PropertyType.Matrix2:
                sb.AppendLine($"$precision2x2 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Matrix3:
                sb.AppendLine($"$precision3x3 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Matrix4:
                sb.AppendLine($"$precision4x4 {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.SamplerState:
                sb.AppendLine($"SamplerState {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                break;

            case PropertyType.Gradient:
                if (generationMode == GenerationMode.Preview)
                {
                    sb.AppendLine($"Gradient {GetVariableNameForSlot(OutputSlotId)} = {GradientUtil.GetGradientForPreview(property.referenceName)};");
                }
                else
                {
                    sb.AppendLine($"Gradient {GetVariableNameForSlot(OutputSlotId)} = {property.referenceName};");
                }
                break;
            }
        }
        public void GetPropertiesDeclaration(ShaderStringBuilder builder, GenerationMode mode, ConcretePrecision defaultPrecision)
        {
            foreach (var prop in properties)
            {
                // set up switched properties to use the inherited precision
                prop.SetupConcretePrecision(defaultPrecision);
            }

            // build a list of all HLSL properties
            var hlslProps = BuildHLSLPropertyList();

            if (mode == GenerationMode.Preview)
            {
                builder.AppendLine("CBUFFER_START(UnityPerMaterial)");

                // all non-gpu instanced properties (even non-batchable ones!)
                // this is because for preview we convert all properties to UnityPerMaterial properties
                // as we will be submitting the default preview values via the Material..  :)
                foreach (var h in hlslProps)
                {
                    if ((h.declaration == HLSLDeclaration.UnityPerMaterial) ||
                        (h.declaration == HLSLDeclaration.Global))
                    {
                        h.AppendTo(builder);
                    }
                }

                // gpu-instanced properties
                var gpuInstancedProps = hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance);
                if (gpuInstancedProps.Any())
                {
                    builder.AppendLine("#ifdef UNITY_HYBRID_V1_INSTANCING_ENABLED");
                    foreach (var h in gpuInstancedProps)
                    {
                        h.AppendTo(builder, name => name + "_dummy");
                    }
                    builder.AppendLine("#else // V2");
                    foreach (var h in gpuInstancedProps)
                    {
                        h.AppendTo(builder);
                    }
                    builder.AppendLine("#endif");
                }
                builder.AppendLine("CBUFFER_END");
                return;
            }

            // Hybrid V1 generates a special version of UnityPerMaterial, which has dummy constants for
            // instanced properties, and regular constants for other properties.
            // Hybrid V2 generates a perfectly normal UnityPerMaterial, but needs to append
            // a UNITY_DOTS_INSTANCING_START/END block after it that contains the instanced properties.

#if !ENABLE_HYBRID_RENDERER_V2
            builder.AppendLine("CBUFFER_START(UnityPerMaterial)");

            // non-GPU-instanced batchable properties go first in the UnityPerMaterial cbuffer
            foreach (var h in hlslProps)
            {
                if (h.declaration == HLSLDeclaration.UnityPerMaterial)
                {
                    h.AppendTo(builder);
                }
            }

            // followed by GPU-instanced batchable properties
            var gpuInstancedProperties = hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance);
            if (gpuInstancedProperties.Any())
            {
                builder.AppendLine("#ifdef UNITY_HYBRID_V1_INSTANCING_ENABLED");
                foreach (var hlslProp in gpuInstancedProperties)
                {
                    hlslProp.AppendTo(builder, name => name + "_dummy");
                }
                builder.AppendLine("#else");
                foreach (var hlslProp in gpuInstancedProperties)
                {
                    hlslProp.AppendTo(builder);
                }
                builder.AppendLine("#endif");
            }
            builder.AppendLine("CBUFFER_END");
#else
            // TODO: need to test this path with HYBRID_RENDERER_V2 ...

            builder.AppendLine("CBUFFER_START(UnityPerMaterial)");

            int instancedCount = 0;
            foreach (var h in hlslProps)
            {
                if (h.declaration == HLSLDeclaration.UnityPerMaterial)
                {
                    h.AppendTo(builder);
                }
                else if (h.declaration == HLSLDeclaration.HybridPerInstance)
                {
                    instancedCount++;
                }
            }

            if (instancedCount > 0)
            {
                builder.AppendLine("// Hybrid instanced properties");
                foreach (var h in hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance))
                {
                    h.AppendTo(builder);
                }
            }
            builder.AppendLine("CBUFFER_END");

            if (instancedCount > 0)
            {
                builder.AppendLine("#if defined(UNITY_DOTS_INSTANCING_ENABLED)");

                builder.AppendLine("// DOTS instancing definitions");
                builder.AppendLine("UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)");
                foreach (var h in hlslProps.Where(h => h.declaration == HLSLDeclaration.HybridPerInstance))
                {
                    var    n    = h.name;
                    string type = h.GetValueTypeString();
                    builder.AppendLine($"    UNITY_DOTS_INSTANCED_PROP({type}, {n})");
                }
                builder.AppendLine("UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)");

                builder.AppendLine("// DOTS instancing usage macros");
                builder.AppendLine("#define UNITY_ACCESS_HYBRID_INSTANCED_PROP(var, type) UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(type, Metadata_##var)");
                builder.AppendLine("#else");
                builder.AppendLine("#define UNITY_ACCESS_HYBRID_INSTANCED_PROP(var, type) var");
                builder.AppendLine("#endif");
            }
#endif

            builder.AppendNewLine();
            builder.AppendLine("// Object and Global properties");
            foreach (var h in hlslProps)
            {
                if (h.declaration == HLSLDeclaration.Global)
                {
                    h.AppendTo(builder);
                }
            }
        }
Exemple #19
0
        // Node generations
        public virtual void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            sb.AppendLine("$precision3 {0}_UV = {1} * {2};", 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:
                // See comment for default case.
                sb.AppendLine("$precision3 {0}_Blend = SafePositivePow_$precision({1}, min({2}, floor(log2(Min_$precision())/log2(1/sqrt(3)))) );"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode)
                              , GetSlotValue(BlendInputId, generationMode));
                sb.AppendLine("{0}_Blend /= ({0}_Blend.x + {0}_Blend.y + {0}_Blend.z ).xxx;", GetVariableNameForNode());

                sb.AppendLine("$precision3 {0}_X = UnpackNormal(SAMPLE_TEXTURE2D({1}.tex, {2}.samplerstate, {0}_UV.zy));"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : id);

                sb.AppendLine("$precision3 {0}_Y = UnpackNormal(SAMPLE_TEXTURE2D({1}.tex, {2}.samplerstate, {0}_UV.xz));"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : id);

                sb.AppendLine("$precision3 {0}_Z = UnpackNormal(SAMPLE_TEXTURE2D({1}.tex, {2}.samplerstate, {0}_UV.xy));"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : id);

                sb.AppendLine("{0}_X = $precision3({0}_X.xy + {1}.zy, abs({0}_X.z) * {1}.x);"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode));

                sb.AppendLine("{0}_Y = $precision3({0}_Y.xy + {1}.xz, abs({0}_Y.z) * {1}.y);"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode));

                sb.AppendLine("{0}_Z = $precision3({0}_Z.xy + {1}.xy, abs({0}_Z.z) * {1}.z);"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode));

                var outputVariable = GetVariableNameForSlot(OutputSlotId);
                sb.AppendLine("$precision4 {0} = $precision4({1}_X.zyx * {1}_Blend.x + {1}_Y.xzy * {1}_Blend.y + {1}_Z.xyz * {1}_Blend.z, 1);"
                              , outputVariable
                              , GetVariableNameForNode());

                // transform the normal from input to output space, and normalize

                outputVariable = $"{outputVariable}.rgb";
                SpaceTransformUtil.GenerateTransformCodeStatement(normalTransform, outputVariable, outputVariable, sb);
                break;

            default:
                // We want the sum of the 3 blend weights (by which we normalize them) to be > 0.
                // Max safe exponent is log2(REAL_MIN)/log2(1/sqrt(3)):
                // Take the set of all possible normalized vectors, make a set from selecting the maximum component of each 3-vectors from the previous set,
                // the minimum (:= min_of_max) of that new set is 1/sqrt(3) (by the fact vectors are normalized).
                // We then want a maximum exponent such that
                //                            precision_min < min_of_max^exponent_max
                // where exponent_max is blend,
                //                       log(precision_min) < log(min_of_max) * exponent_max
                //     log(precision_min) / log(min_of_max) > exponent_max
                sb.AppendLine("$precision3 {0}_Blend = SafePositivePow_$precision({1}, min({2}, floor(log2(Min_$precision())/log2(1/sqrt(3)))) );"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode)
                              , GetSlotValue(BlendInputId, generationMode));
                sb.AppendLine("{0}_Blend /= dot({0}_Blend, 1.0);", GetVariableNameForNode());
                sb.AppendLine("$precision4 {0}_X = SAMPLE_TEXTURE2D({1}.tex, {2}.samplerstate, {0}_UV.zy);"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : id);

                sb.AppendLine("$precision4 {0}_Y = SAMPLE_TEXTURE2D({1}.tex, {2}.samplerstate, {0}_UV.xz);"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : id);

                sb.AppendLine("$precision4 {0}_Z = SAMPLE_TEXTURE2D({1}.tex, {2}.samplerstate, {0}_UV.xy);"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : id);

                sb.AppendLine("$precision4 {0} = {1}_X * {1}_Blend.x + {1}_Y * {1}_Blend.y + {1}_Z * {1}_Blend.z;"
                              , GetVariableNameForSlot(OutputSlotId)
                              , GetVariableNameForNode());
                break;
            }
        }
Exemple #20
0
        public static GenerationResults GetShader(this GraphData graph, AbstractMaterialNode node, GenerationMode mode, string name)
        {
            // ----------------------------------------------------- //
            //                         SETUP                         //
            // ----------------------------------------------------- //

            // -------------------------------------
            // String builders

            var finalShader = new ShaderStringBuilder();
            var results     = new GenerationResults();

            var shaderProperties          = new PropertyCollector();
            var shaderKeywords            = new KeywordCollector();
            var shaderPropertyUniforms    = new ShaderStringBuilder();
            var shaderKeywordDeclarations = new ShaderStringBuilder();
            var shaderKeywordPermutations = new ShaderStringBuilder(1);

            var functionBuilder  = new ShaderStringBuilder();
            var functionRegistry = new FunctionRegistry(functionBuilder);

            var vertexDescriptionFunction = new ShaderStringBuilder(0);

            var surfaceDescriptionInputStruct = new ShaderStringBuilder(0);
            var surfaceDescriptionStruct      = new ShaderStringBuilder(0);
            var surfaceDescriptionFunction    = new ShaderStringBuilder(0);

            var vertexInputs = new ShaderStringBuilder(0);

            graph.CollectShaderKeywords(shaderKeywords, mode);

            if (graph.GetKeywordPermutationCount() > ShaderGraphPreferences.variantLimit)
            {
                graph.AddValidationError(node.tempId, ShaderKeyword.kVariantLimitWarning, Rendering.ShaderCompilerMessageSeverity.Error);

                results.configuredTextures = shaderProperties.GetConfiguredTexutres();
                results.shader             = string.Empty;
                return(results);
            }

            // -------------------------------------
            // Get Slot and Node lists

            var activeNodeList = ListPool <AbstractMaterialNode> .Get();

            NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node);

            var slots = new List <MaterialSlot>();

            if (node is IMasterNode || node is SubGraphOutputNode)
            {
                slots.AddRange(node.GetInputSlots <MaterialSlot>());
            }
            else
            {
                var outputSlots = node.GetOutputSlots <MaterialSlot>().ToList();
                if (outputSlots.Count > 0)
                {
                    slots.Add(outputSlots[0]);
                }
            }

            // -------------------------------------
            // Get Requirements

            var requirements = ShaderGraphRequirements.FromNodes(activeNodeList, ShaderStageCapability.Fragment);

            // ----------------------------------------------------- //
            //                         KEYWORDS                      //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Get keyword permutations

            graph.CollectShaderKeywords(shaderKeywords, mode);

            // Track permutation indicies for all nodes and requirements
            List <int>[] keywordPermutationsPerNode = new List <int> [activeNodeList.Count];

            // -------------------------------------
            // Evaluate all permutations

            for (int i = 0; i < shaderKeywords.permutations.Count; i++)
            {
                // Get active nodes for this permutation
                var localNodes = ListPool <AbstractMaterialNode> .Get();

                NodeUtils.DepthFirstCollectNodesFromNode(localNodes, node, keywordPermutation: shaderKeywords.permutations[i]);

                // Track each pixel node in this permutation
                foreach (AbstractMaterialNode pixelNode in localNodes)
                {
                    int nodeIndex = activeNodeList.IndexOf(pixelNode);

                    if (keywordPermutationsPerNode[nodeIndex] == null)
                    {
                        keywordPermutationsPerNode[nodeIndex] = new List <int>();
                    }
                    keywordPermutationsPerNode[nodeIndex].Add(i);
                }

                // Get active requirements for this permutation
                var localSurfaceRequirements = ShaderGraphRequirements.FromNodes(localNodes, ShaderStageCapability.Fragment, false);
                var localPixelRequirements   = ShaderGraphRequirements.FromNodes(localNodes, ShaderStageCapability.Fragment);
            }


            // ----------------------------------------------------- //
            //                START VERTEX DESCRIPTION               //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Generate Vertex Description function

            vertexDescriptionFunction.AppendLine("GraphVertexInput PopulateVertexData(GraphVertexInput v)");
            using (vertexDescriptionFunction.BlockScope())
            {
                vertexDescriptionFunction.AppendLine("return v;");
            }

            // ----------------------------------------------------- //
            //               START SURFACE DESCRIPTION               //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Generate Input structure for Surface Description function
            // Surface Description Input requirements are needed to exclude intermediate translation spaces

            GenerateSurfaceInputStruct(surfaceDescriptionInputStruct, requirements, "SurfaceDescriptionInputs");

            results.previewMode = PreviewMode.Preview2D;
            foreach (var pNode in activeNodeList)
            {
                if (pNode.previewMode == PreviewMode.Preview3D)
                {
                    results.previewMode = PreviewMode.Preview3D;
                    break;
                }
            }

            // -------------------------------------
            // Generate Output structure for Surface Description function

            GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, slots, useIdsInNames: !(node is IMasterNode));

            // -------------------------------------
            // Generate Surface Description function

            GenerateSurfaceDescriptionFunction(
                activeNodeList,
                keywordPermutationsPerNode,
                node,
                graph,
                surfaceDescriptionFunction,
                functionRegistry,
                shaderProperties,
                shaderKeywords,
                mode,
                outputIdProperty: results.outputIdProperty);

            // ----------------------------------------------------- //
            //           GENERATE VERTEX > PIXEL PIPELINE            //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Keyword declarations

            shaderKeywords.GetKeywordsDeclaration(shaderKeywordDeclarations, mode);

            // -------------------------------------
            // Property uniforms

            shaderProperties.GetPropertiesDeclaration(shaderPropertyUniforms, mode, graph.concretePrecision);

            // -------------------------------------
            // Generate Input structure for Vertex shader

            GenerateApplicationVertexInputs(requirements, vertexInputs);

            // ----------------------------------------------------- //
            //                      FINALIZE                         //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Build final shader

            finalShader.AppendLine(@"Shader ""{0}""", name);
            using (finalShader.BlockScope())
            {
                SubShaderGenerator.GeneratePropertiesBlock(finalShader, shaderProperties, shaderKeywords, mode);
                finalShader.AppendNewLine();

                finalShader.AppendLine(@"HLSLINCLUDE");
                finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/NormalSurfaceGradient.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariables.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariablesFunctions.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl""");
                finalShader.AppendLine(@"#include ""Packages/com.seasun.idsystem/Shaders/URP/Common/URPCommon.hlsl""");

                finalShader.AppendLines(shaderKeywordDeclarations.ToString());
                finalShader.AppendLine(@"#define SHADERGRAPH_PREVIEW 1");
                finalShader.AppendNewLine();

                finalShader.AppendLines(shaderKeywordPermutations.ToString());

                finalShader.AppendLines(shaderPropertyUniforms.ToString());
                finalShader.AppendNewLine();

                finalShader.AppendLines(surfaceDescriptionInputStruct.ToString());
                finalShader.AppendNewLine();

                finalShader.Concat(functionBuilder);
                finalShader.AppendNewLine();

                finalShader.AppendLines(surfaceDescriptionStruct.ToString());
                finalShader.AppendNewLine();
                finalShader.AppendLines(surfaceDescriptionFunction.ToString());
                finalShader.AppendNewLine();

                finalShader.AppendLines(vertexInputs.ToString());
                finalShader.AppendNewLine();
                finalShader.AppendLines(vertexDescriptionFunction.ToString());
                finalShader.AppendNewLine();

                finalShader.AppendLine(@"ENDHLSL");

                finalShader.AppendLines(ShaderGenerator.GetPreviewSubShader(node, requirements));
                ListPool <AbstractMaterialNode> .Release(activeNodeList);
            }

            // -------------------------------------
            // Finalize

            results.configuredTextures = shaderProperties.GetConfiguredTexutres();
            ShaderSourceMap sourceMap;

            results.shader    = finalShader.ToString(out sourceMap);
            results.sourceMap = sourceMap;
            return(results);
        }
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            var outputGraphPrecision = asset?.outputGraphPrecision ?? GraphPrecision.Single;
            var outputPrecision      = outputGraphPrecision.ToConcrete(concretePrecision);

            if (asset == null || hasError)
            {
                var outputSlots = new List <MaterialSlot>();
                GetOutputSlots(outputSlots);

                foreach (var slot in outputSlots)
                {
                    sb.AppendLine($"{slot.concreteValueType.ToShaderString(outputPrecision)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};");
                }

                return;
            }

            var inputVariableName = $"_{GetVariableNameForNode()}";

            GenerationUtils.GenerateSurfaceInputTransferCode(sb, asset.requirements, asset.inputStructName, inputVariableName);

            // declare output variables
            foreach (var outSlot in asset.outputs)
            {
                sb.AppendLine("{0} {1};", outSlot.concreteValueType.ToShaderString(outputPrecision), GetVariableNameForSlot(outSlot.id));
            }

            var arguments = new List <string>();

            foreach (AbstractShaderProperty prop in asset.inputs)
            {
                // setup the property concrete precision (fallback to node concrete precision when it's switchable)
                prop.SetupConcretePrecision(this.concretePrecision);
                var inSlotId = m_PropertyIds[m_PropertyGuids.IndexOf(prop.guid.ToString())];
                arguments.Add(GetSlotValue(inSlotId, generationMode, prop.concretePrecision));
            }

            // pass surface inputs through
            arguments.Add(inputVariableName);

            foreach (var outSlot in asset.outputs)
            {
                arguments.Add(GetVariableNameForSlot(outSlot.id));
            }

            foreach (var feedbackSlot in asset.vtFeedbackVariables)
            {
                string feedbackVar = GetVariableNameForNode() + "_" + feedbackSlot;
                sb.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single), feedbackVar);
                arguments.Add(feedbackVar);
            }

            sb.AppendIndentation();
            sb.Append(asset.functionName);
            sb.Append("(");
            bool firstArg = true;

            foreach (var arg in arguments)
            {
                if (!firstArg)
                {
                    sb.Append(", ");
                }
                firstArg = false;
                sb.Append(arg);
            }
            sb.Append(");");
            sb.AppendNewLine();
        }
        // Node generations
        public virtual void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            var uvName = GetSlotValue(UVInput, generationMode);

            //Sampler input slot
            var samplerSlot  = FindInputSlot <MaterialSlot>(SamplerInput);
            var edgesSampler = owner.GetEdges(samplerSlot.slotReference);

            var id     = GetSlotValue(TextureInputId, generationMode);
            var offset = GetSlotValue(OffsetInput, generationMode);

            sb.AppendLine("#if (SHADER_TARGET >= 41)");
            {
                sb.AppendLine(string.Format("$precision4 {0} = {1}.tex.Gather({2}.samplerstate, {3}, {4});"
                                            , GetVariableNameForSlot(OutputSlotRGBAId)
                                            , id
                                            , edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : id
                                            , uvName
                                            , offset));
                sb.AppendLine(string.Format("$precision {0} = {1}.r;", GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId)));
                sb.AppendLine(string.Format("$precision {0} = {1}.g;", GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId)));
                sb.AppendLine(string.Format("$precision {0} = {1}.b;", GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId)));
                sb.AppendLine(string.Format("$precision {0} = {1}.a;", GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId)));
            }
            sb.AppendLine("#else");
            {
                // Gather offsets defined in this order:
                // (-,+),(+,+),(+,-),(-,-)

                var uvR = string.Format("(floor({0} * {1}.texelSize.zw + $precision2(-0.5, 0.5)) + trunc({2}) + $precision2(0.5, 0.5)) * {1}.texelSize.xy", uvName, id, offset);
                var uvG = string.Format("(floor({0} * {1}.texelSize.zw + $precision2(0.5, 0.5)) + trunc({2}) + $precision2(0.5, 0.5)) * {1}.texelSize.xy", uvName, id, offset);
                var uvB = string.Format("(floor({0} * {1}.texelSize.zw + $precision2(0.5, -0.5)) + trunc({2}) + $precision2(0.5, 0.5)) * {1}.texelSize.xy", uvName, id, offset);
                var uvA = string.Format("(floor({0} * {1}.texelSize.zw + $precision2(-0.5, -0.5)) + trunc({2}) + $precision2(0.5, 0.5)) * {1}.texelSize.xy", uvName, id, offset);

                sb.AppendLine(string.Format("$precision {0} = SAMPLE_TEXTURE2D_LOD({1}.tex, {2}.samplerstate, {3}, 0).r;", GetVariableNameForSlot(OutputSlotRId), id, edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : id, uvR));
                sb.AppendLine(string.Format("$precision {0} = SAMPLE_TEXTURE2D_LOD({1}.tex, {2}.samplerstate, {3}, 0).r;", GetVariableNameForSlot(OutputSlotGId), id, edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : id, uvG));
                sb.AppendLine(string.Format("$precision {0} = SAMPLE_TEXTURE2D_LOD({1}.tex, {2}.samplerstate, {3}, 0).r;", GetVariableNameForSlot(OutputSlotBId), id, edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : id, uvB));
                sb.AppendLine(string.Format("$precision {0} = SAMPLE_TEXTURE2D_LOD({1}.tex, {2}.samplerstate, {3}, 0).r;", GetVariableNameForSlot(OutputSlotAId), id, edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : id, uvA));

                sb.AppendLine(string.Format("$precision4 {0} = $precision4({1},{2},{3},{4});"
                                            , GetVariableNameForSlot(OutputSlotRGBAId)
                                            , GetVariableNameForSlot(OutputSlotRId)
                                            , GetVariableNameForSlot(OutputSlotGId)
                                            , GetVariableNameForSlot(OutputSlotBId)
                                            , GetVariableNameForSlot(OutputSlotAId)));
            }
            sb.AppendLine("#endif");
        }
Exemple #23
0
        public static void GenerateStandardTransforms(
            int interpolatorStartIndex,
            int maxInterpolators,
            ShaderStringBuilder vertexOutputStruct,
            ShaderStringBuilder vertexShader,
            ShaderStringBuilder vertexShaderDescriptionInputs,
            ShaderStringBuilder vertexShaderOutputs,
            ShaderStringBuilder pixelShader,
            ShaderStringBuilder pixelShaderSurfaceInputs,
            ShaderGraphRequirements pixelRequirements,
            ShaderGraphRequirements surfaceRequirements,
            ShaderGraphRequirements modelRequiements,
            ShaderGraphRequirements vertexRequirements,
            CoordinateSpace preferredCoordinateSpace)
        {
            // ----------------------------------------------------- //
            //                         SETUP                         //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Tangent space requires going via World space

            if (preferredCoordinateSpace == CoordinateSpace.Tangent)
            {
                preferredCoordinateSpace = CoordinateSpace.World;
            }

            // -------------------------------------
            // Generate combined graph requirements

            var graphModelRequirements = pixelRequirements.Union(modelRequiements);
            var combinedRequirements   = vertexRequirements.Union(graphModelRequirements);
            int interpolatorIndex      = interpolatorStartIndex;

            // ----------------------------------------------------- //
            //           GENERATE VERTEX > PIXEL PIPELINE            //
            // ----------------------------------------------------- //

            // -------------------------------------
            // If any stage requires component write into vertex stage
            // If model or pixel requires component write into interpolators and pixel stage

            // -------------------------------------
            // Position

            if (combinedRequirements.requiresPosition > 0)
            {
                var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Position);
                var preferredSpacePosition = ConvertBetweenSpace("v.vertex", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Position);
                vertexShader.AppendLine("float3 {0} = {1}.xyz;", name, preferredSpacePosition);
                if (graphModelRequirements.requiresPosition > 0)
                {
                    vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
                    vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
                    pixelShader.AppendLine("float3 {0} = IN.{0};", name);
                    interpolatorIndex++;
                }
            }

            // -------------------------------------
            // Normal
            // Bitangent needs Normal for x product

            if (combinedRequirements.requiresNormal > 0 || combinedRequirements.requiresBitangent > 0)
            {
                var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal);
                vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.normal", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Normal));
                if (graphModelRequirements.requiresNormal > 0 || graphModelRequirements.requiresBitangent > 0)
                {
                    vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
                    vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
                    pixelShader.AppendLine("float3 {0} = IN.{0};", name);
                    interpolatorIndex++;
                }
            }

            // -------------------------------------
            // Tangent

            if (combinedRequirements.requiresTangent > 0 || combinedRequirements.requiresBitangent > 0)
            {
                var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent);
                vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.tangent.xyz", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Vector));
                if (graphModelRequirements.requiresTangent > 0 || graphModelRequirements.requiresBitangent > 0)
                {
                    vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
                    vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
                    pixelShader.AppendLine("float3 {0} = IN.{0};", name);
                    interpolatorIndex++;
                }
            }

            // -------------------------------------
            // Bitangent

            if (combinedRequirements.requiresBitangent > 0)
            {
                var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent);
                vertexShader.AppendLine("float3 {0} = cross({1}, {2}.xyz) * {3};",
                                        name,
                                        preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal),
                                        preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent),
                                        "v.tangent.w");
                if (graphModelRequirements.requiresBitangent > 0)
                {
                    vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
                    vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
                    pixelShader.AppendLine("float3 {0} = IN.{0};", name);
                    interpolatorIndex++;
                }
            }

            // -------------------------------------
            // View Direction

            if (combinedRequirements.requiresViewDir > 0)
            {
                var          name = preferredCoordinateSpace.ToVariableName(InterpolatorType.ViewDirection);
                const string worldSpaceViewDir     = "_WorldSpaceCameraPos.xyz - mul(GetObjectToWorldMatrix(), float4(v.vertex.xyz, 1.0)).xyz";
                var          preferredSpaceViewDir = ConvertBetweenSpace(worldSpaceViewDir, CoordinateSpace.World, preferredCoordinateSpace, InputType.Vector);
                vertexShader.AppendLine("float3 {0} = {1};", name, preferredSpaceViewDir);
                if (graphModelRequirements.requiresViewDir > 0)
                {
                    vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
                    vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
                    pixelShader.AppendLine("float3 {0} = IN.{0};", name);
                    interpolatorIndex++;
                }
            }

            // -------------------------------------
            // Tangent space transform matrix

            if (combinedRequirements.NeedsTangentSpace())
            {
                var tangent   = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent);
                var bitangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent);
                var normal    = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal);
                if (vertexRequirements.NeedsTangentSpace())
                {
                    vertexShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});",
                                            tangent, bitangent, normal);
                }
                if (graphModelRequirements.NeedsTangentSpace())
                {
                    pixelShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});",
                                           tangent, bitangent, normal);
                }
            }

            // -------------------------------------
            // Vertex Color

            if (combinedRequirements.requiresVertexColor)
            {
                var vertexColor = "v.color";
                vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.VertexColor, vertexColor);
                if (graphModelRequirements.requiresVertexColor)
                {
                    vertexOutputStruct.AppendLine("float4 {0} : COLOR;", ShaderGeneratorNames.VertexColor);
                    vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.VertexColor);
                    pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor);
                }
            }

            // -------------------------------------
            // Screen Position

            if (combinedRequirements.requiresScreenPosition)
            {
                var screenPosition = "ComputeScreenPos(mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), v.vertex)), _ProjectionParams.x)";
                vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.ScreenPosition, screenPosition);
                if (graphModelRequirements.requiresScreenPosition)
                {
                    vertexOutputStruct.AppendLine("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ScreenPosition, interpolatorIndex);
                    vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
                    pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition);
                    interpolatorIndex++;
                }
            }

            // -------------------------------------
            // UV

            foreach (var channel in combinedRequirements.requiresMeshUVs.Distinct())
            {
                vertexShader.AppendLine("float4 {0} = v.texcoord{1};", channel.GetUVName(), (int)channel);
            }
            foreach (var channel in graphModelRequirements.requiresMeshUVs.Distinct())
            {
                vertexOutputStruct.AppendLine("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString());
                vertexShaderOutputs.AppendLine("o.{0} = {0};", channel.GetUVName());
                pixelShader.AppendLine("float4 {0} = IN.{0};", channel.GetUVName());
                interpolatorIndex++;
            }

            // ----------------------------------------------------- //
            //                TRANSLATE NEEDED SPACES                //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Generate the space translations needed by the vertex description

            GenerateSpaceTranslations(vertexRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace,
                                      InputType.Normal, vertexShader, Dimension.Three);
            GenerateSpaceTranslations(vertexRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace,
                                      InputType.Vector, vertexShader, Dimension.Three);
            GenerateSpaceTranslations(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace,
                                      InputType.Vector, vertexShader, Dimension.Three);
            GenerateSpaceTranslations(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace,
                                      InputType.Vector, vertexShader, Dimension.Three);
            GenerateSpaceTranslations(vertexRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace,
                                      InputType.Position, vertexShader, Dimension.Three);

            // -------------------------------------
            // Generate the space translations needed by the surface description and model

            GenerateSpaceTranslations(graphModelRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace,
                                      InputType.Normal, pixelShader, Dimension.Three);
            GenerateSpaceTranslations(graphModelRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace,
                                      InputType.Vector, pixelShader, Dimension.Three);
            GenerateSpaceTranslations(graphModelRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace,
                                      InputType.Vector, pixelShader, Dimension.Three);
            GenerateSpaceTranslations(graphModelRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace,
                                      InputType.Vector, pixelShader, Dimension.Three);
            GenerateSpaceTranslations(graphModelRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace,
                                      InputType.Position, pixelShader, Dimension.Three);

            // ----------------------------------------------------- //
            //               START SURFACE DESCRIPTION               //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Copy the locally defined values into the surface description
            // structure using the requirements for ONLY the shader graph pixel stage
            // additional requirements have come from the lighting model
            // and are not needed in the shader graph

            {
                var replaceString = "surfaceInput.{0} = {0};";
                GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresNormal, InterpolatorType.Normal, pixelShaderSurfaceInputs, replaceString);
                GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresTangent, InterpolatorType.Tangent, pixelShaderSurfaceInputs, replaceString);
                GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresBitangent, InterpolatorType.BiTangent, pixelShaderSurfaceInputs, replaceString);
                GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresViewDir, InterpolatorType.ViewDirection, pixelShaderSurfaceInputs, replaceString);
                GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresPosition, InterpolatorType.Position, pixelShaderSurfaceInputs, replaceString);
            }

            if (pixelRequirements.requiresVertexColor)
            {
                pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.VertexColor);
            }

            if (pixelRequirements.requiresScreenPosition)
            {
                pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
            }

            if (pixelRequirements.requiresFaceSign)
            {
                pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.FaceSign);
            }

            foreach (var channel in pixelRequirements.requiresMeshUVs.Distinct())
            {
                pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.GetUVName(channel));
            }

            // ----------------------------------------------------- //
            //                START VERTEX DESCRIPTION               //
            // ----------------------------------------------------- //

            // -------------------------------------
            // Copy the locally defined values into the vertex description
            // structure using the requirements for ONLY the shader graph vertex stage
            // additional requirements have come from the lighting model
            // and are not needed in the shader graph

            {
                var replaceString = "vdi.{0} = {0};";
                GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexShaderDescriptionInputs, replaceString);
                GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexShaderDescriptionInputs, replaceString);
                GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexShaderDescriptionInputs, replaceString);
                GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexShaderDescriptionInputs, replaceString);
                GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexShaderDescriptionInputs, replaceString);
            }

            if (vertexRequirements.requiresVertexColor)
            {
                vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.VertexColor);
            }

            if (vertexRequirements.requiresScreenPosition)
            {
                vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
            }

            foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct())
            {
                vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", channel.GetUVName(), (int)channel);
            }
        }
Exemple #24
0
        // Node generations
        public virtual void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            var uvName = GetSlotValue(UVInputId, generationMode);

            //Sampler input slot
            var samplerSlot  = FindInputSlot <MaterialSlot>(SamplerInputId);
            var edgesSampler = owner.GetEdges(samplerSlot.slotReference);

            var lodSlot = GetSlotValue(LODInputId, generationMode);

            var id = GetSlotValue(TextureInputId, generationMode);

            // GLES2 does not always support LOD sampling
            sb.AppendLine("#if defined(SHADER_API_GLES) && (SHADER_TARGET < 30)");
            {
                sb.AppendLine("  $precision4 {0} = $precision4(0.0f, 0.0f, 0.0f, 1.0f);", GetVariableNameForSlot(OutputSlotRGBAId));
            }
            sb.AppendLine("#else");
            {
                var result = string.Format("  $precision4 {0} = SAMPLE_TEXTURE2D_LOD({1}.tex, {2}.samplerstate, {1}.GetTransformedUV({3}), {4});"
                                           , GetVariableNameForSlot(OutputSlotRGBAId)
                                           , id
                                           , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : id
                                           , uvName
                                           , lodSlot);

                sb.AppendLine(result);
            }
            sb.AppendLine("#endif");

            if (textureType == TextureType.Normal)
            {
                if (normalMapSpace == NormalMapSpace.Tangent)
                {
                    sb.AppendLine(string.Format("{0}.rgb = UnpackNormal({0});", GetVariableNameForSlot(OutputSlotRGBAId)));
                }
                else
                {
                    sb.AppendLine(string.Format("{0}.rgb = UnpackNormalRGB({0});", GetVariableNameForSlot(OutputSlotRGBAId)));
                }
            }

            sb.AppendLine(string.Format("$precision {0} = {1}.r;", GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId)));
            sb.AppendLine(string.Format("$precision {0} = {1}.g;", GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId)));
            sb.AppendLine(string.Format("$precision {0} = {1}.b;", GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId)));
            sb.AppendLine(string.Format("$precision {0} = {1}.a;", GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId)));
        }
Exemple #25
0
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            if (asset == null || hasError)
            {
                var outputSlots = new List <MaterialSlot>();
                GetOutputSlots(outputSlots);
                var outputPrecision = asset != null ? asset.outputPrecision : ConcretePrecision.Float;
                foreach (var slot in outputSlots)
                {
                    sb.AppendLine($"{slot.concreteValueType.ToShaderString(outputPrecision)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};");
                }

                return;
            }

            var inputVariableName = $"_{GetVariableNameForNode()}";

            GenerationUtils.GenerateSurfaceInputTransferCode(sb, asset.requirements, asset.inputStructName, inputVariableName);

            foreach (var outSlot in asset.outputs)
            {
                sb.AppendLine("{0} {1};", outSlot.concreteValueType.ToShaderString(asset.outputPrecision), GetVariableNameForSlot(outSlot.id));
            }

            var arguments = new List <string>();

            foreach (var prop in asset.inputs)
            {
                prop.ValidateConcretePrecision(asset.graphPrecision);
                var inSlotId = m_PropertyIds[m_PropertyGuids.IndexOf(prop.guid.ToString())];

                switch (prop)
                {
                case Texture2DShaderProperty texture2DProp:
                    arguments.Add(string.Format("TEXTURE2D_ARGS({0}, sampler{0}), {0}_TexelSize", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
                    break;

                case Texture2DArrayShaderProperty texture2DArrayProp:
                    arguments.Add(string.Format("TEXTURE2D_ARRAY_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
                    break;

                case Texture3DShaderProperty texture3DProp:
                    arguments.Add(string.Format("TEXTURE3D_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
                    break;

                case CubemapShaderProperty cubemapProp:
                    arguments.Add(string.Format("TEXTURECUBE_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
                    break;

                default:
                    arguments.Add(string.Format("{0}", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
                    break;
                }
            }

            // pass surface inputs through
            arguments.Add(inputVariableName);

            foreach (var outSlot in asset.outputs)
            {
                arguments.Add(GetVariableNameForSlot(outSlot.id));
            }

            foreach (var feedbackSlot in asset.vtFeedbackVariables)
            {
                string feedbackVar = GetVariableNameForNode() + "_" + feedbackSlot;
                sb.AppendLine("{0} {1};", ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Float), feedbackVar);
                arguments.Add(feedbackVar);
            }

            sb.AppendLine("{0}({1});", asset.functionName, arguments.Aggregate((current, next) => string.Format("{0}, {1}", current, next)));
        }
        // Node generations
        public virtual void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            sb.AppendLine("$precision3 {0}_UV = {1} * {2};", 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("$precision3 {0}_Blend = max(pow(abs({1}), {2}), 0);"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode)
                              , GetSlotValue(BlendInputId, generationMode));
                sb.AppendLine("{0}_Blend /= ({0}_Blend.x + {0}_Blend.y + {0}_Blend.z ).xxx;", GetVariableNameForNode());

                sb.AppendLine("$precision3 {0}_X = UnpackNormal(SAMPLE_TEXTURE2D({1}, {2}, {0}_UV.zy));"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id);

                sb.AppendLine("$precision3 {0}_Y = UnpackNormal(SAMPLE_TEXTURE2D({1}, {2}, {0}_UV.xz));"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id);

                sb.AppendLine("$precision3 {0}_Z = UnpackNormal(SAMPLE_TEXTURE2D({1}, {2}, {0}_UV.xy));"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id);

                sb.AppendLine("{0}_X = $precision3({0}_X.xy + {1}.zy, abs({0}_X.z) * {1}.x);"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode));

                sb.AppendLine("{0}_Y = $precision3({0}_Y.xy + {1}.xz, abs({0}_Y.z) * {1}.y);"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode));

                sb.AppendLine("{0}_Z = $precision3({0}_Z.xy + {1}.xy, abs({0}_Z.z) * {1}.z);"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode));

                sb.AppendLine("$precision4 {0} = $precision4(normalize({1}_X.zyx * {1}_Blend.x + {1}_Y.xzy * {1}_Blend.y + {1}_Z.xyz * {1}_Blend.z), 1);"
                              , GetVariableNameForSlot(OutputSlotId)
                              , GetVariableNameForNode());
                sb.AppendLine("$precision3x3 {0}_Transform = $precision3x3(IN.WorldSpaceTangent, IN.WorldSpaceBiTangent, IN.WorldSpaceNormal);", GetVariableNameForNode());
                sb.AppendLine("{0}.rgb = TransformWorldToTangent({0}.rgb, {1}_Transform);"
                              , GetVariableNameForSlot(OutputSlotId)
                              , GetVariableNameForNode());
                break;

            default:
                sb.AppendLine("$precision3 {0}_Blend = pow(abs({1}), {2});"
                              , GetVariableNameForNode()
                              , GetSlotValue(NormalInputId, generationMode)
                              , GetSlotValue(BlendInputId, generationMode));
                sb.AppendLine("{0}_Blend /= dot({0}_Blend, 1.0);", GetVariableNameForNode());
                sb.AppendLine("$precision4 {0}_X = SAMPLE_TEXTURE2D({1}, {2}, {0}_UV.zy);"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id);

                sb.AppendLine("$precision4 {0}_Y = SAMPLE_TEXTURE2D({1}, {2}, {0}_UV.xz);"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id);

                sb.AppendLine("$precision4 {0}_Z = SAMPLE_TEXTURE2D({1}, {2}, {0}_UV.xy);"
                              , GetVariableNameForNode()
                              , id
                              , edgesSampler.Any() ? GetSlotValue(SamplerInputId, generationMode) : "sampler" + id);

                sb.AppendLine("$precision4 {0} = {1}_X * {1}_Blend.x + {1}_Y * {1}_Blend.y + {1}_Z * {1}_Blend.z;"
                              , GetVariableNameForSlot(OutputSlotId)
                              , GetVariableNameForNode());
                break;
            }
        }
Exemple #27
0
 public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
 {
     sb.AppendLine(string.Format("$precision {0} = max(0, IN.{1});", GetVariableNameForSlot(OutputSlotId), ShaderGeneratorNames.FaceSign));
 }
Exemple #28
0
 public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
 {
     sb.AppendLine(string.Format("$precision4 {0} = IN.{1};", GetVariableNameForSlot(OutputSlotId), m_OutputChannel.GetUVName()));
 }
        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;");
            }
        }
Exemple #30
0
 public void GetDepthTest(ShaderStringBuilder builder)
 {
     builder.AppendLine("ZTest {0}", zTest);
 }