|
|
|
|
|
|
|
|
|
|
var graphView = graphEditorView.graphView; |
|
|
|
|
|
|
|
var nodes = graphView.selection.OfType<MaterialNodeView>().Where(x => !(x.node is PropertyNode)).Select(x => x.node as INode).ToArray(); |
|
|
|
Vector2 middle = Vector2.zero; |
|
|
|
foreach (var node in nodes) |
|
|
|
{ |
|
|
|
middle += node.drawState.position.center; |
|
|
|
} |
|
|
|
middle /= nodes.Length; |
|
|
|
|
|
|
|
var copyPasteGraph = new CopyPasteGraph( |
|
|
|
graphView.selection.OfType<MaterialNodeView>().Where(x => !(x.node is PropertyNode)).Select(x => x.node as INode), |
|
|
|
graphView.selection.OfType<Edge>().Select(x => x.userData as IEdge)); |
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
var graph = new SubGraph(); |
|
|
|
graph.AddNode(new SubGraphOutputNode()); |
|
|
|
var subGraph = new SubGraph(); |
|
|
|
subGraph.AddNode(new SubGraphOutputNode()); |
|
|
|
|
|
|
|
var nodeGuidMap = new Dictionary<Guid, Guid>(); |
|
|
|
foreach (var node in deserialized.GetNodes<INode>()) |
|
|
|
|
|
|
nodeGuidMap[oldGuid] = newGuid; |
|
|
|
graph.AddNode(node); |
|
|
|
subGraph.AddNode(node); |
|
|
|
// remap outputs to the subgraph
|
|
|
|
var onlyInputInternallyConnected = new List<IEdge>(); |
|
|
|
var onlyOutputInternallyConnected = new List<IEdge>(); |
|
|
|
// figure out what needs remapping
|
|
|
|
var externalOutputSlots = new List<IEdge>(); |
|
|
|
var externalInputSlots = new List<IEdge>(); |
|
|
|
foreach (var edge in deserialized.edges) |
|
|
|
{ |
|
|
|
var outputSlot = edge.outputSlot; |
|
|
|
|
|
|
Guid remappedInputNodeGuid; |
|
|
|
var outputRemapExists = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid); |
|
|
|
var inputRemapExists = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid); |
|
|
|
var outputSlotExistsInSubgraph = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid); |
|
|
|
var inputSlotExistsInSubgraph = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid); |
|
|
|
if (outputRemapExists && inputRemapExists) |
|
|
|
if (outputSlotExistsInSubgraph && inputSlotExistsInSubgraph) |
|
|
|
graph.Connect(outputSlotRef, inputSlotRef); |
|
|
|
subGraph.Connect(outputSlotRef, inputSlotRef); |
|
|
|
else if (outputRemapExists) |
|
|
|
else if (outputSlotExistsInSubgraph) |
|
|
|
onlyOutputInternallyConnected.Add(edge); |
|
|
|
externalInputSlots.Add(edge); |
|
|
|
else if (inputRemapExists) |
|
|
|
else if (inputSlotExistsInSubgraph) |
|
|
|
onlyInputInternallyConnected.Add(edge); |
|
|
|
externalOutputSlots.Add(edge); |
|
|
|
var uniqueInputEdges = onlyOutputInternallyConnected.GroupBy( |
|
|
|
// Find the unique edges coming INTO the graph
|
|
|
|
var uniqueIncomingEdges = externalOutputSlots.GroupBy( |
|
|
|
(key, edges) => new { slotRef = key, edges = edges.ToList() }); |
|
|
|
foreach (var group in uniqueInputEdges) |
|
|
|
(key, edges) => new {slotRef = key, edges = edges.ToList()}); |
|
|
|
|
|
|
|
|
|
|
|
var externalInputNeedingConnection = new List<KeyValuePair<IEdge, IShaderProperty>>(); |
|
|
|
foreach (var group in uniqueIncomingEdges) |
|
|
|
IShaderProperty prop; |
|
|
|
case ConcreteSlotValueType.SamplerState: |
|
|
|
break; |
|
|
|
case ConcreteSlotValueType.Matrix4: |
|
|
|
break; |
|
|
|
case ConcreteSlotValueType.Matrix3: |
|
|
|
break; |
|
|
|
case ConcreteSlotValueType.Matrix2: |
|
|
|
break; |
|
|
|
prop = new TextureShaderProperty(); |
|
|
|
prop = new Vector4ShaderProperty(); |
|
|
|
prop = new Vector3ShaderProperty(); |
|
|
|
prop = new Vector2ShaderProperty(); |
|
|
|
prop = new FloatShaderProperty(); |
|
|
|
|
|
|
|
if (prop != null) |
|
|
|
{ |
|
|
|
subGraph.AddShaderProperty(prop); |
|
|
|
var propNode = new PropertyNode(); |
|
|
|
subGraph.AddNode(propNode); |
|
|
|
propNode.propertyGuid = prop.guid; |
|
|
|
|
|
|
|
foreach (var edge in group.edges) |
|
|
|
{ |
|
|
|
subGraph.Connect( |
|
|
|
new SlotReference(propNode.guid, PropertyNode.OutputSlotId), |
|
|
|
new SlotReference(nodeGuidMap[edge.inputSlot.nodeGuid], edge.inputSlot.slotId)); |
|
|
|
externalInputNeedingConnection.Add(new KeyValuePair<IEdge, IShaderProperty>(edge, prop)); |
|
|
|
} |
|
|
|
} |
|
|
|
var uniqueOutputEdges = onlyInputInternallyConnected.GroupBy( |
|
|
|
var uniqueOutgoingEdges = externalInputSlots.GroupBy( |
|
|
|
(key, edges) => new { slot = key, edges = edges.ToList() }); |
|
|
|
(key, edges) => new {slot = key, edges = edges.ToList()}); |
|
|
|
var outputsNeedingConnection = new List<KeyValuePair<IEdge, IEdge>>(); |
|
|
|
foreach (var group in uniqueOutputEdges) |
|
|
|
var externalOutputsNeedingConnection = new List<KeyValuePair<IEdge, IEdge>>(); |
|
|
|
foreach (var group in uniqueOutgoingEdges) |
|
|
|
var outputNode = graph.outputNode; |
|
|
|
var outputNode = subGraph.outputNode; |
|
|
|
var slotId = outputNode.AddSlot(); |
|
|
|
|
|
|
|
var inputSlotRef = new SlotReference(outputNode.guid, slotId); |
|
|
|
|
|
|
var newEdge = graph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotId), inputSlotRef); |
|
|
|
outputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge)); |
|
|
|
var newEdge = subGraph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotId), inputSlotRef); |
|
|
|
externalOutputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge)); |
|
|
|
File.WriteAllText(path, EditorJsonUtility.ToJson(graph)); |
|
|
|
File.WriteAllText(path, EditorJsonUtility.ToJson(subGraph)); |
|
|
|
var subGraph = AssetDatabase.LoadAssetAtPath(path, typeof(MaterialSubGraphAsset)) as MaterialSubGraphAsset; |
|
|
|
if (subGraph == null) |
|
|
|
var loadedSubGraph = AssetDatabase.LoadAssetAtPath(path, typeof(MaterialSubGraphAsset)) as MaterialSubGraphAsset; |
|
|
|
if (loadedSubGraph == null) |
|
|
|
var ds = subGraphNode.drawState; |
|
|
|
ds.position = new Rect(middle, Vector2.one); |
|
|
|
subGraphNode.drawState = ds; |
|
|
|
subGraphNode.subGraphAsset = subGraph; |
|
|
|
subGraphNode.subGraphAsset = loadedSubGraph; |
|
|
|
/* foreach (var edgeMap in inputsNeedingConnection) |
|
|
|
{ |
|
|
|
graphObject.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.outputSlot.slotId)); |
|
|
|
}*/ |
|
|
|
foreach (var edgeMap in externalInputNeedingConnection) |
|
|
|
{ |
|
|
|
graphObject.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.guid.GetHashCode())); |
|
|
|
} |
|
|
|
foreach (var edgeMap in outputsNeedingConnection) |
|
|
|
foreach (var edgeMap in externalOutputsNeedingConnection) |
|
|
|
{ |
|
|
|
graphObject.graph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot); |
|
|
|
} |
|
|
|
|
|
|
var shaderImporter = AssetImporter.GetAtPath(path) as ShaderGraphImporter; |
|
|
|
if (shaderImporter == null) |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
File.WriteAllText(path, EditorJsonUtility.ToJson(graph, true)); |
|
|
|
shaderImporter.SaveAndReimport(); |
|
|
|
AssetDatabase.ImportAsset(path); |
|
|
|