IEnumerable <VFXParameter> GetSortedInputParameters() { var resource = m_Subgraph.GetResource(); if (resource != null) { var graph = resource.GetOrCreateGraph(); if (graph != null) { var UIInfos = graph.UIInfos; var categoriesOrder = UIInfos.categories; if (categoriesOrder == null) { categoriesOrder = new List <VFXUI.CategoryInfo>(); } return(GetParameters(t => InputPredicate(t)).OrderBy(t => categoriesOrder.FindIndex(u => u.name == t.category)).ThenBy(t => t.order)); } else { Debug.LogError("Can't find subgraph graph"); } } else { Debug.LogError("Cant't find subgraph resource"); } return(Enumerable.Empty <VFXParameter>()); }
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); }
VFXGraph MakeTemporaryGraph() { m_Asset = VisualEffectResource.CreateNewAsset(tempFilePath); VisualEffectResource resource = m_Asset.GetResource(); // force resource creation VFXGraph graph = ScriptableObject.CreateInstance<VFXGraph>(); graph.visualEffectResource = resource; var window = EditorWindow.GetWindow<VFXViewWindow>(); window.Close(); window = EditorWindow.GetWindow<VFXViewWindow>(); m_ViewController = VFXViewController.GetController(m_Asset.GetResource(), true); m_View = window.graphView; m_View.controller = m_ViewController; return graph; }
public void CreateTestAsset(string name) { var filePath = string.Format(testAssetName, name); var directoryPath = Path.GetDirectoryName(filePath); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } m_Asset = VisualEffectResource.CreateNewAsset(filePath); VFXViewWindow window = EditorWindow.GetWindow <VFXViewWindow>(); window.Close(); window = EditorWindow.GetWindow <VFXViewWindow>(); m_ViewController = VFXViewController.GetController(m_Asset.GetResource(), true); window.graphView.controller = m_ViewController; }
public static void MigrateComponentsCurrentScnene() { HashSet <GameObject> prefabs = new HashSet <GameObject>(); FileVFXComponents components = FindComponentsInScene(prefabs); List <FileVFXComponents> prefabsInfos = new List <FileVFXComponents>(); foreach (var prefab in prefabs) { prefabsInfos.Add(FindComponentsInPrefab(prefab)); Debug.Log("Found prefab : " + AssetDatabase.GetAssetPath(prefab)); } foreach (var path in components.componentPaths.Values.Union(prefabsInfos.SelectMany(t => t.componentPaths.Values)).Distinct()) { VisualEffectAsset asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(path.assetPath); if (asset == null) { AssetDatabase.ImportAsset(path.assetPath); asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(path.assetPath); } if (asset != null) { var resource = asset.GetResource(); resource.ValidateAsset(); try { var graph = resource.GetOrCreateGraph(); graph.RecompileIfNeeded(); EditorUtility.SetDirty(graph); } catch (System.Exception e) { Debug.LogError("Couldn't resave vfx" + path.assetPath + " " + e.Message); } } } SetComponentsInScene(components); EditorSceneManager.SaveScene(EditorSceneManager.GetSceneByPath(components.path)); }
public override void Action(int instanceId, string pathName, string resourceFile) { try { var templateString = System.IO.File.ReadAllText(templatePath + templateAssetName); System.IO.File.WriteAllText(pathName, templateString); } catch (FileNotFoundException) { CreateNewAsset(pathName); } AssetDatabase.ImportAsset(pathName); VisualEffectAsset vfxAsset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(pathName); var graph = vfxAsset.GetResource().GetOrCreateGraph(); graph.SetExpressionGraphDirty(); graph.RecompileIfNeeded(); ProjectWindowUtil.FrameObjectInProjectWindow(vfxAsset.GetInstanceID()); }
public void CreateTestAsset() { var directoryPath = Path.GetDirectoryName(testAssetName); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } if (File.Exists(testAssetName)) { AssetDatabase.DeleteAsset(testAssetName); } VisualEffectAsset asset = VisualEffectResource.CreateNewAsset(testAssetName); VisualEffectResource resource = asset.GetResource(); // force resource creation m_ViewController = VFXViewController.GetController(resource); m_ViewController.useCount++; m_StartUndoGroupId = Undo.GetCurrentGroup(); }
public void CheckTypeMenu(SerializedProperty property, VFXPropertyBindingAttribute attribute, VisualEffectAsset asset) { GenericMenu menu = new GenericMenu(); var parameters = (asset.GetResource().graph as UnityEditor.VFX.VFXGraph).children.OfType <UnityEditor.VFX.VFXParameter>(); foreach (var param in parameters) { string typeName = param.type.ToString(); if (attribute.EditorTypes.Contains(typeName)) { MenuPropertySetName set = new MenuPropertySetName { property = property, value = param.exposedName }; menu.AddItem(new GUIContent(param.exposedName), false, SetFieldName, set); } } menu.ShowAsContext(); }
static void ResaveFolder(string dirPath) { foreach (var path in Directory.GetFiles(dirPath)) { if (Path.GetExtension(path) == ".vfx") { VisualEffectAsset asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(path); if (asset == null) { AssetDatabase.ImportAsset(path); asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(path); } if (asset == null) { Debug.LogError("Couldn't Import vfx" + path); } var resource = asset.GetResource(); if (resource != null) { resource.ValidateAsset(); try { var graph = resource.GetOrCreateGraph(); graph.RecompileIfNeeded(); EditorUtility.SetDirty(graph); } catch (System.Exception e) { Debug.LogError("Couldn't resave vfx" + path + " " + e.Message); } } } } foreach (var path in Directory.GetDirectories(dirPath)) { ResaveFolder(path); } }
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); }
public void Initial_Space_Supposed_To_Be_Same_As_Context() { //Cover also case 1163442, this behavior only exists in controller var directoryPath = Path.GetDirectoryName(testAssetName); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } if (File.Exists(testAssetName)) { AssetDatabase.DeleteAsset(testAssetName); } VisualEffectAsset asset = VisualEffectAssetEditorUtility.CreateNewAsset(testAssetName); var resource = asset.GetResource(); // force resource creation var viewController = VFXViewController.GetController(resource); viewController.useCount++; var startUndoGroupId = Undo.GetCurrentGroup(); var updateContext = ScriptableObject.CreateInstance <VFXBasicUpdate>(); updateContext.space = VFXCoordinateSpace.World; viewController.AddVFXModel(Vector2.zero, updateContext); viewController.ApplyChanges(); viewController.ForceReload(); var collision = ScriptableObject.CreateInstance <CollisionSphere>(); var contextController = viewController.allChildren.OfType <VFXContextController>().First(); contextController.AddBlock(0, collision, true); Assert.IsTrue(collision.inputSlots.Where(o => o.spaceable).All(o => o.space == VFXCoordinateSpace.World)); viewController.useCount--; Undo.RevertAllDownToGroup(startUndoGroupId); AssetDatabase.DeleteAsset(testAssetName); }
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); } } }
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); } } }
protected VisualEffectResource GetCurrentResource() { var objs = Selection.objects; VisualEffectResource selectedResource = null; if (objs != null && objs.Length == 1) { if (objs[0] is VisualEffectAsset) { VisualEffectAsset asset = objs[0] as VisualEffectAsset; selectedResource = asset.GetResource(); } else if (objs[0] is VisualEffectResource) { selectedResource = objs[0] as VisualEffectResource; } } if (selectedResource == null) { int instanceID = Selection.activeInstanceID; if (instanceID != 0) { string path = AssetDatabase.GetAssetPath(instanceID); if (path.EndsWith(".vfx")) { selectedResource = VisualEffectResource.GetResourceAtPath(path); } } } if (selectedResource == null && m_DisplayedResource != null) { selectedResource = m_DisplayedResource; } return(selectedResource); }
public void CheckTypeMenu(SerializedProperty property, VFXPropertyBindingAttribute attribute, VisualEffectAsset asset) { VFXGraph graph = null; if (asset != null) { var resource = asset.GetResource(); if (resource != null) //If VisualEffectGraph is store in asset bundle, we can't use this following code { graph = resource.graph as VFXGraph; } } if (graph == null) { return; } var menu = new GenericMenu(); var parameters = graph.children.OfType <UnityEditor.VFX.VFXParameter>(); foreach (var param in parameters) { string typeName = param.type.ToString(); if (attribute.EditorTypes.Contains(typeName)) { MenuPropertySetName set = new MenuPropertySetName { property = property, value = param.exposedName }; menu.AddItem(new GUIContent(param.exposedName), false, SetFieldName, set); } } menu.ShowAsContext(); }
public void CopyPasteEdges() { VisualEffectAsset asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>("Assets/AllTests/Editor/Tests/CopyPasteTest.vfx"); VFXViewController controller = VFXViewController.GetController(asset.GetResource(), true); VFXViewWindow window = EditorWindow.GetWindow <VFXViewWindow>(); VFXView view = window.graphView; view.controller = controller; view.ClearSelection(); var originalElements = view.Query().OfType <GraphElement>().ToList().OfType <ISelectable>().ToArray(); Assert.AreNotEqual(originalElements.Length, 0); foreach (var element in originalElements) { view.AddToSelection(element); } view.CopySelectionCallback(); view.controller = m_ViewController; view.PasteCallback(); m_ViewController.ApplyChanges(); VFXParameterUI[] parameters = view.Query().OfType <VFXParameterUI>().ToList().ToArray(); Assert.AreEqual(parameters.Length, 2); if (parameters[0].title == "Vector3") { var tmp = parameters[0]; parameters[0] = parameters[1]; parameters[1] = tmp; } VFXOperatorUI[] operators = view.Query().OfType <VFXOperatorUI>().ToList().ToArray(); Assert.AreEqual(operators.Length, 2); VFXContextUI[] contexts = view.Query().OfType <VFXContextUI>().ToList().ToArray(); Assert.AreEqual(contexts.Length, 2); if (contexts[0].controller.model is VFXBasicUpdate) { var tmp = contexts[0]; contexts[0] = contexts[1]; contexts[1] = tmp; } VFXDataEdge[] dataEdges = view.Query().OfType <VFXDataEdge>().ToList().ToArray(); Assert.AreEqual(dataEdges.Length, 4); Assert.IsNotNull(dataEdges.Where(t => t.output.GetFirstAncestorOfType <VFXNodeUI>() == parameters[1] && operators.Contains(t.input.GetFirstAncestorOfType <VFXOperatorUI>()) ).FirstOrDefault()); Assert.IsNotNull(dataEdges.Where(t => operators.Contains(t.input.GetFirstAncestorOfType <VFXOperatorUI>()) && operators.Contains(t.output.GetFirstAncestorOfType <VFXOperatorUI>()) && t.output.GetFirstAncestorOfType <VFXNodeUI>() != t.input.GetFirstAncestorOfType <VFXNodeUI>() ).FirstOrDefault()); Assert.IsNotNull(dataEdges.Where(t => t.output.GetFirstAncestorOfType <VFXNodeUI>() == parameters[0] && t.input.GetFirstAncestorOfType <VFXNodeUI>() == contexts[0] ).FirstOrDefault()); Assert.IsNotNull(dataEdges.Where(t => operators.Contains(t.output.GetFirstAncestorOfType <VFXNodeUI>()) && t.input.GetFirstAncestorOfType <VFXNodeUI>() == contexts[0].GetAllBlocks().First() ).FirstOrDefault()); VFXFlowEdge flowEdge = view.Query().OfType <VFXFlowEdge>(); Assert.IsNotNull(flowEdge); Assert.AreEqual(flowEdge.output.GetFirstAncestorOfType <VFXContextUI>(), contexts[1]); Assert.AreEqual(flowEdge.input.GetFirstAncestorOfType <VFXContextUI>(), contexts[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; }
void OnEnable() { VisualEffectAsset target = this.target as VisualEffectAsset; m_OutputContexts.Clear(); m_OutputContexts.AddRange(target.GetResource().GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.sortPriority)); m_ReorderableList = new ReorderableList(m_OutputContexts, typeof(IVFXSubRenderer)); m_ReorderableList.displayRemove = false; m_ReorderableList.displayAdd = false; m_ReorderableList.onReorderCallback = OnReorder; m_ReorderableList.drawHeaderCallback = DrawHeader; m_ReorderableList.drawElementCallback = DrawOutputContextItem; if (m_VisualEffectGO == null) { m_PreviewUtility = new PreviewRenderUtility(); m_PreviewUtility.camera.fieldOfView = 60.0f; m_PreviewUtility.camera.allowHDR = true; m_PreviewUtility.camera.allowMSAA = false; m_PreviewUtility.camera.farClipPlane = 10000.0f; m_PreviewUtility.ambientColor = new Color(.1f, .1f, .1f, 1.0f); m_PreviewUtility.lights[0].intensity = 1.4f; m_PreviewUtility.lights[0].transform.rotation = Quaternion.Euler(40f, 40f, 0); m_PreviewUtility.lights[1].intensity = 1.4f; m_VisualEffectGO = new GameObject("VisualEffect (Preview)"); m_VisualEffectGO.hideFlags = HideFlags.DontSave; m_VisualEffect = m_VisualEffectGO.AddComponent <VisualEffect>(); m_PreviewUtility.AddManagedGO(m_VisualEffectGO); m_VisualEffectGO.transform.localPosition = Vector3.zero; m_VisualEffectGO.transform.localRotation = Quaternion.identity; m_VisualEffectGO.transform.localScale = Vector3.one; m_VisualEffect.visualEffectAsset = target; m_CurrentBounds = new Bounds(Vector3.zero, Vector3.one); m_FrameCount = 0; m_Distance = 10; m_Angles = Vector3.forward; if (s_CubeWireFrame == null) { s_CubeWireFrame = new Mesh(); var vertices = new Vector3[] { new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(-0.5f, 0.5f, 0.5f), new Vector3(-0.5f, 0.5f, -0.5f), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, 0.5f, 0.5f), new Vector3(0.5f, 0.5f, -0.5f) }; var indices = new int[] { 0, 1, 0, 3, 0, 4, 6, 2, 6, 5, 6, 7, 1, 2, 1, 5, 3, 7, 3, 2, 4, 5, 4, 7 }; s_CubeWireFrame.vertices = vertices; s_CubeWireFrame.SetIndices(indices, MeshTopology.Lines, 0); } } resourceObject = new SerializedObject(targets.Cast <VisualEffectAsset>().Select(t => t.GetResource()).Where(t => t != null).ToArray()); resourceUpdateModeProperty = resourceObject.FindProperty("m_Infos.m_UpdateMode"); cullingFlagsProperty = resourceObject.FindProperty("m_Infos.m_CullingFlags"); motionVectorRenderModeProperty = resourceObject.FindProperty("m_Infos.m_RendererSettings.motionVectorGenerationMode"); prewarmDeltaTime = resourceObject.FindProperty("m_Infos.m_PreWarmDeltaTime"); prewarmStepCount = resourceObject.FindProperty("m_Infos.m_PreWarmStepCount"); initialEventName = resourceObject.FindProperty("m_Infos.m_InitialEventName"); }
void OnPreprocessAsset() { if (!allowExternalization) { return; } if (assetPath.EndsWith(VisualEffectResource.Extension)) { string vfxName = Path.GetFileNameWithoutExtension(assetPath); string vfxDirectory = Path.GetDirectoryName(assetPath); string shaderDirectory = vfxDirectory + "/" + k_ShaderDirectory + "/" + vfxName; if (!Directory.Exists(shaderDirectory)) { return; } VisualEffectAsset asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(assetPath); if (asset == null) { return; } bool oneFound = false; VisualEffectResource resource = asset.GetResource(); if (resource == null) { return; } VFXShaderSourceDesc[] descs = resource.shaderSources; foreach (var shaderPath in Directory.GetFiles(shaderDirectory)) { if (shaderPath.EndsWith(k_ShaderExt)) { System.IO.StreamReader file = new System.IO.StreamReader(shaderPath); string shaderLine = file.ReadLine(); file.Close(); if (shaderLine == null || !shaderLine.StartsWith("//")) { continue; } string[] shaderParams = shaderLine.Split(','); string shaderName = shaderParams[0].Substring(2); int index; if (!int.TryParse(shaderParams[1], out index)) { continue; } if (index < 0 || index >= descs.Length) { continue; } if (descs[index].name != shaderName) { continue; } string shaderSource = File.ReadAllText(shaderPath); //remove the first two lines that where added when externalized shaderSource = shaderSource.Substring(shaderSource.IndexOf("\n", shaderSource.IndexOf("\n") + 1) + 1); descs[index].source = shaderSource; oneFound = true; } } if (oneFound) { resource.shaderSources = descs; } } }
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); } }
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; }
protected virtual void DrawParameters() { #if !WORKAROUND_TIMELINE if (s_FakeObjectCache == null) { s_FakeObjectCache = ScriptableObject.CreateInstance <FakeObject>(); s_FakeObjectSerializedCache = new SerializedObject(s_FakeObjectCache); } #endif var component = (VisualEffect)target; if (m_graph == null || m_asset != component.visualEffectAsset) { m_asset = component.visualEffectAsset; if (m_asset != null) { m_graph = m_asset.GetResource().GetOrCreateGraph(); } } GUI.enabled = true; if (m_graph != null) { if (m_graph.m_ParameterInfo == null) { m_graph.BuildParameterInfo(); } if (m_graph.m_ParameterInfo != null) { ShowHeader(Contents.headerParameters, false, false, false, false); var stack = new List <int>(); int currentCount = m_graph.m_ParameterInfo.Length; if (currentCount == 0) { GUILayout.Label("No Parameter exposed in the asset"); } bool ignoreUntilNextCat = false; foreach (var param in m_graph.m_ParameterInfo) { --currentCount; var parameter = param; if (parameter.descendantCount > 0) { stack.Add(currentCount); currentCount = parameter.descendantCount; } if (currentCount == 0 && stack.Count > 0) { do { currentCount = stack.Last(); stack.RemoveAt(stack.Count - 1); }while (currentCount == 0); } if (string.IsNullOrEmpty(parameter.sheetType)) { if (!string.IsNullOrEmpty(parameter.name)) { if (string.IsNullOrEmpty(parameter.realType)) // This is a category { bool wasIgnored = ignoreUntilNextCat; ignoreUntilNextCat = false; var nameContent = GetGUIContent(parameter.name); bool prevState = EditorPrefs.GetBool("VFX-category-" + parameter.name, true); bool currentState = ShowHeader(nameContent, !wasIgnored, false, true, prevState); if (currentState != prevState) { EditorPrefs.SetBool("VFX-category-" + parameter.name, currentState); } if (!currentState) { ignoreUntilNextCat = true; } else { GUILayout.Space(Styles.headerBottomMargin); } } else if (!ignoreUntilNextCat) { EmptyLineControl(parameter.name, parameter.tooltip, stack.Count); } } } else if (!ignoreUntilNextCat) { //< Try find source property var sourceVfxField = m_VFXPropertySheet.FindPropertyRelative(parameter.sheetType + ".m_Array"); SerializedProperty sourceProperty = null; for (int i = 0; i < sourceVfxField.arraySize; ++i) { sourceProperty = sourceVfxField.GetArrayElementAtIndex(i); var nameProperty = sourceProperty.FindPropertyRelative("m_Name").stringValue; if (nameProperty == parameter.path) { break; } sourceProperty = null; } //< Prepare potential indirection bool wasNewProperty = false; bool wasNotOverriddenProperty = false; SerializedProperty actualDisplayedPropertyValue = null; SerializedProperty actualDisplayedPropertyOverridden = null; if (sourceProperty == null) { s_FakeObjectSerializedCache.Update(); var fakeField = s_FakeObjectSerializedCache.FindProperty("m_PropertySheet." + parameter.sheetType + ".m_Array"); fakeField.InsertArrayElementAtIndex(fakeField.arraySize); var newFakeEntry = fakeField.GetArrayElementAtIndex(fakeField.arraySize - 1); newFakeEntry.FindPropertyRelative("m_Name").stringValue = param.path; newFakeEntry.FindPropertyRelative("m_Overridden").boolValue = false; actualDisplayedPropertyOverridden = newFakeEntry.FindPropertyRelative("m_Overridden"); actualDisplayedPropertyValue = newFakeEntry.FindPropertyRelative("m_Value"); SetObjectValue(actualDisplayedPropertyValue, parameter.defaultValue.Get()); wasNewProperty = true; } else { actualDisplayedPropertyOverridden = sourceProperty.FindPropertyRelative("m_Overridden"); actualDisplayedPropertyValue = sourceProperty.FindPropertyRelative("m_Value"); if (!actualDisplayedPropertyOverridden.boolValue) { s_FakeObjectSerializedCache.Update(); actualDisplayedPropertyOverridden = s_FakeObjectSerializedCache.FindProperty(actualDisplayedPropertyOverridden.propertyPath); actualDisplayedPropertyValue = s_FakeObjectSerializedCache.FindProperty(actualDisplayedPropertyValue.propertyPath); SetObjectValue(actualDisplayedPropertyValue, parameter.defaultValue.Get()); wasNotOverriddenProperty = true; } } //< Actual display GUIContent nameContent = GetGUIContent(parameter.name, parameter.tooltip); EditorGUI.BeginChangeCheck(); DisplayProperty(ref parameter, nameContent, actualDisplayedPropertyOverridden, actualDisplayedPropertyValue, AnimationMode.IsPropertyAnimated(target, actualDisplayedPropertyValue.propertyPath)); if (EditorGUI.EndChangeCheck()) { if (wasNewProperty) { //We start editing a new exposed value which wasn't stored in this Visual Effect Component sourceVfxField.InsertArrayElementAtIndex(sourceVfxField.arraySize); var newEntry = sourceVfxField.GetArrayElementAtIndex(sourceVfxField.arraySize - 1); newEntry.FindPropertyRelative("m_Overridden").boolValue = actualDisplayedPropertyOverridden.boolValue; SetObjectValue(newEntry.FindPropertyRelative("m_Value"), GetObjectValue(actualDisplayedPropertyValue)); newEntry.FindPropertyRelative("m_Name").stringValue = param.path; } else if (wasNotOverriddenProperty) { if (actualDisplayedPropertyOverridden.boolValue) { //The check box has simply been toggle, we should not restore value from asset but simply change overridden state sourceProperty.FindPropertyRelative("m_Overridden").boolValue = true; } else { //The value has been directly changed, change overridden state and recopy new value SetObjectValue(sourceProperty.FindPropertyRelative("m_Value"), GetObjectValue(actualDisplayedPropertyValue)); sourceProperty.FindPropertyRelative("m_Overridden").boolValue = true; } } else //wasNewProperty == wasNotOverriddenProperty == false => there isn't any additionnal behavior needed, we are already using real serialized property { } serializedObject.ApplyModifiedProperties(); } } EditorGUI.indentLevel = stack.Count; } } } GUILayout.Space(1); // Space for the line if the last category is closed. }
protected virtual void DrawParameters() { #if !WORKAROUND_TIMELINE if (s_FakeObjectCache == null) { s_FakeObjectCache = ScriptableObject.CreateInstance <FakeObject>(); s_FakeObjectSerializedCache = new SerializedObject(s_FakeObjectCache); } #endif var component = (VisualEffect)target; if (m_graph == null || m_asset != component.visualEffectAsset) { m_asset = component.visualEffectAsset; if (m_asset != null) { m_graph = m_asset.GetResource().GetOrCreateGraph(); } } GUI.enabled = true; if (m_graph != null) { if (m_graph.m_ParameterInfo == null) { m_graph.BuildParameterInfo(); } if (m_graph.m_ParameterInfo != null) { ShowHeader(Contents.headerParameters, false, false, false, false); List <int> stack = new List <int>(); int currentCount = m_graph.m_ParameterInfo.Length; if (currentCount == 0) { GUILayout.Label("No Parameter exposed in the asset"); } bool ignoreUntilNextCat = false; foreach (var param in m_graph.m_ParameterInfo) { --currentCount; var parameter = param; if (parameter.descendantCount > 0) { stack.Add(currentCount); currentCount = parameter.descendantCount; } if (currentCount == 0 && stack.Count > 0) { do { currentCount = stack.Last(); stack.RemoveAt(stack.Count - 1); }while (currentCount == 0); } if (string.IsNullOrEmpty(parameter.sheetType)) { if (!string.IsNullOrEmpty(parameter.name)) { if (string.IsNullOrEmpty(parameter.realType)) // This is a category { bool wasIgnored = ignoreUntilNextCat; ignoreUntilNextCat = false; var nameContent = GetGUIContent(parameter.name); bool prevState = EditorPrefs.GetBool("VFX-category-" + parameter.name, true); bool currentState = ShowHeader(nameContent, !wasIgnored, false, true, prevState); if (currentState != prevState) { EditorPrefs.SetBool("VFX-category-" + parameter.name, currentState); } if (!currentState) { ignoreUntilNextCat = true; } else { GUILayout.Space(Styles.headerBottomMargin); } } else if (!ignoreUntilNextCat) { EmptyLineControl(parameter.name, parameter.tooltip, stack.Count); } } } else if (!ignoreUntilNextCat) { var vfxField = m_VFXPropertySheet.FindPropertyRelative(parameter.sheetType + ".m_Array"); SerializedProperty property = null; if (vfxField != null) { for (int i = 0; i < vfxField.arraySize; ++i) { property = vfxField.GetArrayElementAtIndex(i); var nameProperty = property.FindPropertyRelative("m_Name").stringValue; if (nameProperty == parameter.path) { break; } property = null; } } if (property != null) { SerializedProperty overrideProperty = property.FindPropertyRelative("m_Overridden"); property = property.FindPropertyRelative("m_Value"); string firstpropName = property.name; Color previousColor = GUI.color; var animated = AnimationMode.IsPropertyAnimated(target, property.propertyPath); if (animated) { GUI.color = AnimationMode.animatedPropertyColor; } DisplayProperty(ref parameter, overrideProperty, property); if (animated) { GUI.color = previousColor; } } } EditorGUI.indentLevel = stack.Count; } } } GUILayout.Space(1); // Space for the line if the last category is closed. }
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; }
public void RecreateCopy() { DetachFromOriginal(); if (m_Subgraph == null) { m_SubChildren = null; return; } var resource = m_Subgraph.GetResource(); if (resource == null) { m_SubChildren = null; return; } var graph = resource.GetOrCreateGraph(); HashSet <ScriptableObject> dependencies = new HashSet <ScriptableObject>(); graph.CollectDependencies(dependencies); var duplicated = VFXMemorySerializer.DuplicateObjects(dependencies.ToArray()); m_SubChildren = duplicated.OfType <VFXModel>().Where(t => t is VFXContext || t is VFXOperator || t is VFXParameter).ToArray(); foreach (var child in duplicated.Zip(dependencies, (a, b) => new { copy = a, original = b })) { child.copy.hideFlags = HideFlags.HideAndDontSave; if (child.copy is VFXSlot) { var original = child.original as VFXSlot; var copy = child.copy as VFXSlot; if (original.direction == VFXSlot.Direction.kInput || original.owner is VFXParameter) { m_OriginalToCopy[original] = copy; original.onInvalidateDelegate += OnOriginalSlotModified; } } } List <string> newInputFlowNames = new List <string>(); foreach (var basicEvent in m_SubChildren.OfType <VFXBasicEvent>()) { if (!newInputFlowNames.Contains(basicEvent.eventName)) { newInputFlowNames.Add(basicEvent.eventName); } } bool hasStart = false; bool hasStop = false; foreach (var initialize in m_SubChildren.OfType <VFXBasicSpawner>()) { if (!hasStart && initialize.inputFlowSlot[0].link.Count() == 0) { hasStart = true; } if (!hasStop && initialize.inputFlowSlot[1].link.Count() == 0) { hasStop = true; } } int directEventCount = newInputFlowNames.Count; foreach (var subContext in m_SubChildren.OfType <VFXSubgraphContext>()) { for (int i = 0; i < subContext.inputFlowCount; ++i) { string name = subContext.GetInputFlowName(i); switch (name) { case VisualEffectAsset.PlayEventName: hasStart = true; break; case VisualEffectAsset.StopEventName: hasStop = true; break; default: m_InputFlowNames.Add(name); break; } } } newInputFlowNames.Sort(0, directEventCount, Comparer <string> .Default); newInputFlowNames.Sort(directEventCount, newInputFlowNames.Count - directEventCount, Comparer <string> .Default); if (hasStop) { newInputFlowNames.Insert(0, VisualEffectAsset.StopEventName); } if (hasStart) { newInputFlowNames.Insert(0, VisualEffectAsset.PlayEventName); } if (!newInputFlowNames.SequenceEqual(m_InputFlowNames) || inputFlowSlot.Length != inputFlowCount) { var oldLinks = new Dictionary <string, List <VFXContextLink> >(); for (int i = 0; i < inputFlowSlot.Count() && i < m_InputFlowNames.Count; ++i) { oldLinks[GetInputFlowName(i)] = inputFlowSlot[i].link.ToList(); } m_InputFlowNames = newInputFlowNames; RefreshInputFlowSlots(); for (int i = 0; i < inputFlowSlot.Count(); ++i) { List <VFXContextLink> ctxSlot; if (oldLinks.TryGetValue(GetInputFlowName(i), out ctxSlot)) { foreach (var link in ctxSlot) { LinkFrom(link.context, link.slotIndex, i); } } } } SyncSlots(VFXSlot.Direction.kInput, true); }
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; }
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.BeginChangeCheck(); 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 (needRecompile) { foreach (VisualEffectResource resource in resourceObject.targetObjects) { VFXGraph graph = resource.GetOrCreateGraph() as VFXGraph; if (graph != null) { graph.SetExpressionGraphDirty(); graph.RecompileIfNeeded(); } } } if (!serializedObject.isEditingMultipleObjects) { VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), true, true, false, false); VisualEffectAsset asset = (VisualEffectAsset)target; VisualEffectResource resource = asset.GetResource(); 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; }