Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SG2] Asset structure refactor #7745

Open
wants to merge 8 commits into
base: sg2/main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 131 additions & 1 deletion com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphAsset.cs
Original file line number Diff line number Diff line change
@@ -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<PropertyContext>().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<Defs.ShaderGraphContext>());
}
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);
}
}
}
69 changes: 41 additions & 28 deletions com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<JsonData<Target>> Targets => targetSettingsBox.Targets; // TODO: Store the active editing target in the box?
internal Target ActiveTarget => Targets.FirstOrDefault();
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}

/// <summary>
Expand All @@ -203,7 +227,7 @@ public SGNodeUIData GetUIData(RegistryKey registryKey)
/// </summary>
public void CreateUIData()
{
if (Stencil is ShaderGraphStencil stencil)
if (Stencil is ShaderGraphStencil stencil && m_NodeUIData == null)
{
foreach (var registryKey in RegistryInstance.Registry.BrowseRegistryKeys())
{
Expand Down Expand Up @@ -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)
{
Expand Down
62 changes: 62 additions & 0 deletions com.unity.sg2/Editor/GraphUI/DataModel/ShaderGraphTemplate.cs
Original file line number Diff line number Diff line change
@@ -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<ShaderGraphAsset>();

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;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public override void OnImportAsset(AssetImportContext ctx)
{
if (string.CompareOrdinal(Path.GetExtension(assetPath), "."+Extension) == 0)
{
ShaderGraphAssetUtils.HandleImport(ctx);
ShaderGraphAssetUtils.HandleImportAssetGraph(ctx);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ShaderGraphAsset>(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<ShaderGraphEditorWindow>(model);
var window = GraphViewEditorWindow.ShowGraphInExistingOrNewWindow<ShaderGraphEditorWindow>(asset);
return window != null;
}
}
Expand Down
Loading