Exemplo n.º 1
0
        // TODO Remove that
        public static string SetSizesFromVector(VFXContext context, string vector, int nbComponents = 3)
        {
            if (nbComponents < 1 || nbComponents > 3)
            {
                throw new ArgumentException("NbComponents must be between 1 and 3");
            }

            var data = context.GetData();

            string res = string.Empty;

            if (data.IsCurrentAttributeWritten(VFXAttribute.ScaleX, context))
            {
                res += string.Format("scaleX = {0}.x / size;\n", vector);
            }
            if (nbComponents >= 2 && data.IsCurrentAttributeWritten(VFXAttribute.ScaleY, context))
            {
                res += string.Format("scaleY = {0}.y / size;\n", vector);
            }
            if (nbComponents >= 3 && data.IsCurrentAttributeWritten(VFXAttribute.ScaleZ, context))
            {
                res += string.Format("scaleZ = {0}.z / size;\n", vector);
            }

            return(res.TrimEnd(new[] { '\n' }));
        }
Exemplo n.º 2
0
        // A key difference between Material Shader and VFX Shader generation is how surface properties are provided. Material Shaders
        // simply provide properties via UnityPerMaterial cbuffer. VFX expects these same properties to be computed in the vertex
        // stage (because we must evaluate them with the VFX blocks), and packed with the interpolators for the fragment stage.
        static StructDescriptor AppendVFXInterpolator(StructDescriptor interpolator, VFXContext context, VFXContextCompiledData contextData)
        {
            var fields = interpolator.fields.ToList();

            var expressionToName = context.GetData().GetAttributes().ToDictionary(o => new VFXAttributeExpression(o.attrib) as VFXExpression, o => (new VFXAttributeExpression(o.attrib)).GetCodeString(null));

            expressionToName = expressionToName.Union(contextData.uniformMapper.expressionToCode).ToDictionary(s => s.Key, s => s.Value);

            var mainParameters = contextData.gpuMapper.CollectExpression(-1).ToArray();

            // Warning/TODO: FragmentParameters are created from the ShaderGraphVfxAsset.
            // We may ultimately need to move this handling of VFX Interpolators + SurfaceDescriptionFunction function signature directly into the SG Generator (since it knows about the exposed properties).
            foreach (string fragmentParameter in context.fragmentParameters)
            {
                var filteredNamedExpression = mainParameters.FirstOrDefault(o => fragmentParameter == o.name &&
                                                                            !(expressionToName.ContainsKey(o.exp) && expressionToName[o.exp] == o.name)); // if parameter already in the global scope, there's nothing to do

                if (filteredNamedExpression.exp != null)
                {
                    var type = VFXExpression.TypeToType(filteredNamedExpression.exp.valueType);

                    if (!kVFXShaderValueTypeMap.TryGetValue(type, out var shaderValueType))
                    {
                        continue;
                    }

                    // TODO: NoInterpolation only for non-strips.
                    fields.Add(new FieldDescriptor(HDStructFields.VaryingsMeshToPS.name, filteredNamedExpression.name, "", shaderValueType, subscriptOptions: StructFieldOptions.Static, interpolation: "nointerpolation"));
                }
            }

            // VFX Object Space Interpolators
            fields.Add(HDStructFields.VaryingsMeshToPS.worldToElement0);
            fields.Add(HDStructFields.VaryingsMeshToPS.worldToElement1);
            fields.Add(HDStructFields.VaryingsMeshToPS.worldToElement2);

            fields.Add(HDStructFields.VaryingsMeshToPS.elementToWorld0);
            fields.Add(HDStructFields.VaryingsMeshToPS.elementToWorld1);
            fields.Add(HDStructFields.VaryingsMeshToPS.elementToWorld2);

            interpolator.fields = fields.ToArray();
            return(interpolator);
        }
Exemplo n.º 3
0
        public static string GetSizeVector(VFXContext context, int nbComponents = 3)
        {
            var data = context.GetData();

            string sizeX = data.IsCurrentAttributeRead(VFXAttribute.SizeX, context) ? "sizeX" : VFXAttribute.kDefaultSize.ToString();
            string sizeY = nbComponents >= 2 && data.IsCurrentAttributeRead(VFXAttribute.SizeY, context) ? "sizeY" : "sizeX";
            string sizeZ = nbComponents >= 3 && data.IsCurrentAttributeRead(VFXAttribute.SizeZ, context) ? "sizeZ" : string.Format("min({0},{1})", sizeX, sizeY);

            switch (nbComponents)
            {
            case 1: return(sizeX);

            case 2: return(string.Format("float2({0},{1})", sizeX, sizeY));

            case 3: return(string.Format("float3({0},{1},{2})", sizeX, sizeY, sizeZ));

            default:
                throw new ArgumentException("NbComponents must be between 1 and 3");
            }
        }
Exemplo n.º 4
0
        static void PasteNodes(VFXViewController viewController, Vector2 center, Data copyData, ScriptableObject[] allSerializedObjects, VFXView view, VFXGroupNodeController groupNode)
        {
            var     graph       = viewController.graph;
            Vector2 pasteOffset = (copyData.bounds.width > 0 && copyData.bounds.height > 0) ? center - copyData.bounds.center : Vector2.zero;

            // look if pasting there will result in the first element beeing exactly on top of other
            while (true)
            {
                bool foundSamePosition = false;
                if (copyData.contexts != null && copyData.contexts.Length > 0)
                {
                    VFXContext firstContext = copyData.contexts[0];

                    foreach (var existingContext in viewController.graph.children.OfType <VFXContext>())
                    {
                        if ((firstContext.position + pasteOffset - existingContext.position).sqrMagnitude < 1)
                        {
                            foundSamePosition = true;
                            break;
                        }
                    }
                }
                else if (copyData.slotContainers != null && copyData.slotContainers.Length > 0)
                {
                    VFXModel firstContainer = copyData.slotContainers[0];

                    foreach (var existingSlotContainer in viewController.graph.children.Where(t => t is IVFXSlotContainer))
                    {
                        if ((firstContainer.position + pasteOffset - existingSlotContainer.position).sqrMagnitude < 1)
                        {
                            foundSamePosition = true;
                            break;
                        }
                    }
                }
                else
                {
                    VFXUI ui = allSerializedObjects.OfType <VFXUI>().First();

                    if (ui != null)
                    {
                        if (ui.stickyNoteInfos != null && ui.stickyNoteInfos.Length > 0)
                        {
                            foreach (var stickyNote in viewController.stickyNotes)
                            {
                                if ((ui.stickyNoteInfos[0].position.position + pasteOffset - stickyNote.position.position).sqrMagnitude < 1)
                                {
                                    foundSamePosition = true;
                                    break;
                                }
                            }
                        }
                        else if (ui.groupInfos != null && ui.groupInfos.Length > 0)
                        {
                            foreach (var gn in viewController.groupNodes)
                            {
                                if ((ui.groupInfos[0].position.position + pasteOffset - gn.position.position).sqrMagnitude < 1)
                                {
                                    foundSamePosition = true;
                                    break;
                                }
                            }
                        }
                    }
                }

                if (foundSamePosition)
                {
                    pasteOffset += Vector2.one * 30;
                }
                else
                {
                    break;
                }
            }


            if (copyData.contexts != null)
            {
                foreach (var slotContainer in copyData.contexts)
                {
                    var newContext = slotContainer;
                    newContext.position += pasteOffset;
                    ClearLinks(newContext);
                }
            }

            if (copyData.slotContainers != null)
            {
                foreach (var slotContainer in copyData.slotContainers)
                {
                    var newSlotContainer = slotContainer;
                    newSlotContainer.position += pasteOffset;
                    ClearLinks(newSlotContainer as IVFXSlotContainer);
                }
            }


            for (int i = 0; i < allSerializedObjects.Length; ++i)
            {
                ScriptableObject obj = allSerializedObjects[i];

                if (obj is VFXContext || obj is VFXOperator)
                {
                    graph.AddChild(obj as VFXModel);
                }
                else if (obj is VFXParameter)
                {
                    int paramIndex = System.Array.FindIndex(copyData.parameters, t => t.index == i);

                    VFXParameter existingParameter = graph.children.OfType <VFXParameter>().FirstOrDefault(t => t.GetInstanceID() == copyData.parameters[paramIndex].originalInstanceID);
                    if (existingParameter != null)
                    {
                        // The original parameter is from the current graph, add the nodes to the original
                        copyData.parameters[paramIndex].parameter       = existingParameter;
                        copyData.parameters[paramIndex].copiedParameter = obj as VFXParameter;

                        copyData.parameters[paramIndex].infoIndexOffset = existingParameter.nodes.Count;

                        foreach (var info in copyData.parameters[paramIndex].infos)
                        {
                            info.position += pasteOffset;
                        }

                        var oldIDs = copyData.parameters[paramIndex].infos.ToDictionary(t => t, t => t.id);

                        existingParameter.AddNodeRange(copyData.parameters[paramIndex].infos);

                        //keep track of new ids for groupnodes
                        copyData.parameters[paramIndex].idMap = copyData.parameters[paramIndex].infos.ToDictionary(t => oldIDs[t], t => t.id);
                    }
                    else
                    {
                        // The original parameter is from another graph : create the parameter in the other graph, but replace the infos with only the ones copied.
                        copyData.parameters[paramIndex].parameter = obj as VFXParameter;
                        copyData.parameters[paramIndex].parameter.SetNodes(copyData.parameters[paramIndex].infos);

                        graph.AddChild(obj as VFXModel);
                    }
                }
            }


            VFXUI copiedUI              = allSerializedObjects.OfType <VFXUI>().FirstOrDefault();
            int   firstCopiedGroup      = -1;
            int   firstCopiedStickyNote = -1;

            if (copiedUI != null)
            {
                VFXUI ui = viewController.graph.UIInfos;
                firstCopiedStickyNote = ui.stickyNoteInfos != null ? ui.stickyNoteInfos.Length : 0;

                if (copiedUI.groupInfos != null && copiedUI.groupInfos.Length > 0)
                {
                    if (ui.groupInfos == null)
                    {
                        ui.groupInfos = new VFXUI.GroupInfo[0];
                    }
                    firstCopiedGroup = ui.groupInfos.Length;

                    foreach (var groupInfos in copiedUI.groupInfos)
                    {
                        for (int i = 0; i < groupInfos.contents.Length; ++i)
                        {
                            // if we link the parameter node to an existing parameter instead of the copied parameter we have to patch the groupnode content to point the that parameter with the correct id.
                            if (groupInfos.contents[i].model is VFXParameter)
                            {
                                VFXParameter parameter = groupInfos.contents[i].model as VFXParameter;
                                var          paramInfo = copyData.parameters.FirstOrDefault(t => t.copiedParameter == parameter);
                                if (paramInfo.parameter != null) // parameter will not be null unless the struct returned is the default.
                                {
                                    groupInfos.contents[i].model = paramInfo.parameter;
                                    groupInfos.contents[i].id    = paramInfo.idMap[groupInfos.contents[i].id];
                                }
                            }
                            else if (groupInfos.contents[i].isStickyNote)
                            {
                                groupInfos.contents[i].id += firstCopiedStickyNote;
                            }
                        }
                    }

                    ui.groupInfos = ui.groupInfos.Concat(copiedUI.groupInfos.Select(t => new VFXUI.GroupInfo(t)
                    {
                        position = new Rect(t.position.position + pasteOffset, t.position.size)
                    })).ToArray();
                }
                if (copiedUI.stickyNoteInfos != null && copiedUI.stickyNoteInfos.Length > 0)
                {
                    if (ui.stickyNoteInfos == null)
                    {
                        ui.stickyNoteInfos = new VFXUI.StickyNoteInfo[0];
                    }
                    ui.stickyNoteInfos = ui.stickyNoteInfos.Concat(copiedUI.stickyNoteInfos.Select(t => new VFXUI.StickyNoteInfo(t)
                    {
                        position = new Rect(t.position.position + pasteOffset, t.position.size)
                    })).ToArray();
                }
            }

            CopyDataEdges(copyData, allSerializedObjects);


            if (copyData.flowEdges != null)
            {
                foreach (var flowEdge in copyData.flowEdges)
                {
                    VFXContext inputContext  = allSerializedObjects[flowEdge.input.contextIndex] as VFXContext;
                    VFXContext outputContext = allSerializedObjects[flowEdge.output.contextIndex] as VFXContext;

                    inputContext.LinkFrom(outputContext, flowEdge.input.flowIndex, flowEdge.output.flowIndex);
                }
            }

            foreach (var dataAndContexts in copyData.dataAndContexts)
            {
                VFXData data = allSerializedObjects[dataAndContexts.dataIndex] as VFXData;

                foreach (var contextIndex in dataAndContexts.contextsIndexes)
                {
                    VFXContext context = allSerializedObjects[contextIndex] as VFXContext;
                    data.CopySettings(context.GetData());
                }
            }

            // Create all ui based on model
            viewController.LightApplyChanges();

            if (view != null)
            {
                view.ClearSelection();

                var elements = view.graphElements.ToList();


                List <VFXNodeUI>    newSlotContainerUIs = new List <VFXNodeUI>();
                List <VFXContextUI> newContextUIs       = new List <VFXContextUI>();

                foreach (var slotContainer in allSerializedObjects.OfType <VFXContext>())
                {
                    VFXContextUI contextUI = elements.OfType <VFXContextUI>().FirstOrDefault(t => t.controller.model == slotContainer);
                    if (contextUI != null)
                    {
                        newSlotContainerUIs.Add(contextUI);
                        newSlotContainerUIs.AddRange(contextUI.GetAllBlocks().Cast <VFXNodeUI>());
                        newContextUIs.Add(contextUI);
                        view.AddToSelection(contextUI);
                    }
                }
                foreach (var slotContainer in allSerializedObjects.OfType <VFXOperator>())
                {
                    VFXOperatorUI slotContainerUI = elements.OfType <VFXOperatorUI>().FirstOrDefault(t => t.controller.model == slotContainer);
                    if (slotContainerUI != null)
                    {
                        newSlotContainerUIs.Add(slotContainerUI);
                        view.AddToSelection(slotContainerUI);
                    }
                }

                foreach (var param in copyData.parameters)
                {
                    foreach (var parameterUI in elements.OfType <VFXParameterUI>().Where(t => t.controller.model == param.parameter && param.parameter.nodes.IndexOf(t.controller.infos) >= param.infoIndexOffset))
                    {
                        newSlotContainerUIs.Add(parameterUI);
                        view.AddToSelection(parameterUI);
                    }
                }

                // Simply selected all data edge with the context or slot container, they can be no other than the copied ones
                foreach (var dataEdge in elements.OfType <VFXDataEdge>())
                {
                    if (newSlotContainerUIs.Contains(dataEdge.input.GetFirstAncestorOfType <VFXNodeUI>()))
                    {
                        view.AddToSelection(dataEdge);
                    }
                }
                // Simply selected all data edge with the context or slot container, they can be no other than the copied ones
                foreach (var flowEdge in elements.OfType <VFXFlowEdge>())
                {
                    if (newContextUIs.Contains(flowEdge.input.GetFirstAncestorOfType <VFXContextUI>()))
                    {
                        view.AddToSelection(flowEdge);
                    }
                }

                if (groupNode != null)
                {
                    foreach (var newSlotContainerUI in newSlotContainerUIs)
                    {
                        groupNode.AddNode(newSlotContainerUI.controller);
                    }
                }

                //Select all groups that are new
                if (firstCopiedGroup >= 0)
                {
                    foreach (var gn in elements.OfType <VFXGroupNode>())
                    {
                        if (gn.controller.index >= firstCopiedGroup)
                        {
                            view.AddToSelection(gn);
                        }
                    }
                }

                //Select all groups that are new
                if (firstCopiedStickyNote >= 0)
                {
                    foreach (var gn in elements.OfType <VFXStickyNote>())
                    {
                        if (gn.controller.index >= firstCopiedStickyNote)
                        {
                            view.AddToSelection(gn);
                        }
                    }
                }
            }
        }
