static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { 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 + ".vfx"; 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(); } foreach (var assetPath in vfxToRefresh) { VisualEffectAsset asset = AssetDatabase.LoadAssetAtPath <VisualEffectAsset>(assetPath); if (asset == null) { return; } AssetDatabase.ImportAsset(assetPath); } }
void OnPreprocessAsset() { if (!allowExternalization) { return; } if (assetPath.EndsWith(".vfx")) { 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; } } }
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; }
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 (!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; }
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(); 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 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; }
private VisualEffectAsset CreateAssetAtPath(string path) { return(VisualEffectResource.CreateNewAsset(path)); }