예제 #1
0
        private void CheckAsset(VisualEffectAsset asset)
        {
            VisualEffectResource resource = asset.GetResource();
            var graph = resource.GetOrCreateGraph();

            Assert.AreEqual(6, graph.GetNbChildren());

            Assert.AreEqual(1, graph[0].GetNbChildren());
            Assert.AreEqual(1, graph[1].GetNbChildren());
            Assert.AreEqual(1, graph[2].GetNbChildren());
            Assert.AreEqual(0, graph[3].GetNbChildren());
            Assert.AreEqual(0, graph[4].GetNbChildren());
            Assert.AreEqual(0, graph[5].GetNbChildren());

            Assert.IsNotNull((graph[0])[0]);
            Assert.IsNotNull((graph[1])[0]);
            Assert.IsNotNull((graph[2])[0]);

            Assert.AreEqual(VFXContextType.Init, ((VFXContext)(graph[0])).contextType);
            Assert.AreEqual(VFXContextType.Update, ((VFXContext)(graph[1])).contextType);
            Assert.AreEqual(VFXContextType.Output, ((VFXContext)(graph[2])).contextType);
            Assert.AreEqual(VFXContextType.Init, ((VFXContext)(graph[3])).contextType);
            Assert.AreEqual(VFXContextType.Output, ((VFXContext)(graph[4])).contextType);

            Assert.IsNotNull(graph[5] as Operator.Add);
        }
예제 #2
0
        public static VFXGraph MakeTemporaryGraph()
        {
            var    guid         = System.Guid.NewGuid().ToString();
            string tempFilePath = string.Format(tempFileFormat, guid);

            System.IO.Directory.CreateDirectory(tempBasePath);

            var asset = VisualEffectAssetEditorUtility.CreateNewAsset(tempFilePath);
            VisualEffectResource resource = asset.GetOrCreateResource(); // force resource creation
            VFXGraph             graph    = resource.GetOrCreateGraph();

            return(graph);
        }
예제 #3
0
        public static VFXGraph CopyTemporaryGraph(string path)
        {
            var    guid         = System.Guid.NewGuid().ToString();
            string tempFilePath = string.Format(tempFileFormat, guid);

            System.IO.Directory.CreateDirectory(tempBasePath);
            File.Copy(path, tempFilePath);

            AssetDatabase.ImportAsset(tempFilePath);
            var asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(tempFilePath);
            VisualEffectResource resource = asset.GetResource();
            var graph = resource.GetOrCreateGraph();

            return(graph);
        }
예제 #4
0
        private void InitAsset(VisualEffectAsset asset)
        {
            VisualEffectResource resource = asset.GetResource();
            var graph = resource.GetOrCreateGraph();

            graph.RemoveAllChildren();

            var init0   = ScriptableObject.CreateInstance <VFXBasicInitialize>();
            var update0 = ScriptableObject.CreateInstance <VFXBasicUpdate>();
            var output0 = ScriptableObject.CreateInstance <VFXPointOutput>();

            graph.AddChild(init0);
            graph.AddChild(update0);
            graph.AddChild(output0);

            init0.LinkTo(update0);
            update0.LinkTo(output0);

            var init1   = ScriptableObject.CreateInstance <VFXBasicInitialize>();
            var output1 = ScriptableObject.CreateInstance <VFXPointOutput>();

            init1.LinkTo(output1);

            graph.AddChild(init1);
            graph.AddChild(output1);

            // Add some block
            var block0 = ScriptableObject.CreateInstance <InitBlockTest>();
            var block1 = ScriptableObject.CreateInstance <UpdateBlockTest>();
            var block2 = ScriptableObject.CreateInstance <OutputBlockTest>();

            // Add some operator
            VFXOperator add = ScriptableObject.CreateInstance <Operator.Add>();

            init0.AddChild(block0);
            update0.AddChild(block1);
            output0.AddChild(block2);

            graph.AddChild(add);
        }
        private void ReadBasicOperators(VisualEffectAsset asset, bool spawnAbs, bool linkAbs)
        {
            VisualEffectResource resource = asset.GetResource();
            var graph = resource.GetOrCreateGraph();
            Assert.AreEqual(spawnAbs ? 2 : 1, graph.GetNbChildren());
            Assert.IsNotNull((Operator.Add)graph[0]);
            var add = (Operator.Add)graph[0];
            CheckIsolatedOperatorAdd(add);

            if (spawnAbs)
            {
                Assert.IsNotNull((Operator.Absolute)graph[1]);
                var abs = (Operator.Absolute)graph[1];
                CheckIsolatedOperatorAbs(abs);
                Assert.AreEqual(abs.position.x, 64.0f);
                Assert.AreEqual(abs.position.y, 64.0f);
                if (linkAbs)
                {
                    CheckConnectedAbs(abs);
                }
            }
        }
        private void WriteBasicOperators(VisualEffectAsset asset, bool spawnAbs, bool linkAbs)
        {
            var add = ScriptableObject.CreateInstance<Operator.Add>();
            VisualEffectResource resource = asset.GetResource();
            var graph = resource.GetOrCreateGraph();
            graph.AddChild(add);

            CheckIsolatedOperatorAdd(add);

            if (spawnAbs)
            {
                var abs = ScriptableObject.CreateInstance<Operator.Absolute>();
                abs.position = new Vector2(64.0f, 64.0f);
                graph.AddChild(abs);
                CheckIsolatedOperatorAbs(abs);
                if (linkAbs)
                {
                    abs.inputSlots[0].Link(add.outputSlots[0]);
                    CheckConnectedAbs(abs);
                }
            }
        }
