浏览代码

[material graph]Add button to convert selection into subGraph

/main
Tim Cooper 8 年前
当前提交
607a2f9e
共有 8 个文件被更改,包括 217 次插入25 次删除
  1. 52
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Editor/Drawing/CopySelected.cs
  2. 159
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Editor/Drawing/GraphEditWindow.cs
  3. 24
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/NodeUtils.cs
  4. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/MaterialGraphAsset.cs
  5. 3
      MaterialGraphProject/Assets/UnityShaderEditor/Runtime/SubGraph/SubGraphNode.cs
  6. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/MaterialSubGraphAsset.cs
  7. 0
      /MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/MaterialSubGraphAsset.cs.meta
  8. 0
      /MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/MaterialSubGraphAsset.cs

52
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Editor/Drawing/CopySelected.cs


internal class CopyPasteGraph : ISerializationCallbackReceiver
{
[NonSerialized]
private List<IEdge> m_Edges = new List<IEdge>();
private HashSet<IEdge> m_Edges = new HashSet<IEdge>();
private List<INode> m_Nodes = new List<INode>();
private HashSet<INode> m_Nodes = new HashSet<INode>();
[SerializeField]
List<SerializationHelper.JSONSerializedElement> m_SerializableNodes = new List<SerializationHelper.JSONSerializedElement>();

public virtual void OnAfterDeserialize()
{
m_Nodes = SerializationHelper.Deserialize<INode>(m_SerializableNodes);
var nodes = SerializationHelper.Deserialize<INode>(m_SerializableNodes);
m_Nodes.Clear();
foreach (var node in nodes)
m_Nodes.Add(node);
m_Edges = SerializationHelper.Deserialize<IEdge>(m_SerializableEdges);
var edges = SerializationHelper.Deserialize<IEdge>(m_SerializableEdges);
m_Edges.Clear();
foreach (var edge in edges)
m_Edges.Add(edge);
m_SerializableEdges = null;
}
}

if (e.commandName != "Copy" && e.commandName != "Paste" && e.commandName != "Duplicate")
return false;
if (e.commandName == "Copy" || e.commandName == "Duplicate")
DoCopy(parent);

