905 lines
32 KiB
C#
905 lines
32 KiB
C#
//#define USE_SHADER_AS_SUBASSET
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using UnityEditor;
|
|
using UnityEditor.VFX;
|
|
using UnityEngine;
|
|
using UnityEngine.VFX;
|
|
using UnityEngine.Profiling;
|
|
|
|
|
|
using UnityObject = UnityEngine.Object;
|
|
|
|
namespace UnityEditor.VFX
|
|
{
|
|
[InitializeOnLoad]
|
|
class VFXGraphPreprocessor : AssetPostprocessor
|
|
{
|
|
void OnPreprocessAsset()
|
|
{
|
|
bool isVFX = VisualEffectAssetModicationProcessor.HasVFXExtension(assetPath);
|
|
if (isVFX)
|
|
{
|
|
VisualEffectResource resource = VisualEffectResource.GetResourceAtPath(assetPath);
|
|
if (resource == null)
|
|
return;
|
|
VFXGraph graph = resource.graph as VFXGraph;
|
|
if (graph != null)
|
|
graph.SanitizeForImport();
|
|
else
|
|
Debug.LogError("VisualEffectGraphResource without graph");
|
|
}
|
|
}
|
|
|
|
static string[] OnAddResourceDependencies(string assetPath)
|
|
{
|
|
VisualEffectResource resource = VisualEffectResource.GetResourceAtPath(assetPath);
|
|
if (resource != null)
|
|
{
|
|
VFXGraph graph = resource.graph as VFXGraph;
|
|
if (graph != null)
|
|
return resource.GetOrCreateGraph().GetImportDependencies();
|
|
else
|
|
Debug.LogError("VisualEffectGraphResource without graph");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
static void OnCompileResource(VisualEffectResource resource)
|
|
{
|
|
if (resource != null)
|
|
{
|
|
VFXGraph graph = resource.graph as VFXGraph;
|
|
if (graph != null)
|
|
resource.GetOrCreateGraph().CompileForImport();
|
|
else
|
|
Debug.LogError("VisualEffectGraphResource without graph");
|
|
}
|
|
}
|
|
|
|
static VFXGraphPreprocessor()
|
|
{
|
|
EditorApplication.update += CheckCompilationVersion;
|
|
|
|
VisualEffectResource.onAddResourceDependencies = OnAddResourceDependencies;
|
|
VisualEffectResource.onCompileResource = OnCompileResource;
|
|
}
|
|
|
|
static void CheckCompilationVersion()
|
|
{
|
|
EditorApplication.update -= CheckCompilationVersion;
|
|
string[] allVisualEffectAssets = AssetDatabase.FindAssets("t:VisualEffectAsset");
|
|
|
|
UnityObject vfxmanager = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/VFXManager.asset").FirstOrDefault();
|
|
SerializedObject serializedVFXManager = new SerializedObject(vfxmanager);
|
|
var compiledVersionProperty = serializedVFXManager.FindProperty("m_CompiledVersion");
|
|
var runtimeVersionProperty = serializedVFXManager.FindProperty("m_RuntimeVersion");
|
|
|
|
if (compiledVersionProperty.intValue != VFXGraphCompiledData.compiledVersion || runtimeVersionProperty.intValue != VisualEffectAsset.currentRuntimeDataVersion)
|
|
{
|
|
compiledVersionProperty.intValue = (int)VFXGraphCompiledData.compiledVersion;
|
|
runtimeVersionProperty.intValue = (int)VisualEffectAsset.currentRuntimeDataVersion;
|
|
serializedVFXManager.ApplyModifiedProperties();
|
|
|
|
AssetDatabase.StartAssetEditing();
|
|
foreach (var guid in allVisualEffectAssets)
|
|
{
|
|
string path = AssetDatabase.GUIDToAssetPath(guid);
|
|
|
|
AssetDatabase.ImportAsset(path);
|
|
}
|
|
AssetDatabase.StopAssetEditing();
|
|
}
|
|
}
|
|
}
|
|
class VFXCacheManager : EditorWindow
|
|
{
|
|
private static List<VisualEffectObject> GetAllVisualEffectObjects()
|
|
{
|
|
var vfxObjects = new List<VisualEffectObject>();
|
|
var vfxObjectsGuid = AssetDatabase.FindAssets("t:VisualEffectObject");
|
|
foreach (var guid in vfxObjectsGuid)
|
|
{
|
|
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
|
var vfxObj = AssetDatabase.LoadAssetAtPath<VisualEffectObject>(assetPath);
|
|
if (vfxObj != null)
|
|
{
|
|
vfxObjects.Add(vfxObj);
|
|
}
|
|
}
|
|
return vfxObjects;
|
|
}
|
|
|
|
[MenuItem("Edit/Visual Effects/Rebuild And Save All Visual Effect Graphs", priority = 320)]
|
|
public static void Build()
|
|
{
|
|
var vfxObjects = GetAllVisualEffectObjects();
|
|
|
|
foreach (var vfxObj in vfxObjects)
|
|
{
|
|
if (VFXViewPreference.advancedLogs)
|
|
Debug.Log(string.Format("Recompile VFX asset: {0} ({1})", vfxObj, AssetDatabase.GetAssetPath(vfxObj)));
|
|
|
|
var resource = vfxObj.GetResource();
|
|
if (resource != null)
|
|
{
|
|
VFXGraph graph = resource.GetOrCreateGraph();
|
|
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(graph));
|
|
EditorUtility.SetDirty(resource);
|
|
}
|
|
}
|
|
|
|
VFXExpression.ClearCache();
|
|
AssetDatabase.SaveAssets();
|
|
}
|
|
}
|
|
|
|
class VisualEffectAssetModicationProcessor : UnityEditor.AssetModificationProcessor
|
|
{
|
|
public static bool HasVFXExtension(string filePath)
|
|
{
|
|
if (string.IsNullOrEmpty(filePath))
|
|
return false;
|
|
return filePath.EndsWith(VisualEffectResource.Extension)
|
|
|| filePath.EndsWith(VisualEffectSubgraphBlock.Extension)
|
|
|| filePath.EndsWith(VisualEffectSubgraphOperator.Extension);
|
|
}
|
|
|
|
static string[] OnWillSaveAssets(string[] paths)
|
|
{
|
|
Profiler.BeginSample("VisualEffectAssetModicationProcessor.OnWillSaveAssets");
|
|
foreach (string path in paths.Where(t => HasVFXExtension(t)))
|
|
{
|
|
var vfxResource = VisualEffectResource.GetResourceAtPath(path);
|
|
if (vfxResource != null)
|
|
{
|
|
vfxResource.GetOrCreateGraph().UpdateSubAssets();
|
|
vfxResource.WriteAsset(); // write asset as the AssetDatabase won't do it.
|
|
}
|
|
}
|
|
Profiler.EndSample();
|
|
return paths;
|
|
}
|
|
}
|
|
|
|
static class VisualEffectResourceExtensions
|
|
{
|
|
public static VFXGraph GetOrCreateGraph(this VisualEffectResource resource)
|
|
{
|
|
VFXGraph graph = resource.graph as VFXGraph;
|
|
|
|
if (graph == null)
|
|
{
|
|
string assetPath = AssetDatabase.GetAssetPath(resource);
|
|
AssetDatabase.ImportAsset(assetPath);
|
|
|
|
graph = resource.GetContents().OfType<VFXGraph>().FirstOrDefault();
|
|
}
|
|
|
|
if (graph == null)
|
|
{
|
|
graph = ScriptableObject.CreateInstance<VFXGraph>();
|
|
resource.graph = graph;
|
|
graph.hideFlags |= HideFlags.HideInHierarchy;
|
|
graph.visualEffectResource = resource;
|
|
// in this case we must update the subassets so that the graph is added to the resource dependencies
|
|
graph.UpdateSubAssets();
|
|
}
|
|
|
|
graph.visualEffectResource = resource;
|
|
return graph;
|
|
}
|
|
|
|
public static void UpdateSubAssets(this VisualEffectResource resource)
|
|
{
|
|
resource.GetOrCreateGraph().UpdateSubAssets();
|
|
}
|
|
|
|
public static bool IsAssetEditable(this VisualEffectResource resource)
|
|
{
|
|
return AssetDatabase.IsOpenForEdit(resource.asset, StatusQueryOptions.UseCachedIfPossible);
|
|
}
|
|
}
|
|
|
|
static class VisualEffectObjectExtensions
|
|
{
|
|
public static VisualEffectResource GetOrCreateResource(this VisualEffectObject asset)
|
|
{
|
|
string assetPath = AssetDatabase.GetAssetPath(asset);
|
|
VisualEffectResource resource = VisualEffectResource.GetResourceAtPath(assetPath);
|
|
|
|
if (resource == null && !string.IsNullOrEmpty(assetPath))
|
|
{
|
|
resource = new VisualEffectResource();
|
|
resource.SetAssetPath(assetPath);
|
|
}
|
|
return resource;
|
|
}
|
|
|
|
public static VisualEffectResource GetResource(this VisualEffectObject asset)
|
|
{
|
|
string assetPath = AssetDatabase.GetAssetPath(asset);
|
|
VisualEffectResource resource = VisualEffectResource.GetResourceAtPath(assetPath);
|
|
|
|
if (resource == null && !string.IsNullOrEmpty(assetPath))
|
|
throw new NullReferenceException($"VFX resource does not exist for this asset at path: {assetPath}");
|
|
|
|
return resource;
|
|
}
|
|
}
|
|
|
|
class VFXGraph : VFXModel
|
|
{
|
|
// Please add increment reason for each version below
|
|
// 1: Size refactor
|
|
// 2: Change some SetAttribute to spaceable slot
|
|
// 3: Remove Masked from blendMode in Outputs and split feature to UseAlphaClipping
|
|
// 4: TransformVector|Position|Direction & DistanceToSphere|Plane|Line have now spaceable outputs
|
|
// 5: Harmonized position blocks composition: PositionAABox was the only one with Overwrite position
|
|
// 6: Remove automatic strip orientation from quad strip context
|
|
public static readonly int CurrentVersion = 6;
|
|
|
|
public readonly VFXErrorManager errorManager = new VFXErrorManager();
|
|
|
|
|
|
public override void OnEnable()
|
|
{
|
|
base.OnEnable();
|
|
m_ExpressionGraphDirty = true;
|
|
}
|
|
|
|
public VisualEffectResource visualEffectResource
|
|
{
|
|
get
|
|
{
|
|
return m_Owner;
|
|
}
|
|
set
|
|
{
|
|
if (m_Owner != value)
|
|
{
|
|
m_Owner = value;
|
|
m_Owner.graph = this;
|
|
m_ExpressionGraphDirty = true;
|
|
}
|
|
}
|
|
}
|
|
[SerializeField]
|
|
VFXUI m_UIInfos;
|
|
|
|
public VFXUI UIInfos
|
|
{
|
|
get
|
|
{
|
|
if (m_UIInfos == null)
|
|
{
|
|
m_UIInfos = ScriptableObject.CreateInstance<VFXUI>();
|
|
}
|
|
return m_UIInfos;
|
|
}
|
|
}
|
|
|
|
public VFXParameterInfo[] m_ParameterInfo;
|
|
|
|
private VFXSystemNames m_SystemNames = new VFXSystemNames();
|
|
|
|
public VFXSystemNames systemNames { get { return m_SystemNames; } }
|
|
|
|
public void BuildParameterInfo()
|
|
{
|
|
m_ParameterInfo = VFXParameterInfo.BuildParameterInfo(this);
|
|
VisualEffectEditor.RepaintAllEditors();
|
|
}
|
|
|
|
public override bool AcceptChild(VFXModel model, int index = -1)
|
|
{
|
|
return !(model is VFXGraph); // Can hold any model except other VFXGraph
|
|
}
|
|
|
|
public object Backup()
|
|
{
|
|
Profiler.BeginSample("VFXGraph.Backup");
|
|
var dependencies = new HashSet<ScriptableObject>();
|
|
|
|
dependencies.Add(this);
|
|
CollectDependencies(dependencies);
|
|
|
|
var result = VFXMemorySerializer.StoreObjectsToByteArray(dependencies.ToArray(), CompressionLevel.Fastest);
|
|
|
|
Profiler.EndSample();
|
|
|
|
return result;
|
|
}
|
|
|
|
public void Restore(object str)
|
|
{
|
|
Profiler.BeginSample("VFXGraph.Restore");
|
|
var scriptableObject = VFXMemorySerializer.ExtractObjects(str as byte[], false);
|
|
|
|
Profiler.BeginSample("VFXGraph.Restore SendUnknownChange");
|
|
foreach (var model in scriptableObject.OfType<VFXModel>())
|
|
{
|
|
model.OnUnknownChange();
|
|
}
|
|
Profiler.EndSample();
|
|
Profiler.EndSample();
|
|
m_SystemNames.Sync(this);
|
|
m_ExpressionGraphDirty = true;
|
|
m_ExpressionValuesDirty = true;
|
|
m_DependentDirty = true;
|
|
}
|
|
|
|
public override void CollectDependencies(HashSet<ScriptableObject> objs, bool ownedOnly = true)
|
|
{
|
|
Profiler.BeginSample("VFXEditor.CollectDependencies");
|
|
try
|
|
{
|
|
if (m_UIInfos != null)
|
|
objs.Add(m_UIInfos);
|
|
base.CollectDependencies(objs, ownedOnly);
|
|
}
|
|
finally
|
|
{
|
|
Profiler.EndSample();
|
|
}
|
|
}
|
|
|
|
public void SanitizeGraph()
|
|
{
|
|
if (m_GraphSanitized)
|
|
return;
|
|
|
|
var objs = new HashSet<ScriptableObject>();
|
|
CollectDependencies(objs);
|
|
|
|
foreach (var model in objs.OfType<VFXModel>())
|
|
try
|
|
{
|
|
model.Sanitize(m_GraphVersion); // This can modify dependencies but newly created model are supposed safe so we dont care about retrieving new dependencies
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError(string.Format("Exception while sanitizing model: {0} of type {1}: {2} {3}", model.name, model.GetType(), e, e.StackTrace));
|
|
}
|
|
|
|
if (m_UIInfos != null)
|
|
try
|
|
{
|
|
m_UIInfos.Sanitize(this);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError(string.Format("Exception while sanitizing VFXUI: : {0} {1}", e, e.StackTrace));
|
|
}
|
|
|
|
systemNames.Sync(this);
|
|
|
|
|
|
int resourceCurrentVersion = 0;
|
|
// Stop using reflection after 2020.2;
|
|
FieldInfo info = typeof(VisualEffectResource).GetField("CurrentVersion", BindingFlags.Static | System.Reflection.BindingFlags.Public);
|
|
if (info != null)
|
|
resourceCurrentVersion = (int)info.GetValue(null);
|
|
|
|
if (m_ResourceVersion < resourceCurrentVersion) // Graph not up to date
|
|
{
|
|
if (m_ResourceVersion < 1) // Version before gradient interpreted as linear
|
|
{
|
|
foreach (var model in objs.OfType<VFXSlotGradient>())
|
|
{
|
|
Gradient value = (Gradient)model.value;
|
|
GradientColorKey[] keys = value.colorKeys;
|
|
|
|
for (int i = 0; i < keys.Length; ++i)
|
|
{
|
|
var colorKey = keys[i];
|
|
colorKey.color = colorKey.color.linear;
|
|
keys[i] = colorKey;
|
|
}
|
|
value.colorKeys = keys;
|
|
model.value = new Gradient();
|
|
model.value = value;
|
|
}
|
|
}
|
|
}
|
|
m_ResourceVersion = resourceCurrentVersion;
|
|
m_GraphSanitized = true;
|
|
m_GraphVersion = CurrentVersion;
|
|
|
|
#if !CASE_1289829_HAS_BEEN_FIXED
|
|
if (visualEffectResource != null && (visualEffectResource.updateMode & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep)
|
|
{
|
|
visualEffectResource.updateMode = visualEffectResource.updateMode & ~VFXUpdateMode.ExactFixedTimeStep;
|
|
Debug.Log("Sanitize : Exact Fixed Time has been automatically reset to false to avoid an unexpected behavior.");
|
|
}
|
|
#endif
|
|
|
|
UpdateSubAssets(); //Should not be necessary : force remove no more referenced object from asset
|
|
}
|
|
|
|
public void ClearCompileData()
|
|
{
|
|
m_CompiledData = null;
|
|
|
|
|
|
m_ExpressionValuesDirty = true;
|
|
}
|
|
|
|
[SerializeField]
|
|
List<string> m_ImportDependencies;
|
|
|
|
public void UpdateSubAssets()
|
|
{
|
|
if (visualEffectResource == null)
|
|
return;
|
|
Profiler.BeginSample("VFXEditor.UpdateSubAssets");
|
|
try
|
|
{
|
|
var currentObjects = new HashSet<ScriptableObject>();
|
|
currentObjects.Add(this);
|
|
CollectDependencies(currentObjects);
|
|
|
|
visualEffectResource.SetContents(currentObjects.Cast<UnityObject>().ToArray());
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError(e);
|
|
}
|
|
finally
|
|
{
|
|
Profiler.EndSample();
|
|
}
|
|
}
|
|
|
|
protected override void OnInvalidate(VFXModel model, VFXModel.InvalidationCause cause)
|
|
{
|
|
if (cause == VFXModel.InvalidationCause.kStructureChanged
|
|
|| cause == VFXModel.InvalidationCause.kSettingChanged
|
|
|| cause == VFXModel.InvalidationCause.kConnectionChanged)
|
|
m_SystemNames.Sync(this);
|
|
|
|
base.OnInvalidate(model, cause);
|
|
|
|
if (model is VFXParameter //Something changed directly on VFXParameter (e.g. exposed state boolean)
|
|
|| model is VFXSlot && (model as VFXSlot).owner is VFXParameter //Something changed on a slot owned by a VFXParameter (e.g. the default value)
|
|
|| cause == VFXModel.InvalidationCause.kStructureChanged //A VFXParameter could have been removed
|
|
)
|
|
{
|
|
BuildParameterInfo();
|
|
}
|
|
|
|
|
|
if (cause == VFXModel.InvalidationCause.kStructureChanged)
|
|
{
|
|
UpdateSubAssets();
|
|
if (model == this)
|
|
VFXSubgraphContext.CallOnGraphChanged(this);
|
|
|
|
m_DependentDirty = true;
|
|
}
|
|
|
|
if (cause == VFXModel.InvalidationCause.kSettingChanged && model is VFXParameter)
|
|
{
|
|
VFXSubgraphContext.CallOnGraphChanged(this);
|
|
m_DependentDirty = true;
|
|
}
|
|
|
|
if (cause != VFXModel.InvalidationCause.kExpressionInvalidated &&
|
|
cause != VFXModel.InvalidationCause.kExpressionGraphChanged &&
|
|
cause != VFXModel.InvalidationCause.kUIChangedTransient &&
|
|
(model.hideFlags & HideFlags.DontSave) == 0)
|
|
{
|
|
EditorUtility.SetDirty(this);
|
|
}
|
|
|
|
if (cause == VFXModel.InvalidationCause.kExpressionGraphChanged)
|
|
{
|
|
m_ExpressionGraphDirty = true;
|
|
m_DependentDirty = true;
|
|
}
|
|
|
|
if (cause == VFXModel.InvalidationCause.kParamChanged)
|
|
{
|
|
m_ExpressionValuesDirty = true;
|
|
m_DependentDirty = true;
|
|
}
|
|
}
|
|
|
|
public uint FindReducedExpressionIndexFromSlotCPU(VFXSlot slot)
|
|
{
|
|
RecompileIfNeeded(false, true);
|
|
return compiledData.FindReducedExpressionIndexFromSlotCPU(slot);
|
|
}
|
|
|
|
public void SetCompilationMode(VFXCompilationMode mode)
|
|
{
|
|
if (m_CompilationMode != mode)
|
|
{
|
|
m_CompilationMode = mode;
|
|
SetExpressionGraphDirty();
|
|
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(this));
|
|
}
|
|
}
|
|
|
|
public void SetForceShaderValidation(bool forceShaderValidation)
|
|
{
|
|
if (m_ForceShaderValidation != forceShaderValidation)
|
|
{
|
|
m_ForceShaderValidation = forceShaderValidation;
|
|
if (m_ForceShaderValidation)
|
|
{
|
|
SetExpressionGraphDirty();
|
|
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(this));
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsExpressionGraphDirty()
|
|
{
|
|
return m_ExpressionGraphDirty;
|
|
}
|
|
|
|
public void SetExpressionGraphDirty(bool dirty = true)
|
|
{
|
|
m_ExpressionGraphDirty = dirty;
|
|
m_DependentDirty = dirty;
|
|
}
|
|
|
|
public void SetExpressionValueDirty()
|
|
{
|
|
m_ExpressionValuesDirty = true;
|
|
m_DependentDirty = true;
|
|
}
|
|
|
|
public void BuildSubgraphDependencies()
|
|
{
|
|
if (m_SubgraphDependencies == null)
|
|
m_SubgraphDependencies = new List<VisualEffectObject>();
|
|
m_SubgraphDependencies.Clear();
|
|
|
|
HashSet<VisualEffectObject> explored = new HashSet<VisualEffectObject>();
|
|
RecurseBuildDependencies(explored, children);
|
|
}
|
|
|
|
void RecurseBuildDependencies(HashSet<VisualEffectObject> explored, IEnumerable<VFXModel> models)
|
|
{
|
|
foreach (var model in models)
|
|
{
|
|
if (model is VFXSubgraphContext)
|
|
{
|
|
var subgraphContext = model as VFXSubgraphContext;
|
|
|
|
if (subgraphContext.subgraph != null && !explored.Contains(subgraphContext.subgraph))
|
|
{
|
|
explored.Add(subgraphContext.subgraph);
|
|
m_SubgraphDependencies.Add(subgraphContext.subgraph);
|
|
RecurseBuildDependencies(explored, subgraphContext.subgraph.GetResource().GetOrCreateGraph().children);
|
|
}
|
|
}
|
|
else if (model is VFXSubgraphOperator)
|
|
{
|
|
var subgraphOperator = model as VFXSubgraphOperator;
|
|
|
|
if (subgraphOperator.subgraph != null && !explored.Contains(subgraphOperator.subgraph))
|
|
{
|
|
explored.Add(subgraphOperator.subgraph);
|
|
m_SubgraphDependencies.Add(subgraphOperator.subgraph);
|
|
RecurseBuildDependencies(explored, subgraphOperator.subgraph.GetResource().GetOrCreateGraph().children);
|
|
}
|
|
}
|
|
else if (model is VFXContext)
|
|
{
|
|
foreach (var block in (model as VFXContext).children)
|
|
{
|
|
if (block is VFXSubgraphBlock)
|
|
{
|
|
var subgraphBlock = block as VFXSubgraphBlock;
|
|
|
|
if (subgraphBlock.subgraph != null && !explored.Contains(subgraphBlock.subgraph))
|
|
{
|
|
explored.Add(subgraphBlock.subgraph);
|
|
m_SubgraphDependencies.Add(subgraphBlock.subgraph);
|
|
RecurseBuildDependencies(explored, subgraphBlock.subgraph.GetResource().GetOrCreateGraph().children);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RecurseSubgraphRecreateCopy(IEnumerable<VFXModel> children)
|
|
{
|
|
foreach (var child in children)
|
|
{
|
|
if (child is VFXSubgraphContext)
|
|
{
|
|
var subgraphContext = child as VFXSubgraphContext;
|
|
subgraphContext.RecreateCopy();
|
|
if (subgraphContext.subgraph != null)
|
|
{
|
|
RecurseSubgraphRecreateCopy(subgraphContext.subChildren);
|
|
}
|
|
}
|
|
else if (child is VFXContext)
|
|
{
|
|
foreach (var block in child.children)
|
|
{
|
|
if (block is VFXSubgraphBlock)
|
|
{
|
|
var subgraphBlock = block as VFXSubgraphBlock;
|
|
subgraphBlock.RecreateCopy();
|
|
if (subgraphBlock.subgraph != null)
|
|
RecurseSubgraphRecreateCopy(subgraphBlock.subChildren);
|
|
}
|
|
}
|
|
}
|
|
else if (child is VFXSubgraphOperator operatorChild)
|
|
{
|
|
operatorChild.RecreateCopy();
|
|
if (operatorChild.ResyncSlots(true))
|
|
operatorChild.UpdateOutputExpressions();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SetFlattenedParentToSubblocks()
|
|
{
|
|
foreach (var child in children.OfType<VFXContext>())
|
|
foreach (var block in child.children.OfType<VFXSubgraphBlock>())
|
|
block.SetSubblocksFlattenedParent();
|
|
}
|
|
|
|
void RecurseSubgraphPatchInputExpression(IEnumerable<VFXModel> children)
|
|
{
|
|
foreach (var child in children)
|
|
{
|
|
if (child is VFXSubgraphContext)
|
|
{
|
|
var subgraphContext = child as VFXSubgraphContext;
|
|
subgraphContext.PatchInputExpressions();
|
|
}
|
|
else if (child is VFXContext)
|
|
{
|
|
foreach (var block in child.children)
|
|
{
|
|
if (block is VFXSubgraphBlock)
|
|
{
|
|
var subgraphBlock = block as VFXSubgraphBlock;
|
|
subgraphBlock.PatchInputExpressions();
|
|
}
|
|
}
|
|
}
|
|
else if (child is VFXSubgraphOperator operatorChild)
|
|
{
|
|
operatorChild.ResyncSlots(false);
|
|
operatorChild.UpdateOutputExpressions();
|
|
}
|
|
}
|
|
foreach (var child in children)
|
|
{
|
|
if (child is VFXSubgraphContext)
|
|
{
|
|
var subgraphContext = child as VFXSubgraphContext;
|
|
if (subgraphContext.subgraph != null && subgraphContext.subChildren != null)
|
|
RecurseSubgraphPatchInputExpression(subgraphContext.subChildren);
|
|
}
|
|
else if (child is VFXContext)
|
|
{
|
|
foreach (var block in child.children)
|
|
{
|
|
if (block is VFXSubgraphBlock)
|
|
{
|
|
var subgraphBlock = block as VFXSubgraphBlock;
|
|
if (subgraphBlock.subgraph != null && subgraphBlock.subChildren != null)
|
|
RecurseSubgraphPatchInputExpression(subgraphBlock.subChildren);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SubgraphDirty(VisualEffectObject subgraph)
|
|
{
|
|
if (m_SubgraphDependencies != null && m_SubgraphDependencies.Contains(subgraph))
|
|
{
|
|
PrepareSubgraphs();
|
|
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(this));
|
|
}
|
|
}
|
|
|
|
private void PrepareSubgraphs()
|
|
{
|
|
Profiler.BeginSample("PrepareSubgraphs");
|
|
RecurseSubgraphRecreateCopy(children);
|
|
SetFlattenedParentToSubblocks();
|
|
RecurseSubgraphPatchInputExpression(children);
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
IEnumerable<VFXGraph> GetAllGraphs<T>() where T : VisualEffectObject
|
|
{
|
|
var guids = AssetDatabase.FindAssets("t:" + typeof(T).Name);
|
|
|
|
foreach (var assetPath in guids.Select(t => AssetDatabase.GUIDToAssetPath(t)))
|
|
{
|
|
var asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);
|
|
if (asset != null)
|
|
{
|
|
var graph = asset.GetResource().GetOrCreateGraph();
|
|
yield return graph;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Explicit compile must be used if we want to force compilation even if a dependency is needed, which me must not do on a deleted library import.
|
|
public static bool explicitCompile { get; set; } = false;
|
|
|
|
|
|
public void SanitizeForImport()
|
|
{
|
|
if (!explicitCompile)
|
|
{
|
|
HashSet<int> dependentAsset = new HashSet<int>();
|
|
GetImportDependentAssets(dependentAsset);
|
|
|
|
foreach (var instanceID in dependentAsset)
|
|
{
|
|
if (instanceID != 0 && EditorUtility.InstanceIDToObject(instanceID) == null)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var child in children)
|
|
child.CheckGraphBeforeImport();
|
|
|
|
SanitizeGraph();
|
|
}
|
|
|
|
public void CompileForImport()
|
|
{
|
|
if (!GetResource().isSubgraph)
|
|
{
|
|
// Don't pursue the compile if one of the dependency is not yet loaded
|
|
// which happen at first import with .pcache
|
|
if (!explicitCompile)
|
|
{
|
|
HashSet<int> dependentAsset = new HashSet<int>();
|
|
GetImportDependentAssets(dependentAsset);
|
|
|
|
foreach (var instanceID in dependentAsset)
|
|
{
|
|
if (instanceID != 0 && EditorUtility.InstanceIDToObject(instanceID) == null)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// Graph must have been sanitized at this point by the VFXGraphPreprocessor.OnPreprocess
|
|
BuildSubgraphDependencies();
|
|
PrepareSubgraphs();
|
|
|
|
compiledData.Compile(m_CompilationMode, m_ForceShaderValidation);
|
|
}
|
|
m_ExpressionGraphDirty = false;
|
|
m_ExpressionValuesDirty = false;
|
|
}
|
|
|
|
public static VFXCompileErrorReporter compileReporter = null;
|
|
|
|
public void RecompileIfNeeded(bool preventRecompilation = false, bool preventDependencyRecompilation = false)
|
|
{
|
|
SanitizeGraph();
|
|
|
|
if (!GetResource().isSubgraph)
|
|
{
|
|
bool considerGraphDirty = m_ExpressionGraphDirty && !preventRecompilation;
|
|
if (considerGraphDirty)
|
|
{
|
|
BuildSubgraphDependencies();
|
|
PrepareSubgraphs();
|
|
|
|
compiledData.Compile(m_CompilationMode, m_ForceShaderValidation);
|
|
}
|
|
else if (m_ExpressionValuesDirty && !m_ExpressionGraphDirty)
|
|
{
|
|
compiledData.UpdateValues();
|
|
}
|
|
|
|
if (considerGraphDirty)
|
|
m_ExpressionGraphDirty = false;
|
|
m_ExpressionValuesDirty = false;
|
|
}
|
|
else if (m_ExpressionGraphDirty && !preventRecompilation)
|
|
{
|
|
BuildSubgraphDependencies();
|
|
PrepareSubgraphs();
|
|
m_ExpressionGraphDirty = false;
|
|
}
|
|
if (!preventDependencyRecompilation && m_DependentDirty)
|
|
{
|
|
var obj = GetResource().visualEffectObject;
|
|
foreach (var graph in GetAllGraphs<VisualEffectAsset>())
|
|
{
|
|
graph.SubgraphDirty(obj);
|
|
}
|
|
m_DependentDirty = false;
|
|
}
|
|
}
|
|
|
|
private VFXGraphCompiledData compiledData
|
|
{
|
|
get
|
|
{
|
|
if (m_CompiledData == null)
|
|
m_CompiledData = new VFXGraphCompiledData(this);
|
|
return m_CompiledData;
|
|
}
|
|
}
|
|
public int version { get { return m_GraphVersion; } }
|
|
|
|
[SerializeField]
|
|
private int m_GraphVersion = CurrentVersion;
|
|
|
|
[SerializeField]
|
|
private int m_ResourceVersion;
|
|
|
|
[NonSerialized]
|
|
private bool m_GraphSanitized = false;
|
|
[NonSerialized]
|
|
private bool m_ExpressionGraphDirty = true;
|
|
[NonSerialized]
|
|
private bool m_ExpressionValuesDirty = true;
|
|
[NonSerialized]
|
|
private bool m_DependentDirty = true;
|
|
|
|
[NonSerialized]
|
|
private VFXGraphCompiledData m_CompiledData;
|
|
private VFXCompilationMode m_CompilationMode = VFXCompilationMode.Runtime;
|
|
private bool m_ForceShaderValidation = false;
|
|
|
|
[NonSerialized]
|
|
public Action<VFXGraph> onRuntimeDataChanged;
|
|
|
|
[SerializeField]
|
|
private List<VisualEffectObject> m_SubgraphDependencies = new List<VisualEffectObject>();
|
|
|
|
[SerializeField]
|
|
private string m_CategoryPath;
|
|
|
|
public string categoryPath
|
|
{
|
|
get { return m_CategoryPath; }
|
|
set { m_CategoryPath = value; }//TODO invalidate cache here
|
|
}
|
|
|
|
public ReadOnlyCollection<VisualEffectObject> subgraphDependencies
|
|
{
|
|
get { return m_SubgraphDependencies.AsReadOnly(); }
|
|
}
|
|
|
|
public string[] GetImportDependencies()
|
|
{
|
|
visualEffectResource.ClearImportDependencies();
|
|
|
|
HashSet<int> dependentAsset = new HashSet<int>();
|
|
GetImportDependentAssets(dependentAsset);
|
|
|
|
foreach (var dep in dependentAsset)
|
|
{
|
|
if (dep != 0)
|
|
visualEffectResource.AddImportDependency(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(dep)));
|
|
}
|
|
|
|
return dependentAsset.Select(t => AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(t))).Distinct().ToArray();
|
|
}
|
|
|
|
private VisualEffectResource m_Owner;
|
|
}
|
|
}
|