예제 #7
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();

        bool enable = GUI.enabled; //Everything in external asset is disabled by default

        GUI.enabled = true;

        EditorGUI.BeginChangeCheck();
        EditorGUI.showMixedValue = resourceUpdateModeProperty.hasMultipleDifferentValues;
        VFXUpdateMode newUpdateMode = (VFXUpdateMode)EditorGUILayout.EnumPopup(EditorGUIUtility.TrTextContent("Update Mode"), (VFXUpdateMode)resourceUpdateModeProperty.intValue);

        if (EditorGUI.EndChangeCheck())
        {
            resourceUpdateModeProperty.intValue = (int)newUpdateMode;
            resourceObject.ApplyModifiedProperties();
        }

        EditorGUILayout.BeginHorizontal();
        EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
        EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags"));
        EditorGUI.BeginChangeCheck();
        int newOption = EditorGUILayout.Popup(Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue), k_CullingOptionsContents);

        if (EditorGUI.EndChangeCheck())
        {
            cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
            resourceObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();

        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            if (!prewarmDeltaTime.hasMultipleDifferentValues && !prewarmStepCount.hasMultipleDifferentValues)
            {
                var currentDeltaTime = prewarmDeltaTime.floatValue;
                var currentStepCount = prewarmStepCount.intValue;
                var currentTotalTime = currentDeltaTime * currentStepCount;
                EditorGUI.BeginChangeCheck();
                currentTotalTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Total Time"), currentTotalTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentStepCount = EditorGUILayout.IntField(EditorGUIUtility.TrTextContent("PreWarm Step Count"), currentStepCount);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0 && currentTotalTime != 0.0f)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime == 0.0f ? 0.0f : currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    prewarmStepCount.intValue   = currentStepCount;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentDeltaTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Delta Time"), currentDeltaTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentDeltaTime < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = currentDeltaTime = k_MinimalCommonDeltaTime;
                    }

                    if (currentDeltaTime > currentTotalTime)
                    {
                        currentTotalTime = currentDeltaTime;
                    }

                    if (currentTotalTime != 0.0f)
                    {
                        var candidateStepCount_A = Mathf.FloorToInt(currentTotalTime / currentDeltaTime);
                        var candidateStepCount_B = Mathf.RoundToInt(currentTotalTime / currentDeltaTime);

                        var totalTime_A = currentDeltaTime * candidateStepCount_A;
                        var totalTime_B = currentDeltaTime * candidateStepCount_B;

                        if (Mathf.Abs(totalTime_A - currentTotalTime) < Mathf.Abs(totalTime_B - currentTotalTime))
                        {
                            currentStepCount = candidateStepCount_A;
                        }
                        else
                        {
                            currentStepCount = candidateStepCount_B;
                        }

                        prewarmStepCount.intValue = currentStepCount;
                    }
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }
            }
            else
            {
                //Multi selection case, can't resolve total time easily
                EditorGUI.BeginChangeCheck();
                EditorGUI.showMixedValue = prewarmStepCount.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmStepCount, EditorGUIUtility.TrTextContent("PreWarm Step Count"));
                EditorGUI.showMixedValue = prewarmDeltaTime.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmDeltaTime, EditorGUIUtility.TrTextContent("PreWarm Delta Time"));
                if (EditorGUI.EndChangeCheck())
                {
                    if (prewarmDeltaTime.floatValue < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = k_MinimalCommonDeltaTime;
                    }
                    resourceObject.ApplyModifiedProperties();
                }
            }
        }

        if (initialEventName != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = initialEventName.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(initialEventName);
            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            VisualEffectAsset    asset    = (VisualEffectAsset)target;
            VisualEffectResource resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.sortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), false, false);

            var shaderSources = resource.shaderSources;

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var shader in objects)
            {
                if (shader is Shader || shader is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(shader.name, GUILayout.ExpandWidth(true));
                    int index = resource.GetShaderIndex(shader);
                    if (index >= 0 && index < shaderSources.Length)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization)
                        {
                            string externalPath = directory + shaderSources[index].name;
                            if (!shaderSources[index].compute)
                            {
                                externalPath = directory + shaderSources[index].name.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;
                            }
                            else
                            {
                                externalPath = directory + shaderSources[index].name + VFXExternalShaderProcessor.k_ShaderExt;
                            }

                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUILayout.Button("Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUILayout.Button("Externalize", GUILayout.Width(80)))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSources[index].name + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + shaderSources[index].source);
                                }
                            }
                        }

                        if (GUILayout.Button("Show Generated", GUILayout.Width(110)))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }
                    if (GUILayout.Button("Select", GUILayout.Width(50)))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }
예제 #8
0
    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        foreach (var assetPath in deletedAssets)
        {
            if (VisualEffectAssetModicationProcessor.HasVFXExtension(assetPath))
            {
                VisualEffectResource.DeleteAtPath(assetPath);
            }
        }

        if (!allowExternalization)
        {
            return;
        }
        HashSet <string> vfxToRefresh   = new HashSet <string>();
        HashSet <string> vfxToRecompile = new HashSet <string>(); // Recompile vfx if a shader is deleted to replace

        foreach (string assetPath in importedAssets.Concat(deletedAssets).Concat(movedAssets))
        {
            if (assetPath.EndsWith(k_ShaderExt))
            {
                string shaderDirectory = Path.GetDirectoryName(assetPath);
                string vfxName         = Path.GetFileName(shaderDirectory);
                string vfxPath         = Path.GetDirectoryName(shaderDirectory);

                if (Path.GetFileName(vfxPath) != k_ShaderDirectory)
                {
                    continue;
                }

                vfxPath = Path.GetDirectoryName(vfxPath) + "/" + vfxName + VisualEffectResource.Extension;

                if (deletedAssets.Contains(assetPath))
                {
                    vfxToRecompile.Add(vfxPath);
                }
                else
                {
                    vfxToRefresh.Add(vfxPath);
                }
            }
        }

        foreach (var assetPath in vfxToRecompile)
        {
            VisualEffectAsset asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(assetPath);
            if (asset == null)
            {
                continue;
            }

            // Force Recompilation to restore the previous shaders
            VisualEffectResource resource = asset.GetResource();
            if (resource == null)
            {
                continue;
            }
            resource.GetOrCreateGraph().SetExpressionGraphDirty();
            resource.GetOrCreateGraph().RecompileIfNeeded(false, true);
        }

        foreach (var assetPath in vfxToRefresh)
        {
            VisualEffectAsset asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(assetPath);
            if (asset == null)
            {
                return;
            }
            AssetDatabase.ImportAsset(assetPath);
        }
    }