Exemplo n.º 5
0
        /* fixformat ignore:end */

        public static StringBuilder ModifyShader(VFXContext context, StringBuilder source)
        {
            var blockFunctionNames = typeof(FluvioFXBlock)
                                     .Assembly
                                     .GetTypes()
                                     .Where(t =>
                                            (typeof(FluvioFXBlock).IsAssignableFrom(t) || typeof(ICollisionSettings).IsAssignableFrom(t)) &&
                                            !t.IsAbstract &&
                                            !t.IsInterface)
                                     .Select(t => t.Name);

            var shouldModify =
                context.activeChildrenWithImplicit.Any((b) =>
                                                       typeof(FluvioFXBlock).IsAssignableFrom(b.GetType()) ||
                                                       typeof(ICollisionSettings).IsAssignableFrom(b.GetType()));

            if (shouldModify)
            {
                var data    = context.GetData() as VFXDataParticle;
                var defines = FormattableString.Invariant($@"
// FluvioFX simulation constants
#define FLUVIO_EPSILON {FluvioFXSettings.kEpsilon}
#define FLUVIO_MAX_SQR_VELOCITY_CHANGE {FluvioFXSettings.kMaxSqrVelocityChange}
#define FLUVIO_MAX_BUCKET_COUNT {FluvioFXSettings.kMaxBucketCount}
#define FLUVIO_MAX_NEIGHBOR_COUNT {FluvioFXSettings.kMaxNeighborCount}
#define FLUVIO_AUTO_PARTICLE_SIZE_FACTOR {FluvioFXSettings.kAutoParticleSizeFactor}
#define FLUVIO_MAX_GRID_SIZE {(uint)Mathf.Pow(data?.capacity ?? 262144, 1.0f / 3.0f)}

");

                var result = defines + source.ToString().Replace("\r\n", "\n");

                // Special case: replacement
                var replacementBlock =
                    context
                    .activeChildrenWithImplicit
                    .FirstOrDefault((b) => !string.IsNullOrWhiteSpace((b as FluvioFXBlock)?.replacementKernel))
                    as FluvioFXBlock;

                if (replacementBlock != null)
                {
                    result  = result.Substring(0, result.LastIndexOf("[numthreads(NB_THREADS_PER_GROUP,1,1)]"));
                    result += $@"[numthreads(NB_THREADS_PER_GROUP,1,1)]
void CSMain(uint3 groupId          : SV_GroupID,
            uint3 groupThreadId    : SV_GroupThreadID,
			uint3 dispatchThreadId : SV_DispatchThreadID)
{{
{replacementBlock.replacementKernel}
}}";
                }

                foreach (var kvp in globalReplacements)
                {
                    var pattern     = kvp.Key;
                    var replacement = kvp.Value;
                    result = Regex.Replace(result, pattern, replacement);
                }

                foreach (var functionName in blockFunctionNames)
                {
                    foreach (var kvp in replacementFormat)
                    {
                        var pattern     = string.Format(kvp.Key, functionName);
                        var replacement = string.Format(kvp.Value, functionName);
                        result = Regex.Replace(result, pattern, replacement);
                    }
                }

                return(new StringBuilder(result));
            }

            return(source);
        }
Exemplo n.º 6
0
        static void GenerateVFXAdditionalCommands(VFXContext context, VFXContextCompiledData contextData,
                                                  out AdditionalCommandDescriptor loadAttributeDescriptor,
                                                  out AdditionalCommandDescriptor blockFunctionDescriptor,
                                                  out AdditionalCommandDescriptor blockCallFunctionDescriptor,
                                                  out AdditionalCommandDescriptor interpolantsGenerationDescriptor,
                                                  out AdditionalCommandDescriptor buildVFXFragInputsDescriptor,
                                                  out AdditionalCommandDescriptor pixelPropertiesAssignDescriptor,
                                                  out AdditionalCommandDescriptor defineSpaceDescriptor,
                                                  out AdditionalCommandDescriptor parameterBufferDescriptor,
                                                  out AdditionalCommandDescriptor additionalDefinesDescriptor,
                                                  out AdditionalCommandDescriptor loadPositionAttributeDescriptor,
                                                  out AdditionalCommandDescriptor loadCropFactorAttributesDescriptor,
                                                  out AdditionalCommandDescriptor loadTexcoordAttributesDescriptor,
                                                  out AdditionalCommandDescriptor vertexPropertiesGenerationDescriptor,
                                                  out AdditionalCommandDescriptor vertexPropertiesAssignDescriptor)
        {
            // TODO: Clean all of this up. Currently just an adapter between VFX Code Gen + SG Code Gen and *everything* has been stuffed here.

            // Load Attributes
            loadAttributeDescriptor = new AdditionalCommandDescriptor("VFXLoadAttribute", VFXCodeGenerator.GenerateLoadAttribute(".", context).ToString());

            // Graph Blocks
            VFXCodeGenerator.BuildContextBlocks(context, contextData, out var blockFunction, out var blockCallFunction);

            blockFunctionDescriptor     = new AdditionalCommandDescriptor("VFXGeneratedBlockFunction", blockFunction);
            blockCallFunctionDescriptor = new AdditionalCommandDescriptor("VFXProcessBlocks", blockCallFunction);

            // Vertex Input
            VFXCodeGenerator.BuildVertexProperties(context, contextData, out var vertexPropertiesGeneration);
            vertexPropertiesGenerationDescriptor = new AdditionalCommandDescriptor("VFXVertexPropertiesGeneration", vertexPropertiesGeneration);

            VFXCodeGenerator.BuildVertexPropertiesAssign(context, contextData, out var vertexPropertiesAssign);
            vertexPropertiesAssignDescriptor = new AdditionalCommandDescriptor("VFXVertexPropertiesAssign", vertexPropertiesAssign);

            // Interpolator
            VFXCodeGenerator.BuildInterpolatorBlocks(context, contextData, out var interpolatorsGeneration);
            interpolantsGenerationDescriptor = new AdditionalCommandDescriptor("VFXInterpolantsGeneration", interpolatorsGeneration);

            // Frag Inputs - Only VFX will know if frag inputs come from interpolator or the CBuffer.
            VFXCodeGenerator.BuildFragInputsGeneration(context, contextData, out var buildFragInputsGeneration);
            buildVFXFragInputsDescriptor = new AdditionalCommandDescriptor("VFXSetFragInputs", buildFragInputsGeneration);

            VFXCodeGenerator.BuildPixelPropertiesAssign(context, contextData, out var pixelPropertiesAssign);
            pixelPropertiesAssignDescriptor = new AdditionalCommandDescriptor("VFXPixelPropertiesAssign", pixelPropertiesAssign);

            // Define coordinate space
            var defineSpaceDescriptorContent = string.Empty;

            if (context.GetData() is ISpaceable)
            {
                var spaceable = context.GetData() as ISpaceable;
                defineSpaceDescriptorContent =
                    $"#define {(spaceable.space == VFXCoordinateSpace.World ? "VFX_WORLD_SPACE" : "VFX_LOCAL_SPACE")} 1";
            }
            defineSpaceDescriptor = new AdditionalCommandDescriptor("VFXDefineSpace", defineSpaceDescriptorContent);

            // Parameter Cbuffer
            VFXCodeGenerator.BuildParameterBuffer(contextData, out var parameterBuffer);
            parameterBufferDescriptor = new AdditionalCommandDescriptor("VFXParameterBuffer", parameterBuffer);

            // Defines & Headers - Not all are necessary, however some important ones are mixed in like indirect draw, strips, flipbook, particle strip info...
            ShaderStringBuilder additionalDefines = new ShaderStringBuilder();
            // TODO: Need to add defines for current/source usage (i.e. scale).

            var allCurrentAttributes = context.GetData().GetAttributes().Where(a =>
                                                                               (context.GetData().IsCurrentAttributeUsed(a.attrib, context)) ||
                                                                               (context.contextType == VFXContextType.Init && context.GetData().IsAttributeStored(a.attrib))); // In init, needs to declare all stored attributes for intialization

            var allSourceAttributes = context.GetData().GetAttributes().Where(a => (context.GetData().IsSourceAttributeUsed(a.attrib, context)));

            foreach (var attribute in allCurrentAttributes)
            {
                additionalDefines.AppendLine("#define VFX_USE_{0}_{1} 1", attribute.attrib.name.ToUpper(CultureInfo.InvariantCulture), "CURRENT");
            }
            foreach (var attribute in allSourceAttributes)
            {
                additionalDefines.AppendLine("#define VFX_USE_{0}_{1} 1", attribute.attrib.name.ToUpper(CultureInfo.InvariantCulture), "SOURCE");
            }
            foreach (var header in context.additionalDataHeaders)
            {
                additionalDefines.AppendLine(header);
            }
            foreach (var define in context.additionalDefines)
            {
                additionalDefines.AppendLine($"#define {define} 1");
            }
            additionalDefinesDescriptor = new AdditionalCommandDescriptor("VFXDefines", additionalDefines.ToString());

            // Load Position Attribute
            loadPositionAttributeDescriptor = new AdditionalCommandDescriptor("VFXLoadPositionAttribute", VFXCodeGenerator.GenerateLoadAttribute("position", context).ToString().ToString());

            // Load Crop Factor Attribute
            var mainParameters   = contextData.gpuMapper.CollectExpression(-1).ToArray();
            var expressionToName = context.GetData().GetAttributes().ToDictionary(o => new VFXAttributeExpression(o.attrib) as VFXExpression, o => (new VFXAttributeExpression(o.attrib)).GetCodeString(null));

            expressionToName = expressionToName.Union(contextData.uniformMapper.expressionToCode).ToDictionary(s => s.Key, s => s.Value);
            loadCropFactorAttributesDescriptor = new AdditionalCommandDescriptor("VFXLoadCropFactorParameter", VFXCodeGenerator.GenerateLoadParameter("cropFactor", mainParameters, expressionToName).ToString().ToString());
            loadTexcoordAttributesDescriptor   = new AdditionalCommandDescriptor("VFXLoadTexcoordParameter", VFXCodeGenerator.GenerateLoadParameter("texCoord", mainParameters, expressionToName).ToString().ToString());
        }