return true;
}
private void DoCopy(Canvas2D parent)
private static void DoCopy(Canvas2D parent)
{
EditorGUIUtility.systemCopyBuffer = SerializeSelectedElements(parent);
}
public static string SerializeSelectedElements(Canvas2D parent)
{
var selectedElements = parent.selection;

if (dNode != null)
{
graph.AddNode(dNode.m_Node);
continue;
foreach (var edge in NodeUtils.GetAllEdges(dNode.m_Node))
graph.AddEdge(edge);
}
var dEdge = thing as DrawableEdge<NodeAnchor>;

}
// serialize then break references
var serialized = JsonUtility.ToJson(graph, true);
EditorGUIUtility.systemCopyBuffer = serialized;
return serialized;
private void DoPaste(Canvas2D parent)
public static CopyPasteGraph DeserializeSelectedElements(string toDeserialize)
var copyText = EditorGUIUtility.systemCopyBuffer;
if (string.IsNullOrEmpty(copyText))
return;
CopyPasteGraph pastedGraph;
pastedGraph = JsonUtility.FromJson<CopyPasteGraph>(copyText);
return JsonUtility.FromJson<CopyPasteGraph>(toDeserialize);
return;
return null;
}
private static void DoPaste(Canvas2D parent)
{
var copyText = EditorGUIUtility.systemCopyBuffer;
if (string.IsNullOrEmpty(copyText))
return;
var pastedGraph = DeserializeSelectedElements(copyText);
if (pastedGraph == null)
return;

return;
var graph = asset.graph;
if (asset.graph == null)
if (graph == null)
return;
var addedNodes = new List<INode>();

159
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Editor/Drawing/GraphEditWindow.cs


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor.MaterialGraph;
using UnityEngine;
using UnityEngine.Graphing;
using UnityEngine.MaterialGraph;

// The following manipulator show how to work with canvas2d overlay and background rendering
m_Canvas.AddManipulator(new RectangleSelect());
m_Canvas.AddManipulator(new ScreenSpaceGrid());
m_Canvas.AddManipulator(new ContextualMenu(DoAddNodeMenu));
m_Canvas.AddManipulator(new ContextualMenu(DoContextMenu));
m_Canvas.AddManipulator(new DeleteSelected(m_DataSource.DeleteElements));
m_Canvas.AddManipulator(new CopySelected());

}
public virtual bool CanAddToNodeMenu(Type type) { return true; }
protected bool DoAddNodeMenu(Event @event, Canvas2D parent, Object customData)
protected bool DoContextMenu(Event @event, Canvas2D parent, Object customData)
{
var gm = new GenericMenu();
foreach (Type type in Assembly.GetAssembly(typeof(AbstractMaterialNode)).GetTypes())

}
}
}
//gm.AddSeparator("");
// gm.AddItem(new GUIContent("Convert To/SubGraph"), true, ConvertSelectionToSubGraph);
private void ConvertSelectionToSubGraph()
{
if (m_Canvas.dataSource == null)
return;
var dataSource = m_Canvas.dataSource as GraphDataSource;
if (dataSource == null)
return;
var asset = dataSource.graphAsset;
if (asset == null)
return;
var targetGraph = asset.graph;
if (targetGraph == null)
return;
if (!m_Canvas.selection.Any())
return;
var serialzied = CopySelected.SerializeSelectedElements(m_Canvas);
var deserialized = CopySelected.DeserializeSelectedElements(serialzied);
if (deserialized == null)
return;
string path = EditorUtility.SaveFilePanelInProject("Save subgraph", "New SubGraph", "ShaderSubGraph", "");
path = path.Replace(Application.dataPath, "Assets");
if (path.Length == 0)
return;
var graphAsset = CreateInstance<MaterialSubGraphAsset>();
graphAsset.name = Path.GetFileName(path);
graphAsset.PostCreate();
var graph = graphAsset.subGraph;
if (graphAsset.graph == null)
return;
var nodeGuidMap = new Dictionary<Guid, Guid>();
foreach (var node in deserialized.GetNodes<INode>())
{
var oldGuid = node.guid;
var newGuid = node.RewriteGuid();
nodeGuidMap[oldGuid] = newGuid;
graph.AddNode(node);
}
// remap outputs to the subgraph
var inputEdgeNeedsRemap = new List<IEdge>();
var outputEdgeNeedsRemap = new List<IEdge>();
foreach (var edge in deserialized.edges)
{
var outputSlot = edge.outputSlot;
var inputSlot = edge.inputSlot;
Guid remappedOutputNodeGuid;
Guid remappedInputNodeGuid;
var outputRemapExists = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid);
var inputRemapExists = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid);
// pasting nice internal links!
if (outputRemapExists && inputRemapExists)
{
var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotName);
var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotName);
graph.Connect(outputSlotRef, inputSlotRef);
}
// one edge needs to go to outside world
else if (outputRemapExists)
{
inputEdgeNeedsRemap.Add(edge);
}
else if (inputRemapExists)
{
outputEdgeNeedsRemap.Add(edge);
}
}
// we do a grouping here as the same output can
// point to multiple inputs
var uniqueOutputs = outputEdgeNeedsRemap.GroupBy(edge => edge.outputSlot);
var inputsNeedingConnection = new List<KeyValuePair<IEdge, IEdge>>();
foreach (var group in uniqueOutputs)
{
var inputNode = graph.inputNode;
var index = inputNode.GetOutputSlots<ISlot>().Count();
inputNode.AddSlot();
var outputSlotRef = new SlotReference(inputNode.guid, "Input" + index);
foreach (var edge in group)
{
var newEdge = graph.Connect(outputSlotRef, new SlotReference(nodeGuidMap[edge.inputSlot.nodeGuid], edge.inputSlot.slotName));
inputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge));
}
}
var uniqueInputs = inputEdgeNeedsRemap.GroupBy(edge => edge.inputSlot);
var outputsNeedingConnection = new List<KeyValuePair<IEdge, IEdge>>();
foreach (var group in uniqueInputs)
{
var outputNode = graph.outputNode;
var index = outputNode.GetInputSlots<ISlot>().Count();
outputNode.AddSlot();
var inputSlotRef = new SlotReference(outputNode.guid, "Output" + index);
foreach (var edge in group)
{
var newEdge = graph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotName), inputSlotRef);
outputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge));
}
}
AssetDatabase.CreateAsset(graphAsset, path);
var subGraphNode = new SubGraphNode();
targetGraph.AddNode(subGraphNode);
subGraphNode.subGraphAsset = graphAsset;
foreach (var edgeMap in inputsNeedingConnection)
{
targetGraph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.outputSlot.slotName));
}
foreach (var edgeMap in outputsNeedingConnection)
{
targetGraph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotName), edgeMap.Key.inputSlot);
}
var toDelete = m_Canvas.selection.Where(x => x is DrawableNode).ToList();
dataSource.DeleteElements(toDelete);
targetGraph.ValidateGraph();
m_Canvas.ReloadData();
m_Canvas.Invalidate();
m_Canvas.selection.Clear();
var toSelect = m_Canvas.elements.OfType<DrawableNode>().FirstOrDefault(x => x.m_Node == subGraphNode);
if (toSelect != null)
{
toSelect.selected = true;
m_Canvas.selection.Add(toSelect);
}
m_Canvas.Repaint();
}
private void Rebuild()
{
if (m_Canvas == null || m_LastSelection == null)

}
m_Canvas.OnGUI(this, new Rect(0, 0, position.width - 250, position.height));
if (GUI.Button(new Rect(position.width - 250, 0, 250, 50), "Convert to Sub-Graph"))
ConvertSelectionToSubGraph();
}
/*public void RenderOptions(MaterialGraph graph)

24
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/NodeUtils.cs


return foundUsedOutputSlots;
}
public static IEnumerable<IEdge> GetAllEdges(INode node)
{
var result = new List<IEdge>();
var validSlots = ListPool<ISlot>.Get();
validSlots.AddRange(node.GetInputSlots<ISlot>());
for (int index = 0; index < validSlots.Count; index++)
{
var inputSlot = validSlots[index];
result.AddRange(node.owner.GetEdges(node.GetSlotReference(inputSlot.name)));
}
validSlots.Clear();
validSlots.AddRange(node.GetOutputSlots<ISlot>());
for (int index = 0; index < validSlots.Count; index++)
{
var outputSlot = validSlots[index];
result.AddRange(node.owner.GetEdges(node.GetSlotReference(outputSlot.name)));
}
ListPool<ISlot>.Release(validSlots);
return result;
}
public static void RecurseNodesToFindValidOutputSlots(INode fromNode, INode currentNode, ICollection<ISlot> foundUsedOutputSlots)
{
if (fromNode == null || currentNode == null)

2
MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/MaterialGraphAsset.cs


public class MaterialGraphAsset : ScriptableObject, IMaterialGraphAsset
{
[SerializeField]
private MaterialGraph m_MaterialGraph;
private MaterialGraph m_MaterialGraph = new MaterialGraph();
public IGraph graph
{

3
MaterialGraphProject/Assets/UnityShaderEditor/Runtime/SubGraph/SubGraphNode.cs


using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Graphing;
using UnityEngine.MaterialGraph;

if (subGraphAsset == null)
return PreviewMode.Preview2D;
return subGraph.previewMode;
return PreviewMode.Preview3D;
}
}

2
MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/MaterialSubGraphAsset.cs


public class MaterialSubGraphAsset : ScriptableObject, IMaterialGraphAsset
{
[SerializeField]
private SubGraph m_MaterialSubGraph;
private SubGraph m_MaterialSubGraph = new SubGraph();
public IGraph graph
{

/MaterialGraphProject/Assets/UnityShaderEditor/Runtime/SubGraph/MaterialSubGraphAsset.cs.meta → /MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/MaterialSubGraphAsset.cs.meta

/MaterialGraphProject/Assets/UnityShaderEditor/Runtime/SubGraph/MaterialSubGraphAsset.cs → /MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/MaterialSubGraphAsset.cs

正在加载...
取消
保存