예제 #9
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();

        GUI.enabled = AssetDatabase.IsOpenForEdit(this.target, StatusQueryOptions.UseCachedIfPossible);

        VFXUpdateMode initialUpdateMode          = (VFXUpdateMode)0;
        bool?         initialFixedDeltaTime      = null;
        bool?         initialProcessEveryFrame   = null;
        bool?         initialIgnoreGameTimeScale = null;

        if (resourceUpdateModeProperty.hasMultipleDifferentValues)
        {
            var resourceUpdateModeProperties = resourceUpdateModeProperty.serializedObject.targetObjects
                                               .Select(o => new SerializedObject(o)
                                                       .FindProperty(resourceUpdateModeProperty.propertyPath))
                                               .ToArray();  //N.B.: This will create garbage
            var allDeltaTime = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.DeltaTime) == VFXUpdateMode.DeltaTime)
                               .Distinct();
            var allProcessEveryFrame = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep)
                                       .Distinct();
            var allIgnoreScale = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.IgnoreTimeScale) == VFXUpdateMode.IgnoreTimeScale)
                                 .Distinct();
            if (allDeltaTime.Count() == 1)
            {
                initialFixedDeltaTime = !allDeltaTime.First();
            }
            if (allProcessEveryFrame.Count() == 1)
            {
                initialProcessEveryFrame = allProcessEveryFrame.First();
            }
            if (allIgnoreScale.Count() == 1)
            {
                initialIgnoreGameTimeScale = allIgnoreScale.First();
            }
        }
        else
        {
            initialUpdateMode          = (VFXUpdateMode)resourceUpdateModeProperty.intValue;
            initialFixedDeltaTime      = !((initialUpdateMode & VFXUpdateMode.DeltaTime) == VFXUpdateMode.DeltaTime);
            initialProcessEveryFrame   = (initialUpdateMode & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep;
            initialIgnoreGameTimeScale = (initialUpdateMode & VFXUpdateMode.IgnoreTimeScale) == VFXUpdateMode.IgnoreTimeScale;
        }

        EditorGUI.showMixedValue = !initialFixedDeltaTime.HasValue;
        var deltaTimeContent         = EditorGUIUtility.TrTextContent("Fixed Delta Time", "If enabled, use visual effect manager fixed delta time mode, otherwise, use the default Time.deltaTime.");
        var processEveryFrameContent = EditorGUIUtility.TrTextContent("Exact Fixed Time", "Only relevant when using Fixed Delta Time. When enabled, several updates can be processed per frame (e.g.: if a frame is 10ms and the fixed frame rate is set to 5 ms, the effect will update twice with a 5ms deltaTime instead of once with a 10ms deltaTime). This method is expensive and should only be used for high-end scenarios.");
        var ignoreTimeScaleContent   = EditorGUIUtility.TrTextContent("Ignore Time Scale", "When enabled, the computed visual effect delta time ignores the game Time Scale value (Play Rate is still applied).");

        EditorGUI.BeginChangeCheck();

        VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Update mode"), false, false);
        bool newFixedDeltaTime     = EditorGUILayout.Toggle(deltaTimeContent, initialFixedDeltaTime ?? false);
        bool newExactFixedTimeStep = false;

        EditorGUI.showMixedValue = !initialProcessEveryFrame.HasValue;
        EditorGUI.BeginDisabledGroup((!initialFixedDeltaTime.HasValue || !initialFixedDeltaTime.Value) && !resourceUpdateModeProperty.hasMultipleDifferentValues);

#if CASE_1289829_HAS_BEEN_FIXED
        newExactFixedTimeStep = EditorGUILayout.Toggle(processEveryFrameContent, initialProcessEveryFrame ?? false);
#endif

        EditorGUI.EndDisabledGroup();
        EditorGUI.showMixedValue = !initialIgnoreGameTimeScale.HasValue;
        bool newIgnoreTimeScale = EditorGUILayout.Toggle(ignoreTimeScaleContent, initialIgnoreGameTimeScale ?? false);

        if (EditorGUI.EndChangeCheck())
        {
            if (!resourceUpdateModeProperty.hasMultipleDifferentValues)
            {
                var newUpdateMode = (VFXUpdateMode)0;
                if (!newFixedDeltaTime)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.DeltaTime;
                }
                if (newExactFixedTimeStep)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.ExactFixedTimeStep;
                }
                if (newIgnoreTimeScale)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.IgnoreTimeScale;
                }

                resourceUpdateModeProperty.intValue = (int)newUpdateMode;
                resourceObject.ApplyModifiedProperties();
            }
            else
            {
                var resourceUpdateModeProperties = resourceUpdateModeProperty.serializedObject.targetObjects.Select(o => new SerializedObject(o).FindProperty(resourceUpdateModeProperty.propertyPath));
                foreach (var property in resourceUpdateModeProperties)
                {
                    var updateMode = (VFXUpdateMode)property.intValue;

                    if (initialFixedDeltaTime.HasValue)
                    {
                        if (!newFixedDeltaTime)
                        {
                            updateMode = updateMode | VFXUpdateMode.DeltaTime;
                        }
                        else
                        {
                            updateMode = updateMode & ~VFXUpdateMode.DeltaTime;
                        }
                    }
                    else
                    {
                        if (newFixedDeltaTime)
                        {
                            updateMode = updateMode & ~VFXUpdateMode.DeltaTime;
                        }
                    }

                    if (newExactFixedTimeStep)
                    {
                        updateMode = updateMode | VFXUpdateMode.ExactFixedTimeStep;
                    }
                    else if (initialProcessEveryFrame.HasValue)
                    {
                        updateMode = updateMode & ~VFXUpdateMode.ExactFixedTimeStep;
                    }

                    if (newIgnoreTimeScale)
                    {
                        updateMode = updateMode | VFXUpdateMode.IgnoreTimeScale;
                    }
                    else if (initialIgnoreGameTimeScale.HasValue)
                    {
                        updateMode = updateMode & ~VFXUpdateMode.IgnoreTimeScale;
                    }

                    property.intValue = (int)updateMode;
                    property.serializedObject.ApplyModifiedProperties();
                }
            }
        }

        EditorGUILayout.BeginHorizontal();
        EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
        EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags", "Specifies how the system recomputes its bounds and simulates when off-screen."));
        EditorGUI.BeginChangeCheck();
        int newOption = EditorGUILayout.Popup(Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue), k_CullingOptionsContents);
        if (EditorGUI.EndChangeCheck())
        {
            cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
            resourceObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();

        VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Initial state"), false, false);
        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            if (!prewarmDeltaTime.hasMultipleDifferentValues && !prewarmStepCount.hasMultipleDifferentValues)
            {
                var currentDeltaTime = prewarmDeltaTime.floatValue;
                var currentStepCount = prewarmStepCount.intValue;
                var currentTotalTime = currentDeltaTime * currentStepCount;
                EditorGUI.BeginChangeCheck();
                currentTotalTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Total Time", "Sets the time in seconds to advance the current effect to when it is initially played. "), currentTotalTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentStepCount = EditorGUILayout.IntField(EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to. "), currentStepCount);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0 && currentTotalTime != 0.0f)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime == 0.0f ? 0.0f : currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    prewarmStepCount.intValue   = currentStepCount;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentDeltaTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Delta Time", "Sets the time in seconds for each step to achieve the desired total prewarm time."), currentDeltaTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentDeltaTime < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = currentDeltaTime = k_MinimalCommonDeltaTime;
                    }

                    if (currentDeltaTime > currentTotalTime)
                    {
                        currentTotalTime = currentDeltaTime;
                    }

                    if (currentTotalTime != 0.0f)
                    {
                        var candidateStepCount_A = Mathf.FloorToInt(currentTotalTime / currentDeltaTime);
                        var candidateStepCount_B = Mathf.RoundToInt(currentTotalTime / currentDeltaTime);

                        var totalTime_A = currentDeltaTime * candidateStepCount_A;
                        var totalTime_B = currentDeltaTime * candidateStepCount_B;

                        if (Mathf.Abs(totalTime_A - currentTotalTime) < Mathf.Abs(totalTime_B - currentTotalTime))
                        {
                            currentStepCount = candidateStepCount_A;
                        }
                        else
                        {
                            currentStepCount = candidateStepCount_B;
                        }

                        prewarmStepCount.intValue = currentStepCount;
                    }
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }
            }
            else
            {
                //Multi selection case, can't resolve total time easily
                EditorGUI.BeginChangeCheck();
                EditorGUI.showMixedValue = prewarmStepCount.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmStepCount, EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to."));
                EditorGUI.showMixedValue = prewarmDeltaTime.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmDeltaTime, EditorGUIUtility.TrTextContent("PreWarm Delta Time", "Sets the time in seconds for each step to achieve the desired total prewarm time."));
                if (EditorGUI.EndChangeCheck())
                {
                    if (prewarmDeltaTime.floatValue < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = k_MinimalCommonDeltaTime;
                    }
                    resourceObject.ApplyModifiedProperties();
                }
            }
        }

        if (initialEventName != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = initialEventName.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(initialEventName, new GUIContent("Initial Event Name", "Sets the name of the event which triggers once the system is activated. Default: ‘OnPlay’."));
            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            VisualEffectAsset    asset    = (VisualEffectAsset)target;
            VisualEffectResource resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.sortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), false, false);

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var obj in objects)
            {
                if (obj is Material || obj is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    Rect r = GUILayoutUtility.GetRect(0, 18, GUILayout.ExpandWidth(true));

                    int buttonsWidth = VFXExternalShaderProcessor.allowExternalization ? 240 : 160;

                    int index = resource.GetShaderIndex(obj);

                    var shader = obj;
                    if (obj is Material) // Retrieve the shader from the material
                    {
                        shader = ((Material)(obj)).shader;
                    }
                    if (shader == null)
                    {
                        continue;
                    }

                    Rect labelR = r;
                    labelR.width -= buttonsWidth;
                    GUI.Label(labelR, shader.name);

                    if (index >= 0)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization && index < resource.GetShaderSourceCount())
                        {
                            string shaderSourceName = resource.GetShaderSourceName(index);
                            string externalPath     = directory + shaderSourceName;

                            externalPath = directory + shaderSourceName.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;

                            Rect buttonRect = r;
                            buttonRect.xMin  = labelR.xMax;
                            buttonRect.width = 80;
                            labelR.width    += 80;
                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUI.Button(buttonRect, "Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUI.Button(buttonRect, "Externalize"))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSourceName + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + resource.GetShaderSource(index));
                                }
                            }
                        }

                        Rect buttonR = r;
                        buttonR.xMin  = labelR.xMax;
                        buttonR.width = 110;
                        labelR.width += 110;
                        if (GUI.Button(buttonR, "Show Generated"))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }

                    Rect selectButtonR = r;
                    selectButtonR.xMin  = labelR.xMax;
                    selectButtonR.width = 50;
                    if (GUI.Button(selectButtonR, "Select"))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }
예제 #10
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();

        GUI.enabled = AssetDatabase.IsOpenForEdit(this.target, StatusQueryOptions.UseCachedIfPossible);

        EditorGUI.BeginChangeCheck();
        EditorGUI.showMixedValue = resourceUpdateModeProperty.hasMultipleDifferentValues;
        VFXUpdateMode newUpdateMode = (VFXUpdateMode)EditorGUILayout.EnumPopup(EditorGUIUtility.TrTextContent("Update Mode", "Specifies whether particles are updated using a fixed timestep (Fixed Delta Time), or in a frame-rate independent manner (Delta Time)."), (VFXUpdateMode)resourceUpdateModeProperty.intValue);

        if (EditorGUI.EndChangeCheck())
        {
            resourceUpdateModeProperty.intValue = (int)newUpdateMode;
            resourceObject.ApplyModifiedProperties();
        }

        EditorGUILayout.BeginHorizontal();
        EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
        EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags", "Specifies how the system recomputes its bounds and simulates when off-screen."));
        EditorGUI.BeginChangeCheck();
        int newOption = EditorGUILayout.Popup(Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue), k_CullingOptionsContents);

        if (EditorGUI.EndChangeCheck())
        {
            cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
            resourceObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();

        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            if (!prewarmDeltaTime.hasMultipleDifferentValues && !prewarmStepCount.hasMultipleDifferentValues)
            {
                var currentDeltaTime = prewarmDeltaTime.floatValue;
                var currentStepCount = prewarmStepCount.intValue;
                var currentTotalTime = currentDeltaTime * currentStepCount;
                EditorGUI.BeginChangeCheck();
                currentTotalTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Total Time", "Sets the time in seconds to advance the current effect to when it is initially played. "), currentTotalTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentStepCount = EditorGUILayout.IntField(EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to. "), currentStepCount);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0 && currentTotalTime != 0.0f)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime == 0.0f ? 0.0f : currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    prewarmStepCount.intValue   = currentStepCount;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentDeltaTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Delta Time", "Sets the time in seconds for each step to achieve the desired total prewarm time."), currentDeltaTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentDeltaTime < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = currentDeltaTime = k_MinimalCommonDeltaTime;
                    }

                    if (currentDeltaTime > currentTotalTime)
                    {
                        currentTotalTime = currentDeltaTime;
                    }

                    if (currentTotalTime != 0.0f)
                    {
                        var candidateStepCount_A = Mathf.FloorToInt(currentTotalTime / currentDeltaTime);
                        var candidateStepCount_B = Mathf.RoundToInt(currentTotalTime / currentDeltaTime);

                        var totalTime_A = currentDeltaTime * candidateStepCount_A;
                        var totalTime_B = currentDeltaTime * candidateStepCount_B;

                        if (Mathf.Abs(totalTime_A - currentTotalTime) < Mathf.Abs(totalTime_B - currentTotalTime))
                        {
                            currentStepCount = candidateStepCount_A;
                        }
                        else
                        {
                            currentStepCount = candidateStepCount_B;
                        }

                        prewarmStepCount.intValue = currentStepCount;
                    }
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }
            }
            else
            {
                //Multi selection case, can't resolve total time easily
                EditorGUI.BeginChangeCheck();
                EditorGUI.showMixedValue = prewarmStepCount.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmStepCount, EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to."));
                EditorGUI.showMixedValue = prewarmDeltaTime.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmDeltaTime, EditorGUIUtility.TrTextContent("PreWarm Delta Time", "Sets the time in seconds for each step to achieve the desired total prewarm time."));
                if (EditorGUI.EndChangeCheck())
                {
                    if (prewarmDeltaTime.floatValue < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = k_MinimalCommonDeltaTime;
                    }
                    resourceObject.ApplyModifiedProperties();
                }
            }
        }

        if (initialEventName != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = initialEventName.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(initialEventName, new GUIContent("Initial Event Name", "Sets the name of the event which triggers once the system is activated. Default: ‘OnPlay’."));
            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            VisualEffectAsset    asset    = (VisualEffectAsset)target;
            VisualEffectResource resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.sortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), false, false);

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var shader in objects)
            {
                if (shader is Shader || shader is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    Rect r = GUILayoutUtility.GetRect(0, 18, GUILayout.ExpandWidth(true));

                    int buttonsWidth = VFXExternalShaderProcessor.allowExternalization? 240:160;


                    Rect labelR = r;
                    labelR.width -= buttonsWidth;
                    GUI.Label(labelR, shader.name);
                    int index = resource.GetShaderIndex(shader);
                    if (index >= 0)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization && index < resource.GetShaderSourceCount())
                        {
                            string shaderSourceName = resource.GetShaderSourceName(index);
                            string externalPath     = directory + shaderSourceName;

                            externalPath = directory + shaderSourceName.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;

                            Rect buttonRect = r;
                            buttonRect.xMin  = labelR.xMax;
                            buttonRect.width = 80;
                            labelR.width    += 80;
                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUI.Button(buttonRect, "Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUI.Button(buttonRect, "Externalize"))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSourceName + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + resource.GetShaderSource(index));
                                }
                            }
                        }

                        Rect buttonR = r;
                        buttonR.xMin  = labelR.xMax;
                        buttonR.width = 110;
                        labelR.width += 110;
                        if (GUI.Button(buttonR, "Show Generated"))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }

                    Rect selectButtonR = r;
                    selectButtonR.xMin  = labelR.xMax;
                    selectButtonR.width = 50;
                    if (GUI.Button(selectButtonR, "Select"))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }
예제 #11
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();

        bool enable = GUI.enabled; //Everything in external asset is disabled by default

        GUI.enabled = true;

        EditorGUI.BeginChangeCheck();
        EditorGUI.showMixedValue = resourceUpdateModeProperty.hasMultipleDifferentValues;
        VFXUpdateMode newUpdateMode = (VFXUpdateMode)EditorGUILayout.EnumPopup(EditorGUIUtility.TrTextContent("Update Mode"), (VFXUpdateMode)resourceUpdateModeProperty.intValue);

        if (EditorGUI.EndChangeCheck())
        {
            resourceUpdateModeProperty.intValue = (int)newUpdateMode;
            resourceObject.ApplyModifiedProperties();
        }

        EditorGUILayout.BeginHorizontal();
        EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
        EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags"));
        EditorGUI.BeginChangeCheck();
        int newOption = EditorGUILayout.Popup(Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue), k_CullingOptionsContents);

        if (EditorGUI.EndChangeCheck())
        {
            cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
            resourceObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();

        bool needRecompile = false;

        EditorGUI.showMixedValue = motionVectorRenderModeProperty.hasMultipleDifferentValues;
        EditorGUI.BeginChangeCheck();
        bool motionVector = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Use Motion Vectors"), motionVectorRenderModeProperty.intValue == (int)MotionVectorGenerationMode.Object);

        if (EditorGUI.EndChangeCheck())
        {
            motionVectorRenderModeProperty.intValue = motionVector ? (int)MotionVectorGenerationMode.Object : (int)MotionVectorGenerationMode.Camera;
            resourceObject.ApplyModifiedProperties();
            needRecompile = true;
        }

        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = prewarmDeltaTime.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(prewarmDeltaTime);
            EditorGUI.showMixedValue = prewarmStepCount.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(prewarmStepCount);

            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (needRecompile)
        {
            foreach (VisualEffectResource resource in resourceObject.targetObjects)
            {
                VFXGraph graph = resource.GetOrCreateGraph() as VFXGraph;
                if (graph != null)
                {
                    graph.SetExpressionGraphDirty();
                    graph.RecompileIfNeeded();
                }
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            VisualEffectAsset    asset    = (VisualEffectAsset)target;
            VisualEffectResource resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.sortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), true, true, false, false);

            var shaderSources = resource.shaderSources;

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var shader in objects)
            {
                if (shader is Shader || shader is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(shader.name, GUILayout.ExpandWidth(true));
                    int index = resource.GetShaderIndex(shader);
                    if (index >= 0 && index < shaderSources.Length)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization)
                        {
                            string externalPath = directory + shaderSources[index].name;
                            if (!shaderSources[index].compute)
                            {
                                externalPath = directory + shaderSources[index].name.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;
                            }
                            else
                            {
                                externalPath = directory + shaderSources[index].name + VFXExternalShaderProcessor.k_ShaderExt;
                            }

                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUILayout.Button("Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUILayout.Button("Externalize", GUILayout.Width(80)))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSources[index].name + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + shaderSources[index].source);
                                }
                            }
                        }

                        if (GUILayout.Button("Show Generated", GUILayout.Width(110)))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }
                    if (GUILayout.Button("Select", GUILayout.Width(50)))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }
예제 #12
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();

        GUI.enabled = AssetDatabase.IsOpenForEdit(this.target, StatusQueryOptions.UseCachedIfPossible);

        VFXUpdateMode initialUpdateMode          = (VFXUpdateMode)0;
        bool?         initialFixedDeltaTime      = null;
        bool?         initialProcessEveryFrame   = null;
        bool?         initialIgnoreGameTimeScale = null;

        if (resourceUpdateModeProperty.hasMultipleDifferentValues)
        {
            var resourceUpdateModeProperties = resourceUpdateModeProperty.serializedObject.targetObjects
                                               .Select(o => new SerializedObject(o)
                                                       .FindProperty(resourceUpdateModeProperty.propertyPath))
                                               .ToArray();  //N.B.: This will create garbage
            var allDeltaTime = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.DeltaTime) == VFXUpdateMode.DeltaTime)
                               .Distinct();
            var allProcessEveryFrame = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep)
                                       .Distinct();
            var allIgnoreScale = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.IgnoreTimeScale) == VFXUpdateMode.IgnoreTimeScale)
                                 .Distinct();
            if (allDeltaTime.Count() == 1)
            {
                initialFixedDeltaTime = !allDeltaTime.First();
            }
            if (allProcessEveryFrame.Count() == 1)
            {
                initialProcessEveryFrame = allProcessEveryFrame.First();
            }
            if (allIgnoreScale.Count() == 1)
            {
                initialIgnoreGameTimeScale = allIgnoreScale.First();
            }
        }
        else
        {
            initialUpdateMode          = (VFXUpdateMode)resourceUpdateModeProperty.intValue;
            initialFixedDeltaTime      = !((initialUpdateMode & VFXUpdateMode.DeltaTime) == VFXUpdateMode.DeltaTime);
            initialProcessEveryFrame   = (initialUpdateMode & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep;
            initialIgnoreGameTimeScale = (initialUpdateMode & VFXUpdateMode.IgnoreTimeScale) == VFXUpdateMode.IgnoreTimeScale;
        }

        EditorGUI.showMixedValue = !initialFixedDeltaTime.HasValue;
        var deltaTimeContent         = EditorGUIUtility.TrTextContent("Fixed Delta Time", "If enabled, use visual effect manager fixed delta time mode, otherwise, use the default Time.deltaTime.");
        var processEveryFrameContent = EditorGUIUtility.TrTextContent("Exact Fixed Time", "Only relevant when using Fixed Delta Time. When enabled, several updates can be processed per frame (e.g.: if a frame is 10ms and the fixed frame rate is set to 5 ms, the effect will update twice with a 5ms deltaTime instead of once with a 10ms deltaTime). This method is expensive and should only be used for high-end scenarios.");
        var ignoreTimeScaleContent   = EditorGUIUtility.TrTextContent("Ignore Time Scale", "When enabled, the computed visual effect delta time ignores the game Time Scale value (Play Rate is still applied).");

        EditorGUI.BeginChangeCheck();

        VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Update mode"), false, false);
        bool newFixedDeltaTime     = EditorGUILayout.Toggle(deltaTimeContent, initialFixedDeltaTime ?? false);
        bool newExactFixedTimeStep = false;

        EditorGUI.showMixedValue = !initialProcessEveryFrame.HasValue;
        EditorGUI.BeginDisabledGroup((!initialFixedDeltaTime.HasValue || !initialFixedDeltaTime.Value) && !resourceUpdateModeProperty.hasMultipleDifferentValues);
        newExactFixedTimeStep = EditorGUILayout.Toggle(processEveryFrameContent, initialProcessEveryFrame ?? false);
        EditorGUI.EndDisabledGroup();
        EditorGUI.showMixedValue = !initialIgnoreGameTimeScale.HasValue;
        bool newIgnoreTimeScale = EditorGUILayout.Toggle(ignoreTimeScaleContent, initialIgnoreGameTimeScale ?? false);

        if (EditorGUI.EndChangeCheck())
        {
            if (!resourceUpdateModeProperty.hasMultipleDifferentValues)
            {
                var newUpdateMode = (VFXUpdateMode)0;
                if (!newFixedDeltaTime)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.DeltaTime;
                }
                if (newExactFixedTimeStep)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.ExactFixedTimeStep;
                }
                if (newIgnoreTimeScale)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.IgnoreTimeScale;
                }

                resourceUpdateModeProperty.intValue = (int)newUpdateMode;
                resourceObject.ApplyModifiedProperties();
            }
            else
            {
                var resourceUpdateModeProperties = resourceUpdateModeProperty.serializedObject.targetObjects.Select(o => new SerializedObject(o).FindProperty(resourceUpdateModeProperty.propertyPath));
                foreach (var property in resourceUpdateModeProperties)
                {
                    var updateMode = (VFXUpdateMode)property.intValue;

                    if (initialFixedDeltaTime.HasValue)
                    {
                        if (!newFixedDeltaTime)
                        {
                            updateMode = updateMode | VFXUpdateMode.DeltaTime;
                        }
                        else
                        {
                            updateMode = updateMode & ~VFXUpdateMode.DeltaTime;
                        }
                    }
                    else
                    {
                        if (newFixedDeltaTime)
                        {
                            updateMode = updateMode & ~VFXUpdateMode.DeltaTime;
                        }
                    }

                    if (newExactFixedTimeStep)
                    {
                        updateMode = updateMode | VFXUpdateMode.ExactFixedTimeStep;
                    }
                    else if (initialProcessEveryFrame.HasValue)
                    {
                        updateMode = updateMode & ~VFXUpdateMode.ExactFixedTimeStep;
                    }

                    if (newIgnoreTimeScale)
                    {
                        updateMode = updateMode | VFXUpdateMode.IgnoreTimeScale;
                    }
                    else if (initialIgnoreGameTimeScale.HasValue)
                    {
                        updateMode = updateMode & ~VFXUpdateMode.IgnoreTimeScale;
                    }

                    property.intValue = (int)updateMode;
                    property.serializedObject.ApplyModifiedProperties();
                }
            }
        }
        VisualEffectAsset    asset    = (VisualEffectAsset)target;
        VisualEffectResource resource = asset.GetResource();

        //The following should be working, and works for newly created systems, but fails for old systems,
        //due probably to incorrectly pasting the VFXData when creating them.
        // bool hasAutomaticBoundsSystems = resource.GetOrCreateGraph().children
        //     .OfType<VFXDataParticle>().Any(d => d.boundsMode == BoundsSettingMode.Automatic);

        bool hasAutomaticBoundsSystems = resource.GetOrCreateGraph().children
                                         .OfType <VFXBasicInitialize>().Any(d => (d.GetData() as VFXDataParticle).boundsMode == BoundsSettingMode.Automatic);

        using (new EditorGUI.DisabledScope(hasAutomaticBoundsSystems))
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
            string forceSimulateTooltip = hasAutomaticBoundsSystems
                ? " When using systems with Bounds Mode set to Automatic, this has to be set to Always recompute bounds and simulate."
                : "";
            EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags", "Specifies how the system recomputes its bounds and simulates when off-screen." + forceSimulateTooltip));
            EditorGUI.BeginChangeCheck();

            int newOption =
                EditorGUILayout.Popup(
                    Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue),
                    k_CullingOptionsContents);
            if (EditorGUI.EndChangeCheck())
            {
                cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
                resourceObject.ApplyModifiedProperties();
            }
        }

        EditorGUILayout.EndHorizontal();

        VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Initial state"), false, false);
        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            DisplayPrewarmInspectorGUI(resourceObject, prewarmDeltaTime, prewarmStepCount);
        }

        if (initialEventName != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = initialEventName.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(initialEventName, new GUIContent("Initial Event Name", "Sets the name of the event which triggers once the system is activated. Default: ‘OnPlay’."));
            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            asset    = (VisualEffectAsset)target;
            resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.vfxSystemSortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), false, false);

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var obj in objects)
            {
                if (obj is Material || obj is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    Rect r = GUILayoutUtility.GetRect(0, 18, GUILayout.ExpandWidth(true));

                    int buttonsWidth = VFXExternalShaderProcessor.allowExternalization ? 240 : 160;

                    int index = resource.GetShaderIndex(obj);

                    var shader = obj;
                    if (obj is Material) // Retrieve the shader from the material
                    {
                        shader = ((Material)(obj)).shader;
                    }
                    if (shader == null)
                    {
                        continue;
                    }

                    Rect labelR = r;
                    labelR.width -= buttonsWidth;
                    GUI.Label(labelR, shader.name.Replace('\n', ' '));

                    if (index >= 0)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization && index < resource.GetShaderSourceCount())
                        {
                            string shaderSourceName = resource.GetShaderSourceName(index);
                            string externalPath     = directory + shaderSourceName;

                            externalPath = directory + shaderSourceName.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;

                            Rect buttonRect = r;
                            buttonRect.xMin  = labelR.xMax;
                            buttonRect.width = 80;
                            labelR.width    += 80;
                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUI.Button(buttonRect, "Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUI.Button(buttonRect, "Externalize"))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSourceName + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + resource.GetShaderSource(index));
                                }
                            }
                        }

                        Rect buttonR = r;
                        buttonR.xMin  = labelR.xMax;
                        buttonR.width = 110;
                        labelR.width += 110;
                        if (GUI.Button(buttonR, "Show Generated"))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }

                    Rect selectButtonR = r;
                    selectButtonR.xMin  = labelR.xMax;
                    selectButtonR.width = 50;
                    if (GUI.Button(selectButtonR, "Select"))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }