diff --git a/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphAsset.cs b/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphAsset.cs index b23fa9dc501..0ec7510f961 100644 --- a/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphAsset.cs +++ b/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphAsset.cs @@ -1,19 +1,149 @@ using System; using System.IO; using Unity.GraphToolsFoundation.Editor; - +using UnityEditor.ShaderGraph.Configuration; +using UnityEditor.ShaderGraph.GraphDelta; +using UnityEngine; namespace UnityEditor.ShaderGraph.GraphUI { + [Serializable] + internal class SerializableGraphHandler + { + [SerializeField] + string json = ""; + + [NonSerialized] + GraphHandler m_graph; + + // Provide a previously initialized graphHandler-- round-trip it for ownership. + public void Init(GraphHandler value) + { + json = value.ToSerializedFormat(); + var reg = ShaderGraphRegistry.Instance.Registry; // TODO: Singleton? + m_graph = GraphHandler.FromSerializedFormat(json, reg); + m_graph.ReconcretizeAll(); + } + + public void SaveGraph() + { + // Cloning node models (i.e. GTFs model of cloning a scriptable object, + // triggers a serialize on the cloned node before it has a graph handler reference + if (m_graph == null) + return; + json = m_graph.ToSerializedFormat(); + } + + public GraphHandler Graph => m_graph; + + public void OnEnable(bool reconcretize = true) + { + var reg = ShaderGraphRegistry.Instance.Registry; + m_graph = GraphHandler.FromSerializedFormat(json, reg); + if (reconcretize) + { + m_graph.ReconcretizeAll(); + } + } + } + class ShaderGraphAsset : GraphAsset { + // TODO: Do we want to keep this here or do we want a separate subgraph class? + public bool IsSubgraph { get; set; } + protected override Type GraphModelType => typeof(ShaderGraphModel); public ShaderGraphModel ShaderGraphModel => GraphModel as ShaderGraphModel; + // In theory we want to initialize the ShaderGraphModel after the CLDSModel, though any dependency there should be loose at best + public GraphHandler CLDSModel => graphHandlerBox.Graph; + + [SerializeField] + SerializableGraphHandler graphHandlerBox; + + [SerializeField] + LegacyTargetType m_TargetType; + + public LegacyTargetType TargetType => m_TargetType; + + string m_AssetPath; + + public static readonly string kBlackboardContextName = Registry.ResolveKey().Name; + + ShaderGraphAsset() + { + graphHandlerBox = new(); + m_AssetPath = String.Empty; + } + protected override void OnEnable() { + graphHandlerBox.OnEnable(); Name = Path.GetFileNameWithoutExtension(FilePath); base.OnEnable(); } + + public void Initialize(LegacyTargetType legacyTargetType) + { + m_TargetType = legacyTargetType; + var defaultRegistry = ShaderGraphRegistry.Instance.Registry; + GraphHandler graphHandler = new(defaultRegistry); + graphHandler.AddContextNode(kBlackboardContextName); + if (m_TargetType == LegacyTargetType.Blank) // blank shadergraph gets the fallback context node for output. + { + graphHandler.AddContextNode(Registry.ResolveKey()); + } + else // otherwise we are a URP graph. + { + // Conventional shadergraphs with targets will always have these context nodes. + graphHandler.AddContextNode("VertIn"); + graphHandler.AddContextNode("VertOut"); + graphHandler.AddContextNode("FragIn"); + graphHandler.AddContextNode(ShaderGraphAssetUtils.kMainEntryContextName); + + // Though we should be more procedural and be using this: to get the corresponding names, eg: + // CPGraphDataProvider.GatherProviderCPIO(target, out var descriptors); + } + + graphHandler.ReconcretizeAll(); + + graphHandlerBox.Init(graphHandler); + } + + public override string CreateFile(string path, bool overwriteIfExists) + { + if (string.IsNullOrEmpty(path)) + return path; + + if (!overwriteIfExists) + { + path = AssetDatabase.GenerateUniqueAssetPath(path); + } + + m_AssetPath = path; + + Directory.CreateDirectory(Path.GetDirectoryName(path) ?? ""); + if (File.Exists(path)) + AssetDatabase.DeleteAsset(path); + + var json = EditorJsonUtility.ToJson(this, true); + File.WriteAllText(path, json); + return path; + } + + public override GraphAsset Import() + { + return this; + } + + public override void Save() + { + m_AssetPath = m_AssetPath == string.Empty ? FilePath : m_AssetPath; + graphHandlerBox.SaveGraph(); + var json = EditorJsonUtility.ToJson(this, true); + File.WriteAllText(m_AssetPath, json); + AssetDatabase.ImportAsset(m_AssetPath); + EditorUtility.ClearDirty(this); + } } } diff --git a/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphModel.cs b/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphModel.cs index 56d8a5e5312..fa6d6f915ab 100644 --- a/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphModel.cs +++ b/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphModel.cs @@ -112,15 +112,15 @@ public Mesh mesh class ShaderGraphModel : GraphModel { [SerializeField] - private SerializableGraphHandler graphHandlerBox = new(); - [SerializeField] - private SerializableTargetSettings targetSettingsBox = new(); + private ShaderGraphAssetUtils.SerializableTargetSettings targetSettingsBox = new(); [SerializeField] private MainPreviewData mainPreviewData; [SerializeField] private bool isSubGraph = false; - internal GraphHandler GraphHandler => graphHandlerBox.Graph; + [NonSerialized] + GraphHandler m_GraphHandler; + internal GraphHandler GraphHandler => ((ShaderGraphAsset)Asset).CLDSModel; internal ShaderGraphRegistry RegistryInstance => ShaderGraphRegistry.Instance; internal List> Targets => targetSettingsBox.Targets; // TODO: Store the active editing target in the box? internal Target ActiveTarget => Targets.FirstOrDefault(); @@ -152,9 +152,17 @@ class ShaderGraphModel : GraphModel string m_ShaderCategory = "Shader Graphs (SG2)"; public string ShaderName => string.IsNullOrEmpty(m_ShaderCategory) ? Name : m_ShaderCategory + "/" + Name; - internal void Init(GraphHandler graph, bool isSubGraph, Target target) + // TODO: Not initialize this way, need to provide a more generic model context object with all necessary info. + internal void InitModelForNewAsset(bool isSubGraph, LegacyTargetType targetType = LegacyTargetType.Blank) { - graphHandlerBox.Init(graph); + var target = targetType switch + { + LegacyTargetType.Blank => null, + LegacyTargetType.URPLit => URPTargetUtils.ConfigureURPLit(GraphHandler), + LegacyTargetType.URPUnlit => URPTargetUtils.ConfigureURPUnlit(GraphHandler), + _ => throw new ArgumentOutOfRangeException("ShaderGraphTemplate.m_TargetType") + }; + this.isSubGraph = isSubGraph; if (!isSubGraph && target != null) { @@ -166,25 +174,41 @@ internal void Init(GraphHandler graph, bool isSubGraph, Target target) //vertNode.Position = new Vector2(0, -180); } - var outputNode = this.CreateGraphDataContextNode(ShaderGraphAssetUtils.kMainEntryContextName); - outputNode.Title = isSubGraph ? "Subgraph Outputs" : "Fragment Stage"; - } + m_DefaultContextNode = this.CreateGraphDataContextNode(ShaderGraphAssetUtils.kMainEntryContextName); + Init(isSubGraph); + } - public override void OnEnable() + public void Init(bool isSubGraph) { - graphHandlerBox.OnEnable(false); - - targetSettingsBox.OnEnable(); - foreach (var target in Targets) + foreach (var addedTarget in Targets) { // at most there is only one target right now, so this solution is not robust. - InitializeContextFromTarget(target.value); + InitializeContextFromTarget(addedTarget.value); } + GraphHandler.ReconcretizeAll(); + + m_DefaultContextNode ??= GetMainContextNode(); + m_DefaultContextNode.Title = isSubGraph ? "Subgraph Outputs" : "Fragment Stage"; + } + + public override void OnEnable() + { + targetSettingsBox.OnEnable(); base.OnEnable(); mainPreviewData = new(Guid.ToString()); - m_DefaultContextNode = GetMainContextNode(); + } + + GraphDataContextNodeModel GetMainContextNode() + { + foreach (var node in NodeModels) + { + if (node is GraphDataContextNodeModel graphDataContextNodeModel && graphDataContextNodeModel.IsMainContextNode()) + return graphDataContextNodeModel; + } + + return null; } /// @@ -203,7 +227,7 @@ public SGNodeUIData GetUIData(RegistryKey registryKey) /// public void CreateUIData() { - if (Stencil is ShaderGraphStencil stencil) + if (Stencil is ShaderGraphStencil stencil && m_NodeUIData == null) { foreach (var registryKey in RegistryInstance.Registry.BrowseRegistryKeys()) { @@ -254,17 +278,6 @@ internal void InitializeContextFromTarget(Target target) } } - GraphDataContextNodeModel GetMainContextNode() - { - foreach (var node in NodeModels) - { - if (node is GraphDataContextNodeModel graphDataContextNodeModel && graphDataContextNodeModel.IsMainContextNode()) - return graphDataContextNodeModel; - } - - return null; - } - public override bool CanBeSubgraph() => isSubGraph; protected override Type GetWireType(PortModel toPort, PortModel fromPort) { diff --git a/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphTemplate.cs b/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphTemplate.cs new file mode 100644 index 00000000000..ca9294c74bf --- /dev/null +++ b/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphTemplate.cs @@ -0,0 +1,62 @@ +using System; +using Unity.GraphToolsFoundation.Editor; +using UnityEngine; + +namespace UnityEditor.ShaderGraph.GraphUI +{ + [Serializable] + enum LegacyTargetType + { + Blank, + URPLit, + URPUnlit + } + + class ShaderGraphTemplate : GraphTemplate + { + readonly bool m_IsSubgraph; + readonly LegacyTargetType m_TargetType; + + public override Type StencilType => typeof(ShaderGraphStencil); + + public override string DefaultAssetName => ShaderGraphStencil.DefaultGraphAssetName; + + public override string GraphFileExtension => ShaderGraphStencil.GraphExtension; + + public override string GraphTypeName { get; } + + public Action GraphHandlerInitializationCallback; + + public override void InitBasicGraph(GraphModel graphModel) + { + base.InitBasicGraph(graphModel); + + if (graphModel.Asset is ShaderGraphAsset shaderGraphAsset) + shaderGraphAsset.Initialize(m_TargetType); + + if (graphModel is ShaderGraphModel shaderGraphModel) + shaderGraphModel.InitModelForNewAsset(m_IsSubgraph, m_TargetType); + } + + public static ShaderGraphAsset CreateInMemoryGraphFromTemplate(ShaderGraphTemplate graphTemplate) + { + var graphAsset = ScriptableObject.CreateInstance(); + + if (graphAsset != null) + { + graphAsset.Name = graphTemplate.DefaultAssetName; + graphAsset.CreateGraph(graphTemplate.StencilType); + graphTemplate?.InitBasicGraph(graphAsset.GraphModel); + graphAsset = (ShaderGraphAsset)graphAsset.Import(); + } + + return graphAsset; + } + + internal ShaderGraphTemplate(bool isSubgraph, LegacyTargetType targetType) + { + m_IsSubgraph = isSubgraph; + m_TargetType = targetType; + } + } +} diff --git a/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphTemplate.cs.meta b/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphTemplate.cs.meta new file mode 100644 index 00000000000..36567fbced9 --- /dev/null +++ b/com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphTemplate.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bc3815dc4c4044238d34b4fcbc2c0cf1 +timeCreated: 1669751694 \ No newline at end of file diff --git a/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetImporter.cs b/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetImporter.cs index b01e5e44eec..88c4c7b1173 100644 --- a/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetImporter.cs +++ b/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetImporter.cs @@ -68,7 +68,7 @@ public override void OnImportAsset(AssetImportContext ctx) { if (string.CompareOrdinal(Path.GetExtension(assetPath), "."+Extension) == 0) { - ShaderGraphAssetUtils.HandleImport(ctx); + ShaderGraphAssetUtils.HandleImportAssetGraph(ctx); } } } diff --git a/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetImporterEditor.cs b/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetImporterEditor.cs index 12c542a5266..303f29d3218 100644 --- a/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetImporterEditor.cs +++ b/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetImporterEditor.cs @@ -75,14 +75,16 @@ public override void OnDisable() [OnOpenAsset(0)] public static bool OnOpenShaderGraph(int instanceID, int line) { - var path = AssetDatabase.GetAssetPath(instanceID); - var graphAsset = AssetDatabase.LoadAssetAtPath(path); - return graphAsset && ShowWindow(path, graphAsset); + string path = AssetDatabase.GetAssetPath(instanceID); + var graphAsset = ShaderGraphAssetUtils.HandleLoad(path);; + if (graphAsset == null) + return false; + return graphAsset && ShowWindow(graphAsset); } - private static bool ShowWindow(string path, ShaderGraphAsset model) + static bool ShowWindow(ShaderGraphAsset asset) { - var window = GraphViewEditorWindow.ShowGraphInExistingOrNewWindow(model); + var window = GraphViewEditorWindow.ShowGraphInExistingOrNewWindow(asset); return window != null; } } diff --git a/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetUtils.cs b/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetUtils.cs index 73a5569cdd9..378c9920e81 100644 --- a/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetUtils.cs +++ b/com.unity.sg2/Editor/GraphUI/Importers/ShaderGraphAssetUtils.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Text; +using Unity.GraphToolsFoundation.Editor; using UnityEditor.AssetImporters; using UnityEditor.ShaderGraph.Generation; using UnityEditor.ShaderGraph.GraphDelta; @@ -14,9 +15,8 @@ namespace UnityEditor.ShaderGraph { static class ShaderGraphAssetUtils { - public static readonly string kBlackboardContextName = Registry.ResolveKey().Name; - public static readonly string kMainEntryContextName = Registry.ResolveKey().Name; + public static readonly string kMainEntryContextName = Registry.ResolveKey().Name; internal static void RebuildContextNodes(GraphHandler graph, Target target) { // This should be consistent for all legacy targets. @@ -26,142 +26,116 @@ internal static void RebuildContextNodes(GraphHandler graph, Target target) graph.RebuildContextData(kMainEntryContextName, target, "UniversalPipeline", "SurfaceDescription", false); } - internal delegate Target GraphHandlerInitializationCallback(GraphHandler graph); - // TODO: Factory for different types of initial creations- this is modified to use URP for now. - internal static ShaderGraphAsset CreateNewAssetGraph(bool isSubGraph, bool isBlank, GraphHandlerInitializationCallback init = null) + // TODO: Context object for asset? containing path, target, other info + internal static ShaderGraphAsset CreateNewAssetGraph(string assetPath, LegacyTargetType legacyTargetType = LegacyTargetType.Blank) { - var defaultRegistry = ShaderGraphRegistry.Instance.Registry; - Target target = null; - GraphHandler graph = new(defaultRegistry); + // Create template, provide parameters and info. for instantiating the asset later on + var graphTemplate = new ShaderGraphTemplate(false, legacyTargetType); - - graph.AddContextNode(kBlackboardContextName); - if (isSubGraph) - { - // subgraphs get a blank output context node, for now using the name of the old contextDescriptor. - graph.AddContextNode(kMainEntryContextName); - } - else if (isBlank) // blank shadergraph gets the fallback context node for output. - { - graph.AddContextNode(Registry.ResolveKey()); - } - else // otherwise we are a URP graph. - { - // Conventional shadergraphs with targets will always have these context nodes. - graph.AddContextNode("VertIn"); - graph.AddContextNode("VertOut"); - graph.AddContextNode("FragIn"); - graph.AddContextNode(kMainEntryContextName); - - if (init != null) - { - target = init.Invoke(graph); - } - else - { - target = URPTargetUtils.ConfigureURPUnlit(graph); - } - // Though we should be more procedural and be using this: to get the corresponding names, eg: - // CPGraphDataProvider.GatherProviderCPIO(target, out var descriptors); - } - graph.ReconcretizeAll(); - // Setup the GTF Model, it will default to using a universal target for now. - var asset = ScriptableObject.CreateInstance(); - asset.CreateGraph(typeof(ShaderGraphStencil)); - asset.ShaderGraphModel.Init(graph, isSubGraph, target); + // Create asset based on the template + var asset = (ShaderGraphAsset)GraphAssetCreationHelpers.CreateGraphAsset(typeof(ShaderGraphAsset), typeof(ShaderGraphStencil), String.Empty, assetPath, graphTemplate); return asset; } - public static void HandleSave(string path, ShaderGraphAsset asset) + internal static ShaderGraphAsset CreateNewSubGraph(string assetPath) { - var json = EditorJsonUtility.ToJson(asset, true); - File.WriteAllText(path, json); - AssetDatabase.ImportAsset(path); // Is this necessary? + throw new NotImplementedException(); } public static ShaderGraphAsset HandleLoad(string path) { - AssetDatabase.ImportAsset(path); - var asset = AssetDatabase.LoadAssetAtPath(path); - return asset; - } + var graphAsset = AssetDatabase.LoadAssetAtPath(path); + if (graphAsset == null) + return null; - internal static void HandleCreate(string path, bool isSubGraph = false, bool isBlank = false, GraphHandlerInitializationCallback init = null) // TODO: TargetSettingsObject as param - { - HandleSave(path, CreateNewAssetGraph(isSubGraph, isBlank, init)); + graphAsset.ShaderGraphModel.OnEnable(); + graphAsset.ShaderGraphModel.Init(false); + return graphAsset; } - public static void HandleImport(AssetImportContext ctx) + public static void HandleImportAssetGraph(AssetImportContext ctx) { // Deserialize the json box string path = ctx.assetPath; string json = File.ReadAllText(path, Encoding.UTF8); var asset = ScriptableObject.CreateInstance(); EditorJsonUtility.FromJsonOverwrite(json, asset); + asset = ShaderGraphTemplate.CreateInMemoryGraphFromTemplate(new ShaderGraphTemplate(asset.IsSubgraph, asset.TargetType)); // Although name gets set during asset's OnEnable, it can get clobbered during deserialize asset.Name = Path.GetFileNameWithoutExtension(path); var sgModel = asset.ShaderGraphModel; sgModel.OnEnable(); - var graphHandler = sgModel.GraphHandler; - + sgModel.Init(asset.IsSubgraph); + var graphHandler = asset.CLDSModel; + // TODO: SGModel should know what it's entry point is for creating a shader. + var node = graphHandler.GetNode(kMainEntryContextName); + var shaderCode = Interpreter.GetShaderForNode(node, graphHandler, graphHandler.registry, out var defaultTextures, sgModel.ActiveTarget, sgModel.ShaderName); - if (!sgModel.IsSubGraph) + var shader = ShaderUtil.CreateShaderAsset(ctx, shaderCode, false); + Material mat = new(shader) { name = "Material/" + asset.Name }; + foreach (var def in defaultTextures) { - // TODO: SGModel should know what it's entry point is for creating a shader. - var node = graphHandler.GetNode(kMainEntryContextName); - var shaderCode = Interpreter.GetShaderForNode(node, graphHandler, graphHandler.registry, out var defaultTextures, sgModel.ActiveTarget, sgModel.ShaderName); - - var shader = ShaderUtil.CreateShaderAsset(ctx, shaderCode, false); - Material mat = new(shader) {name = "Material/" + asset.Name}; - foreach (var def in defaultTextures) - { - mat.SetTexture(def.Item1, def.Item2); - } - Texture2D texture = Resources.Load("Icons/sg_graph_icon"); - - ctx.AddObjectToAsset("Shader", shader, texture); - ctx.SetMainObject(shader); - ctx.AddObjectToAsset("Material", mat); - ctx.AddObjectToAsset("Asset", asset); + mat.SetTexture(def.Item1, def.Item2); } - else // is subgraph + + Texture2D texture = Resources.Load("Icons/sg_graph_icon"); + + ctx.AddObjectToAsset("Shader", shader, texture); + ctx.SetMainObject(shader); + ctx.AddObjectToAsset("Material", mat); + ctx.AddObjectToAsset("Asset", asset); + } + + public static void HandleImportSubGraph(AssetImportContext ctx) + { + // Deserialize the json box + string path = ctx.assetPath; + string json = File.ReadAllText(path, Encoding.UTF8); + var asset = ShaderGraphTemplate.CreateInMemoryGraphFromTemplate(new ShaderGraphTemplate(false, LegacyTargetType.Blank)); + EditorJsonUtility.FromJsonOverwrite(json, asset); + + // Although name gets set during asset's OnEnable, it can get clobbered during deserialize + asset.Name = Path.GetFileNameWithoutExtension(path); + var sgModel = asset.ShaderGraphModel; + sgModel.OnEnable(); + var graphHandler = asset.CLDSModel; + + Texture2D texture = Resources.Load("Icons/sg_subgraph_icon"); + + ctx.AddObjectToAsset("Asset", asset, texture); + ctx.SetMainObject(asset); + + var assetID = AssetDatabase.GUIDFromAssetPath(ctx.assetPath).ToString(); + var fileName = Path.GetFileNameWithoutExtension(ctx.assetPath); + + List paramDesc = new(); + foreach (var dec in sgModel.VariableDeclarations) { - Texture2D texture = Resources.Load("Icons/sg_subgraph_icon"); - - ctx.AddObjectToAsset("Asset", asset, texture); - ctx.SetMainObject(asset); - - var assetID = AssetDatabase.GUIDFromAssetPath(ctx.assetPath).ToString(); - var fileName = Path.GetFileNameWithoutExtension(ctx.assetPath); - - List paramDesc = new(); - foreach (var dec in sgModel.VariableDeclarations) - { - var displayName = dec.GetVariableName(); - var identifierName = ((BaseShaderGraphConstant)dec.InitializationModel).PortName; - paramDesc.Add(new Defs.ParameterUIDescriptor(identifierName, displayName)); - } - - Defs.NodeUIDescriptor desc = new( - version: 1, - name: assetID, - tooltip: "TODO: This should come from the SubGraphModel", - category: "SubGraphs", - synonyms: new string[] { "SubGraph" }, - displayName: fileName, - hasPreview: true, - parameters: paramDesc.ToArray() - ); - - RegistryKey key = new RegistryKey { Name = assetID, Version = 1 }; - var nodeBuilder = new Defs.SubGraphNodeBuilder(key, graphHandler); - var nodeUI = new StaticNodeUIDescriptorBuilder(desc); - - ShaderGraphRegistry.Instance.Registry.Unregister(key); - ShaderGraphRegistry.Instance.Register(nodeBuilder, nodeUI); + var displayName = dec.GetVariableName(); + var identifierName = ((BaseShaderGraphConstant)dec.InitializationModel).PortName; + paramDesc.Add(new Defs.ParameterUIDescriptor(identifierName, displayName)); } + + Defs.NodeUIDescriptor desc = new( + version: 1, + name: assetID, + tooltip: "TODO: This should come from the SubGraphModel", + category: "SubGraphs", + synonyms: new string[] { "SubGraph" }, + displayName: fileName, + hasPreview: true, + parameters: paramDesc.ToArray() + ); + + RegistryKey key = new RegistryKey { Name = assetID, Version = 1 }; + var nodeBuilder = new Defs.SubGraphNodeBuilder(key, graphHandler); + var nodeUI = new StaticNodeUIDescriptorBuilder(desc); + + ShaderGraphRegistry.Instance.Registry.Unregister(key); + ShaderGraphRegistry.Instance.Register(nodeBuilder, nodeUI); + } public static string[] GatherDependenciesForShaderGraphAsset(string assetPath) @@ -169,14 +143,11 @@ public static string[] GatherDependenciesForShaderGraphAsset(string assetPath) string json = File.ReadAllText(assetPath, Encoding.UTF8); var asset = ScriptableObject.CreateInstance(); EditorJsonUtility.FromJsonOverwrite(json, asset); - asset.ShaderGraphModel.OnEnable(); - - SortedSet deps = new(); - var graph = asset.ShaderGraphModel.GraphHandler; + var graph = asset.CLDSModel; - foreach(var node in graph.GetNodes()) + foreach (var node in graph.GetNodes()) { // Subgraphs use their assetID as a registryKey for now-> this is bad and should be handled gracefully in the UI for a user to set in a safe way. // TODO: make it so any node can be asked about its asset dependencies (Either through the builder, or through a field). @@ -187,77 +158,35 @@ public static string[] GatherDependenciesForShaderGraphAsset(string assetPath) return deps.ToArray(); } - } - - [Serializable] - internal class SerializableGraphHandler : ISerializationCallbackReceiver - { - [SerializeField] - string json = ""; - [NonSerialized] - GraphHandler m_graph; - - // Provide a previously initialized graphHandler-- round-trip it for ownership. - public void Init(GraphHandler value) - { - json = value.ToSerializedFormat(); - var reg = ShaderGraphRegistry.Instance.Registry; // TODO: Singleton? - m_graph = GraphHandler.FromSerializedFormat(json, reg); - m_graph.ReconcretizeAll(); - } - - public GraphHandler Graph => m_graph; - - public void OnBeforeSerialize() + [Serializable] + internal class SerializableTargetSettings : ISerializationCallbackReceiver { - // Cloning node models (i.e. GTFs model of cloning a scriptable object, - // triggers a serialize on the cloned node before it has a graph handler reference - if (m_graph == null) - return; - json = m_graph.ToSerializedFormat(); - } + [SerializeField] + string json = ""; - public void OnAfterDeserialize() { } + [NonSerialized] + TargetSettingsObject m_tso = new(); - public void OnEnable(bool reconcretize = true) - { - var reg = ShaderGraphRegistry.Instance.Registry; - m_graph = GraphHandler.FromSerializedFormat(json, reg); - if (reconcretize) + class TargetSettingsObject : JsonObject { - m_graph.ReconcretizeAll(); + [SerializeField] + public List> m_GraphTargets = new(); } - } - } - - [Serializable] - internal class SerializableTargetSettings : ISerializationCallbackReceiver - { - [SerializeField] - string json = ""; - - [NonSerialized] - TargetSettingsObject m_tso = new(); - - class TargetSettingsObject : JsonObject - { - [SerializeField] - public List> m_GraphTargets = new(); - } - public List> Targets => m_tso.m_GraphTargets; + public List> Targets => m_tso.m_GraphTargets; - public void OnBeforeSerialize() - { - json = MultiJson.Serialize(m_tso); - } + public void OnBeforeSerialize() + { + json = MultiJson.Serialize(m_tso); + } - public void OnAfterDeserialize() { } + public void OnAfterDeserialize() { } - public void OnEnable() - { - MultiJson.Deserialize(m_tso, json); + public void OnEnable() + { + MultiJson.Deserialize(m_tso, json); + } } } } diff --git a/com.unity.sg2/Editor/GraphUI/Importers/ShaderSubGraphAssetImporter.cs b/com.unity.sg2/Editor/GraphUI/Importers/ShaderSubGraphAssetImporter.cs index cbbbf905af1..001a84d8aa3 100644 --- a/com.unity.sg2/Editor/GraphUI/Importers/ShaderSubGraphAssetImporter.cs +++ b/com.unity.sg2/Editor/GraphUI/Importers/ShaderSubGraphAssetImporter.cs @@ -23,7 +23,7 @@ public override void OnImportAsset(AssetImportContext ctx) { if (string.CompareOrdinal(Path.GetExtension(assetPath), "."+Extension) == 0) { - ShaderGraphAssetUtils.HandleImport(ctx); + ShaderGraphAssetUtils.HandleImportSubGraph(ctx); } } } diff --git a/com.unity.sg2/Editor/GraphUI/Importers/ShaderSubGraphAssetImporterEditor.cs b/com.unity.sg2/Editor/GraphUI/Importers/ShaderSubGraphAssetImporterEditor.cs index 7479f0b64e8..b545ec2046f 100644 --- a/com.unity.sg2/Editor/GraphUI/Importers/ShaderSubGraphAssetImporterEditor.cs +++ b/com.unity.sg2/Editor/GraphUI/Importers/ShaderSubGraphAssetImporterEditor.cs @@ -12,13 +12,15 @@ public class ShaderSubGraphAssetImporterEditor : AssetImporterEditor [OnOpenAsset(0)] public static bool OnOpenShaderSubGraph(int instanceID, int line) { - string path = AssetDatabase.GetAssetPath(instanceID); - var graphAsset = AssetDatabase.LoadAssetAtPath(path); - if (!graphAsset) - { - return false; - } - return ShowWindow(path, graphAsset); + //string path = AssetDatabase.GetAssetPath(instanceID); + //var graphAsset = AssetDatabase.LoadAssetAtPath(path); + //if (!graphAsset) + //{ + // return false; + //} + //return ShowWindow(path, graphAsset); + + return false; } diff --git a/com.unity.sg2/Editor/GraphUI/ShaderGraphEditorWindow.cs b/com.unity.sg2/Editor/GraphUI/ShaderGraphEditorWindow.cs index 76d0ef7983a..b6ca32ecdb9 100644 --- a/com.unity.sg2/Editor/GraphUI/ShaderGraphEditorWindow.cs +++ b/com.unity.sg2/Editor/GraphUI/ShaderGraphEditorWindow.cs @@ -7,6 +7,7 @@ using UnityEngine; using Unity.CommandStateObserver; using Unity.GraphToolsFoundation; +using Object = UnityEngine.Object; namespace UnityEditor.ShaderGraph.GraphUI { @@ -120,7 +121,7 @@ bool PromptSaveIfDirtyOnQuit() if (option == 0) // save { - GraphAssetUtils.SaveOpenGraphAsset(GraphTool); + AssetUtils.SaveOpenGraphAsset(GraphTool); return true; } else if (option == 1) // cancel (or escape/close dialog) @@ -162,7 +163,7 @@ bool DisplayDeletedFromDiskDialog() if (option == 0) { - var savedPath = GraphAssetUtils.SaveOpenGraphAssetAs(GraphTool); + var savedPath = AssetUtils.SaveOpenGraphAssetAs(GraphTool); if (savedPath != null) { saved = true; diff --git a/com.unity.sg2/Editor/GraphUI/ShaderGraphOnboardingProvider.cs b/com.unity.sg2/Editor/GraphUI/ShaderGraphOnboardingProvider.cs index fe90421cb66..343b1d7dad9 100644 --- a/com.unity.sg2/Editor/GraphUI/ShaderGraphOnboardingProvider.cs +++ b/com.unity.sg2/Editor/GraphUI/ShaderGraphOnboardingProvider.cs @@ -40,7 +40,7 @@ static GraphAsset CreateBlankShaderGraph() var path = EditorUtility.SaveFilePanelInProject(promptTitle, template.DefaultAssetName, ShaderGraphImporter.Extension, prompt); if (path.Length != 0) { - ShaderGraphAssetUtils.HandleCreate(path); + ShaderGraphAssetUtils.CreateNewAssetGraph(path); return ShaderGraphAssetUtils.HandleLoad(path); } return null; diff --git a/com.unity.sg2/Editor/GraphUI/ShaderGraphStencil.cs b/com.unity.sg2/Editor/GraphUI/ShaderGraphStencil.cs index fe5097eb3e7..eef94ed5c2c 100644 --- a/com.unity.sg2/Editor/GraphUI/ShaderGraphStencil.cs +++ b/com.unity.sg2/Editor/GraphUI/ShaderGraphStencil.cs @@ -8,25 +8,19 @@ namespace UnityEditor.ShaderGraph.GraphUI { + // TODO: With how graph templates seem to work, it would seem like we want to have separate stencil classes for the asset graph and subgraph + // TODO: Maybe a subclass of this for subgraphs which can override the graph name defaults and asset type extension etc. class ShaderGraphStencil : Stencil { - public const string Name = "ShaderGraph"; + // TODO: (Sai) When subgraphs come in, add support for dropdown section + static readonly string[] k_Sections = {"Properties", "Keywords"}; + public const string DefaultGraphAssetName = "NewShaderGraph"; public const string GraphExtension = "sg2"; public const string DefaultSubGraphAssetName = "NewShaderSubGraph"; public const string SubGraphExtension = "sg2subgraph"; - - public string ToolName => - Name; - - // TODO: (Sai) When subgraphs come in, add support for dropdown section - internal static readonly string[] sections = {"Properties", "Keywords"}; - - public override IEnumerable SectionNames => sections; - - public ShaderGraphStencil() - { - } + public override IEnumerable SectionNames => k_Sections; + public ShaderGraphStencil() { } public override BlackboardGraphModel CreateBlackboardGraphModel(GraphModel graphModel) => new SGBlackboardGraphModel(graphModel); @@ -116,7 +110,7 @@ public override void PopulateBlackboardCreateMenu( GroupModel selectedGroup = null) { // Only populate the Properties section for now. Will change in the future. - if (sectionName != sections[0]) return; + if (sectionName != k_Sections[0]) return; foreach (var type in ShaderGraphExampleTypes.BlackboardTypes) { diff --git a/com.unity.sg2/Editor/GraphUI/Toolbars/MainToolbar/ShaderGraphSaveAsButton.cs b/com.unity.sg2/Editor/GraphUI/Toolbars/MainToolbar/ShaderGraphSaveAsButton.cs index dd81bb3ec49..a68782d0cf5 100644 --- a/com.unity.sg2/Editor/GraphUI/Toolbars/MainToolbar/ShaderGraphSaveAsButton.cs +++ b/com.unity.sg2/Editor/GraphUI/Toolbars/MainToolbar/ShaderGraphSaveAsButton.cs @@ -19,7 +19,7 @@ public ShaderGraphSaveAsButton() /// protected override void OnClick() { - GraphAssetUtils.SaveOpenGraphAssetAs(GraphTool); + AssetUtils.SaveOpenGraphAssetAs(GraphTool); } } } diff --git a/com.unity.sg2/Editor/GraphUI/Toolbars/MainToolbar/ShaderGraphSaveButton.cs b/com.unity.sg2/Editor/GraphUI/Toolbars/MainToolbar/ShaderGraphSaveButton.cs index 3af8bf1ff2c..79a6a9a63e5 100644 --- a/com.unity.sg2/Editor/GraphUI/Toolbars/MainToolbar/ShaderGraphSaveButton.cs +++ b/com.unity.sg2/Editor/GraphUI/Toolbars/MainToolbar/ShaderGraphSaveButton.cs @@ -18,7 +18,7 @@ public ShaderGraphSaveButton() /// protected override void OnClick() { - GraphAssetUtils.SaveOpenGraphAsset(GraphTool); + AssetUtils.SaveOpenGraphAsset(GraphTool); } } } diff --git a/com.unity.sg2/Editor/GraphUI/Utilities/GraphAssetUtils.cs b/com.unity.sg2/Editor/GraphUI/Utilities/AssetUtils.cs similarity index 81% rename from com.unity.sg2/Editor/GraphUI/Utilities/GraphAssetUtils.cs rename to com.unity.sg2/Editor/GraphUI/Utilities/AssetUtils.cs index 20d9ac3285f..9492fca28b2 100644 --- a/com.unity.sg2/Editor/GraphUI/Utilities/GraphAssetUtils.cs +++ b/com.unity.sg2/Editor/GraphUI/Utilities/AssetUtils.cs @@ -5,17 +5,15 @@ namespace UnityEditor.ShaderGraph.GraphUI { - public static class GraphAssetUtils + public static class AssetUtils { - internal class CreateGraphAssetAction : ProjectWindowCallback.EndNameEditAction + internal class CreateAssetGraphAction : ProjectWindowCallback.EndNameEditAction { - internal bool isBlank = false; - internal bool isSubGraph = false; - internal ShaderGraphAssetUtils.GraphHandlerInitializationCallback callback = null; + internal LegacyTargetType legacyTargetType = LegacyTargetType.Blank; public override void Action(int instanceId, string pathName, string resourceFile) { - ShaderGraphAssetUtils.HandleCreate(pathName, isSubGraph, isBlank, callback); + ShaderGraphAssetUtils.CreateNewAssetGraph(pathName, legacyTargetType); var obj = AssetDatabase.LoadAssetAtPath(pathName); Selection.activeObject = obj; } @@ -24,8 +22,8 @@ public override void Action(int instanceId, string pathName, string resourceFile [MenuItem("Assets/Create/Shader Graph 2/URP Lit Shader Graph", priority = CoreUtils.Priorities.assetsCreateShaderMenuPriority)] public static void CreateURPLitGraphInProjectWindow() { - var newGraphAction = ScriptableObject.CreateInstance(); - newGraphAction.callback = URPTargetUtils.ConfigureURPLit; + var newGraphAction = ScriptableObject.CreateInstance(); + newGraphAction.legacyTargetType = LegacyTargetType.URPLit; ProjectWindowUtil.StartNameEditingIfProjectWindowExists( 0, newGraphAction, @@ -37,8 +35,8 @@ public static void CreateURPLitGraphInProjectWindow() [MenuItem("Assets/Create/Shader Graph 2/URP Unlit Shader Graph", priority = CoreUtils.Priorities.assetsCreateShaderMenuPriority)] public static void CreateURPUnlitGraphInProjectWindow() { - var newGraphAction = ScriptableObject.CreateInstance(); - newGraphAction.callback = URPTargetUtils.ConfigureURPUnlit; + var newGraphAction = ScriptableObject.CreateInstance(); + newGraphAction.legacyTargetType = LegacyTargetType.URPUnlit; ProjectWindowUtil.StartNameEditingIfProjectWindowExists( 0, newGraphAction, @@ -51,7 +49,7 @@ public static void CreateURPUnlitGraphInProjectWindow() //[MenuItem("Assets/Create/Shader Graph 2/Blank Shader SubGraph", priority = CoreUtils.Priorities.assetsCreateShaderMenuPriority)] //public static void CreateBlankSubGraphInProjectWindow() //{ - // var newGraphAction = ScriptableObject.CreateInstance(); + // var newGraphAction = ScriptableObject.CreateInstance(); // newGraphAction.isSubGraph = true; // ProjectWindowUtil.StartNameEditingIfProjectWindowExists( @@ -62,22 +60,21 @@ public static void CreateURPUnlitGraphInProjectWindow() // null); //} - private static void SaveImplementation(BaseGraphTool GraphTool, Action SaveAction) + private static void SaveImplementation(BaseGraphTool GraphTool) { // If no currently opened graph, early out if (GraphTool.ToolState.CurrentGraph.GetGraphAsset() == null) return; - if (GraphTool.ToolState.CurrentGraph.GetGraphAsset() is ShaderGraphAsset assetModel) + if (GraphTool.ToolState.CurrentGraph.GetGraphAsset() is ShaderGraphAsset graphAsset) { var assetPath = GraphTool.ToolState.CurrentGraph.GetGraphAssetPath(); - SaveAction(assetPath, assetModel); // Set to false after saving to clear modification state from editor window tab - assetModel.Dirty = false; + graphAsset.Dirty = false; } } - private static string SaveAsImplementation(BaseGraphTool GraphTool, Action SaveAction, string dialogTitle, string extension) + private static string SaveAsImplementation(BaseGraphTool GraphTool, string dialogTitle, string extension) { // If no currently opened graph, early out if (GraphTool.ToolState.CurrentGraph.GetGraphAsset() == null) @@ -94,8 +91,6 @@ private static string SaveAsImplementation(BaseGraphTool GraphTool, Action - SaveImplementation(GraphTool, - ShaderGraphAssetUtils.HandleSave); static void SaveSubGraphImplementation(BaseGraphTool GraphTool) => - SaveImplementation(GraphTool, - ShaderGraphAssetUtils.HandleSave); + SaveImplementation(GraphTool); static string SaveAsGraphImplementation(BaseGraphTool GraphTool) => SaveAsImplementation(GraphTool, - ShaderGraphAssetUtils.HandleSave, "Save Shader Graph Asset at: ", ShaderGraphStencil.GraphExtension); static string SaveAsSubGraphImplementation(BaseGraphTool GraphTool) => SaveAsImplementation(GraphTool, - ShaderGraphAssetUtils.HandleSave, "Save Shader SubGraph Asset at:", ShaderGraphStencil.SubGraphExtension); @@ -141,7 +130,7 @@ internal static void SaveOpenGraphAsset(BaseGraphTool graphTool) } else { - SaveGraphImplementation(graphTool); + graphAsset.Save(); } } diff --git a/com.unity.sg2/Editor/GraphUI/Utilities/GraphAssetUtils.cs.meta b/com.unity.sg2/Editor/GraphUI/Utilities/AssetUtils.cs.meta similarity index 100% rename from com.unity.sg2/Editor/GraphUI/Utilities/GraphAssetUtils.cs.meta rename to com.unity.sg2/Editor/GraphUI/Utilities/AssetUtils.cs.meta diff --git a/com.unity.sg2/Tests/GraphUI/BaseGraphWindowTest.cs b/com.unity.sg2/Tests/GraphUI/BaseGraphWindowTest.cs index 38c0077e45c..787d6fbb9cf 100644 --- a/com.unity.sg2/Tests/GraphUI/BaseGraphWindowTest.cs +++ b/com.unity.sg2/Tests/GraphUI/BaseGraphWindowTest.cs @@ -52,29 +52,30 @@ public virtual void SetUp() switch (GraphToInstantiate) { case GraphInstantiation.MemoryBlank: - graphAsset = ShaderGraphAssetUtils.CreateNewAssetGraph(false, true); + graphAsset = ShaderGraphAssetUtils.CreateNewAssetGraph(testAssetPath); break; case GraphInstantiation.Memory: - graphAsset = ShaderGraphAssetUtils.CreateNewAssetGraph(false, false); + graphAsset = ShaderGraphAssetUtils.CreateNewAssetGraph(testAssetPath, LegacyTargetType.URPUnlit); break; case GraphInstantiation.MemorySubGraph: - graphAsset = ShaderGraphAssetUtils.CreateNewAssetGraph(true, false); + graphAsset = ShaderGraphAssetUtils.CreateNewSubGraph(testAssetPath); break; case GraphInstantiation.Disk: { - var newGraphAction = ScriptableObject.CreateInstance(); + var newGraphAction = ScriptableObject.CreateInstance(); newGraphAction.Action(0, testAssetPath, ""); graphAsset = AssetDatabase.LoadAssetAtPath(testAssetPath); break; } + // TODO: This should call a CreateSubGraphAssetAction instead case GraphInstantiation.DiskSubGraph: { - var newGraphAction = ScriptableObject.CreateInstance(); - newGraphAction.isSubGraph = true; + var newGraphAction = ScriptableObject.CreateInstance(); + //newGraphAction.isSubGraph = true; newGraphAction.Action(0, testAssetPath, ""); graphAsset = ShaderGraphAssetUtils.HandleLoad(testAssetPath); break; @@ -139,7 +140,7 @@ public void CloseWindow() /// public IEnumerator SaveAndReopenGraph() { - GraphAssetUtils.SaveOpenGraphAsset(m_Window.GraphTool); + AssetUtils.SaveOpenGraphAsset(m_Window.GraphTool); CloseWindow(); yield return null; diff --git a/com.unity.sg2/Tests/GraphUI/BlackboardTests.cs b/com.unity.sg2/Tests/GraphUI/BlackboardTests.cs index b3b57cb1290..eaca4841519 100644 --- a/com.unity.sg2/Tests/GraphUI/BlackboardTests.cs +++ b/com.unity.sg2/Tests/GraphUI/BlackboardTests.cs @@ -37,7 +37,7 @@ string CreateSecondGraph( { // Create second graph var secondGraphPath = testAssetPath.Replace(ShaderGraphStencil.DefaultGraphAssetName, "NewShaderGraph1"); - var newGraphAction = ScriptableObject.CreateInstance(); + var newGraphAction = ScriptableObject.CreateInstance(); newGraphAction.Action(0, secondGraphPath, ""); secondGraphAsset = AssetDatabase.LoadAssetAtPath(secondGraphPath); diff --git a/com.unity.sg2/Tests/GraphUI/GraphAssetTests.cs b/com.unity.sg2/Tests/GraphUI/GraphAssetTests.cs index 21f3e575c17..ac8a9502d22 100644 --- a/com.unity.sg2/Tests/GraphUI/GraphAssetTests.cs +++ b/com.unity.sg2/Tests/GraphUI/GraphAssetTests.cs @@ -18,7 +18,7 @@ public void Setup() [Test] public void CreateGraphAssetTest() { - var newGraphAction = ScriptableObject.CreateInstance(); + var newGraphAction = ScriptableObject.CreateInstance(); var assetPath = $"Assets\\{ShaderGraphStencil.DefaultGraphAssetName}.{ShaderGraphStencil.GraphExtension}"; newGraphAction.Action(0, assetPath, ""); var newAsset = AssetDatabase.LoadAssetAtPath(assetPath); @@ -28,7 +28,7 @@ public void CreateGraphAssetTest() [Test] public void GraphSubAssetAssociationTest() { - var newGraphAction = ScriptableObject.CreateInstance(); + var newGraphAction = ScriptableObject.CreateInstance(); var assetPath = $"Assets\\{ShaderGraphStencil.DefaultGraphAssetName}.{ShaderGraphStencil.GraphExtension}"; newGraphAction.Action(0, assetPath, ""); var materialAsset = AssetDatabase.LoadAssetAtPath(assetPath); diff --git a/com.unity.sg2/Tests/GraphUI/Tools.cs b/com.unity.sg2/Tests/GraphUI/Tools.cs index e5e5d140b35..9fc1d261d99 100644 --- a/com.unity.sg2/Tests/GraphUI/Tools.cs +++ b/com.unity.sg2/Tests/GraphUI/Tools.cs @@ -17,7 +17,7 @@ static void GenerateAllNodesGraph() var graphWindowTest = new BaseGraphWindowTest(); var window = graphWindowTest.CreateWindow(); - var newGraphAction = ScriptableObject.CreateInstance(); + var newGraphAction = ScriptableObject.CreateInstance(); newGraphAction.Action(0, testAssetPath, ""); var graphAsset = AssetDatabase.LoadAssetAtPath(testAssetPath); @@ -62,7 +62,7 @@ static int RoundOff(int i) } // Save asset - ShaderGraphAssetUtils.HandleSave(testAssetPath, graphAsset); + graphAsset.Save(); } [MenuItem("Tests/Shader Graph/Create Texture 2D Array")] diff --git a/com.unity.shadergraph/Editor/GraphDeltaRegistry/PreviewManager.meta b/com.unity.shadergraph/Editor/GraphDeltaRegistry/PreviewManager.meta new file mode 100644 index 00000000000..d6401193c79 --- /dev/null +++ b/com.unity.shadergraph/Editor/GraphDeltaRegistry/PreviewManager.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e029902807be57944ab5ac17b42ea6de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.shadergraph/Editor/GraphUI/DataModel.meta b/com.unity.shadergraph/Editor/GraphUI/DataModel.meta new file mode 100644 index 00000000000..1cdb1951a5c --- /dev/null +++ b/com.unity.shadergraph/Editor/GraphUI/DataModel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53d3aa41dda1a16478619cb388d8044c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.shadergraph/Editor/GraphUI/EditorCommon.meta b/com.unity.shadergraph/Editor/GraphUI/EditorCommon.meta new file mode 100644 index 00000000000..d206d689cc7 --- /dev/null +++ b/com.unity.shadergraph/Editor/GraphUI/EditorCommon.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 792bc95e7e155c44ca1de6fae46ebf50 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.shadergraph/Editor/GraphUI/EditorCommon/CommandStateObserver.meta b/com.unity.shadergraph/Editor/GraphUI/EditorCommon/CommandStateObserver.meta new file mode 100644 index 00000000000..9669a653bd0 --- /dev/null +++ b/com.unity.shadergraph/Editor/GraphUI/EditorCommon/CommandStateObserver.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09b32ff550ff1c045823a7fb267bfebf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: