Tim Cooper
9 年前
当前提交
07060e1e
共有 9 个文件被更改,包括 0 次插入 和 617 次删除
-
102UnityProject/Assets/UnityShaderEditor/Editor/Source/Util/NodeUtils.cs
-
8UnityProject/Assets/UnityShaderEditor/Editor/Source/Util/NodeUtils.cs.meta
-
248UnityProject/Assets/UnityShaderEditor/Editor/Source/BaseMaterialGraph.cs
-
8UnityProject/Assets/UnityShaderEditor/Editor/Source/BaseMaterialGraph.cs.meta
-
30UnityProject/Assets/UnityShaderEditor/Editor/Source/Edge.cs
-
12UnityProject/Assets/UnityShaderEditor/Editor/Source/Edge.cs.meta
-
44UnityProject/Assets/UnityShaderEditor/Editor/Source/SlotReference.cs
-
12UnityProject/Assets/UnityShaderEditor/Editor/Source/SlotReference.cs.meta
-
153UnityProject/Assets/UnityShaderEditor/Editor/Source/SerializableGraph.cs
|
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
|
|||
namespace UnityEditor.MaterialGraph |
|||
{ |
|||
internal class NodeUtils |
|||
{ |
|||
// GetSlotsThatOutputToNodeRecurse returns a list of output slots on from node that
|
|||
// manage to connect to toNode... they may go via some other nodes to reach there.
|
|||
// This is done by working backwards from the toNode to the fromNode as graph is one directional
|
|||
public static List<SerializableSlot> GetSlotsThatOutputToNodeRecurse(SerializableNode fromNode, SerializableNode toNode) |
|||
{ |
|||
var foundUsedOutputSlots = new List<SerializableSlot>(); |
|||
RecurseNodesToFindValidOutputSlots(fromNode, toNode, foundUsedOutputSlots); |
|||
return foundUsedOutputSlots; |
|||
} |
|||
|
|||
public static void RecurseNodesToFindValidOutputSlots(SerializableNode fromNode, SerializableNode currentNode, ICollection<SerializableSlot> foundUsedOutputSlots) |
|||
{ |
|||
if (fromNode == null || currentNode == null) |
|||
{ |
|||
Debug.LogError("Recursing to find valid inputs on NULL node"); |
|||
return; |
|||
} |
|||
|
|||
var validSlots = ListPool<SerializableSlot>.Get(); |
|||
validSlots.AddRange(currentNode.inputSlots); |
|||
for (int index = 0; index < validSlots.Count; index++) |
|||
{ |
|||
var inputSlot = validSlots[index]; |
|||
var edges = currentNode.owner.GetEdges(inputSlot); |
|||
foreach (var edge in edges) |
|||
{ |
|||
var outputNode = currentNode.owner.GetNodeFromGuid(edge.outputSlot.nodeGuid); |
|||
var outputSlot = outputNode.FindOutputSlot(edge.outputSlot.slotName); |
|||
if (outputNode == fromNode && !foundUsedOutputSlots.Contains(outputSlot)) |
|||
foundUsedOutputSlots.Add(outputSlot); |
|||
else |
|||
RecurseNodesToFindValidOutputSlots(fromNode, outputNode, foundUsedOutputSlots); |
|||
} |
|||
} |
|||
ListPool<SerializableSlot>.Release(validSlots); |
|||
} |
|||
|
|||
public static void CollectChildNodesByExecutionOrder(List<SerializableNode> nodeList, SerializableNode node, SerializableSlot slotToUse) |
|||
{ |
|||
if (node == null) |
|||
return; |
|||
|
|||
if (nodeList.Contains(node)) |
|||
return; |
|||
|
|||
var validSlots = ListPool<SerializableSlot>.Get(); |
|||
validSlots.AddRange(node.inputSlots); |
|||
if (slotToUse != null && !validSlots.Contains(slotToUse)) |
|||
{ |
|||
ListPool<SerializableSlot>.Release(validSlots); |
|||
return; |
|||
} |
|||
|
|||
if (slotToUse != null) |
|||
{ |
|||
validSlots.Clear(); |
|||
validSlots.Add(slotToUse); |
|||
} |
|||
|
|||
for (int index = 0; index < validSlots.Count; index++) |
|||
{ |
|||
var slot = validSlots[index]; |
|||
|
|||
var edges = node.owner.GetEdges(slot); |
|||
foreach (var edge in edges) |
|||
{ |
|||
var outputNode = node.owner.GetNodeFromGuid(edge.outputSlot.nodeGuid); |
|||
CollectChildNodesByExecutionOrder(nodeList, outputNode, null); |
|||
} |
|||
} |
|||
|
|||
nodeList.Add(node); |
|||
ListPool<SerializableSlot>.Release(validSlots); |
|||
} |
|||
|
|||
public static void CollectDependentNodes(List<SerializableNode> nodeList, SerializableNode node) |
|||
{ |
|||
if (node == null) |
|||
return; |
|||
|
|||
if (nodeList.Contains(node)) |
|||
return; |
|||
|
|||
foreach (var slot in node.outputSlots) |
|||
{ |
|||
foreach (var edge in node.owner.GetEdges(slot)) |
|||
{ |
|||
var inputNode = node.owner.GetNodeFromGuid(edge.inputSlot.nodeGuid); |
|||
CollectDependentNodes(nodeList, inputNode); |
|||
} |
|||
} |
|||
nodeList.Add(node); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 992a8f404953a8248b943cb6fb0b2c79 |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
|
|||
namespace UnityEditor.MaterialGraph |
|||
{ |
|||
[Serializable] |
|||
public abstract class BaseMaterialGraph : ISerializationCallbackReceiver |
|||
{ |
|||
[SerializeField] |
|||
private List<Edge> m_Edges = new List<Edge>(); |
|||
|
|||
[SerializeField] |
|||
private List<BaseMaterialNode> m_Nodes = new List<BaseMaterialNode>(); |
|||
|
|||
private PreviewRenderUtility m_PreviewUtility; |
|||
|
|||
private MaterialGraph m_Owner; |
|||
|
|||
public BaseMaterialGraph(MaterialGraph owner) |
|||
{ |
|||
m_Owner = owner; |
|||
} |
|||
|
|||
public IEnumerable<BaseMaterialNode> nodes { get { return m_Nodes; } } |
|||
public IEnumerable<Edge> edges { get { return m_Edges; } } |
|||
|
|||
public PreviewRenderUtility previewUtility |
|||
{ |
|||
get |
|||
{ |
|||
if (m_PreviewUtility == null) |
|||
{ |
|||
m_PreviewUtility = new PreviewRenderUtility(); |
|||
// EditorUtility.SetCameraAnimateMaterials(m_PreviewUtility.m_Camera, true);
|
|||
} |
|||
|
|||
return m_PreviewUtility; |
|||
} |
|||
} |
|||
|
|||
public bool requiresRepaint |
|||
{ |
|||
get { return m_Nodes.Any(x => x is IRequiresTime); } |
|||
} |
|||
|
|||
public MaterialGraph owner |
|||
{ |
|||
get { return m_Owner; } |
|||
} |
|||
|
|||
public void RemoveEdge(Edge e) |
|||
{ |
|||
m_Edges.Remove(e); |
|||
RevalidateGraph(); |
|||
} |
|||
|
|||
public void RemoveEdgeNoRevalidate(Edge e) |
|||
{ |
|||
m_Edges.Remove(e); |
|||
} |
|||
|
|||
public void RemoveNode(BaseMaterialNode node) |
|||
{ |
|||
if (!node.canDeleteNode) |
|||
return; |
|||
|
|||
m_Nodes.Remove(node); |
|||
RevalidateGraph(); |
|||
} |
|||
|
|||
public void RemoveNodeNoRevalidate(BaseMaterialNode node) |
|||
{ |
|||
if (!node.canDeleteNode) |
|||
return; |
|||
|
|||
m_Nodes.Remove(node); |
|||
} |
|||
|
|||
public BaseMaterialNode GetNodeFromGUID(Guid guid) |
|||
{ |
|||
return m_Nodes.FirstOrDefault(x => x.guid == guid); |
|||
} |
|||
|
|||
public IEnumerable<Edge> GetEdges(Slot s) |
|||
{ |
|||
return m_Edges.Where(x => |
|||
(x.outputSlot.nodeGuid == s.owner.guid && x.outputSlot.slotName == s.name) |
|||
|| x.inputSlot.nodeGuid == s.owner.guid && x.inputSlot.slotName == s.name); |
|||
} |
|||
|
|||
public Edge Connect(Slot fromSlot, Slot toSlot) |
|||
{ |
|||
Slot outputSlot = null; |
|||
Slot inputSlot = null; |
|||
|
|||
// output must connect to input
|
|||
if (fromSlot.isOutputSlot) |
|||
outputSlot = fromSlot; |
|||
else if (fromSlot.isInputSlot) |
|||
inputSlot = fromSlot; |
|||
|
|||
if (toSlot.isOutputSlot) |
|||
outputSlot = toSlot; |
|||
else if (toSlot.isInputSlot) |
|||
inputSlot = toSlot; |
|||
|
|||
if (inputSlot == null || outputSlot == null) |
|||
return null; |
|||
|
|||
var edges = GetEdges(inputSlot).ToList(); |
|||
// remove any inputs that exits before adding
|
|||
foreach (var edge in edges) |
|||
{ |
|||
Debug.Log("Removing existing edge:" + edge); |
|||
// call base here as we DO NOT want to
|
|||
// do expensive shader regeneration
|
|||
RemoveEdge(edge); |
|||
} |
|||
|
|||
var newEdge = new Edge(new SlotReference(outputSlot.owner.guid, outputSlot.name), new SlotReference(inputSlot.owner.guid, inputSlot.name)); |
|||
m_Edges.Add(newEdge); |
|||
|
|||
Debug.Log("Connected edge: " + newEdge); |
|||
RevalidateGraph(); |
|||
return newEdge; |
|||
} |
|||
|
|||
public virtual void RevalidateGraph() |
|||
{ |
|||
//First validate edges, remove any
|
|||
//orphans. This can happen if a user
|
|||
//manually modifies serialized data
|
|||
//of if they delete a node in the inspector
|
|||
//debug view.
|
|||
var allNodeGUIDs = m_Nodes.Select(x => x.guid).ToList(); |
|||
|
|||
foreach (var edge in edges.ToArray()) |
|||
{ |
|||
if (allNodeGUIDs.Contains(edge.inputSlot.nodeGuid) && allNodeGUIDs.Contains(edge.outputSlot.nodeGuid)) |
|||
continue; |
|||
|
|||
//orphaned edge
|
|||
m_Edges.Remove(edge); |
|||
} |
|||
|
|||
var bmns = m_Nodes.Where(x => x is BaseMaterialNode).ToList(); |
|||
|
|||
foreach (var node in bmns) |
|||
node.ValidateNode(); |
|||
} |
|||
|
|||
public void AddNode(BaseMaterialNode node) |
|||
{ |
|||
m_Nodes.Add(node); |
|||
RevalidateGraph(); |
|||
} |
|||
|
|||
private void AddNodeNoValidate(BaseMaterialNode node) |
|||
{ |
|||
m_Nodes.Add(node); |
|||
} |
|||
|
|||
private static string GetTypeSerializableAsString(Type type) |
|||
{ |
|||
if (type == null) |
|||
return string.Empty; |
|||
|
|||
return string.Format("{0}, {1}", type.FullName, type.Assembly.GetName().Name); |
|||
} |
|||
|
|||
private static Type GetTypeFromSerializedString(string type) |
|||
{ |
|||
if (string.IsNullOrEmpty(type)) |
|||
return null; |
|||
|
|||
return Type.GetType(type); |
|||
} |
|||
|
|||
[Serializable] |
|||
struct SerializableNode |
|||
{ |
|||
[SerializeField] |
|||
public string typeName; |
|||
|
|||
[SerializeField] |
|||
public string JSONnodeData; |
|||
} |
|||
|
|||
[SerializeField] |
|||
List<SerializableNode> m_SerializableNodes = new List<SerializableNode>(); |
|||
public void OnBeforeSerialize() |
|||
{ |
|||
m_SerializableNodes.Clear(); |
|||
|
|||
foreach (var node in nodes) |
|||
{ |
|||
if (node == null) |
|||
continue; |
|||
|
|||
var typeName = GetTypeSerializableAsString(node.GetType()); |
|||
var data = JsonUtility.ToJson(node, true); |
|||
|
|||
if (string.IsNullOrEmpty(typeName) || string.IsNullOrEmpty(data)) |
|||
continue; |
|||
|
|||
m_SerializableNodes.Add( new SerializableNode() |
|||
{ |
|||
typeName = typeName, |
|||
JSONnodeData = data |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public void OnAfterDeserialize() |
|||
{ |
|||
m_Nodes.Clear(); |
|||
foreach (var serializedNode in m_SerializableNodes) |
|||
{ |
|||
if (string.IsNullOrEmpty(serializedNode.typeName) || string.IsNullOrEmpty(serializedNode.JSONnodeData)) |
|||
continue; |
|||
|
|||
var type = GetTypeFromSerializedString(serializedNode.typeName); |
|||
if (type == null) |
|||
{ |
|||
Debug.LogWarningFormat("Could not find node of type {0} in loaded assemblies", serializedNode.typeName); |
|||
continue; |
|||
} |
|||
|
|||
BaseMaterialNode node; |
|||
try |
|||
{ |
|||
var constructorInfo = type.GetConstructor(new[] { typeof(BaseMaterialGraph) }); |
|||
node = (BaseMaterialNode)constructorInfo.Invoke(new object[] { this }); |
|||
} |
|||
catch |
|||
{ |
|||
Debug.LogWarningFormat("Could not construct instance of: {0} as there is no single argument constuctor that takes a BaseMaterialGraph", type); |
|||
continue; |
|||
} |
|||
JsonUtility.FromJsonOverwrite(serializedNode.JSONnodeData, node); |
|||
AddNodeNoValidate(node); |
|||
} |
|||
RevalidateGraph(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 6567c9f37c0aaa94e9083ffc63612ecf |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|
|||
using System; |
|||
using UnityEngine; |
|||
|
|||
namespace UnityEditor.MaterialGraph |
|||
{ |
|||
[Serializable] |
|||
public class Edge |
|||
{ |
|||
[SerializeField] |
|||
private SlotReference m_OutputSlot; |
|||
[SerializeField] |
|||
private SlotReference m_InputSlot; |
|||
|
|||
public Edge(SlotReference outputSlot, SlotReference inputSlot) |
|||
{ |
|||
m_OutputSlot = outputSlot; |
|||
m_InputSlot = inputSlot; |
|||
} |
|||
|
|||
public SlotReference outputSlot |
|||
{ |
|||
get { return m_OutputSlot; } |
|||
} |
|||
|
|||
public SlotReference inputSlot |
|||
{ |
|||
get { return m_InputSlot; } |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 6b610a05c25f54d4c90f7ebf82696481 |
|||
timeCreated: 1463576280 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using UnityEngine; |
|||
|
|||
namespace UnityEditor.MaterialGraph |
|||
{ |
|||
[Serializable] |
|||
public class SlotReference : ISerializationCallbackReceiver |
|||
{ |
|||
[SerializeField] |
|||
private string m_SlotName; |
|||
|
|||
[NonSerialized] |
|||
private Guid m_NodeGUID; |
|||
|
|||
[SerializeField] |
|||
private string m_NodeGUIDSerialized; |
|||
|
|||
public SlotReference(Guid nodeGuid, string slotName) |
|||
{ |
|||
m_NodeGUID = nodeGuid; |
|||
m_SlotName = slotName; |
|||
} |
|||
|
|||
public Guid nodeGuid |
|||
{ |
|||
get { return m_NodeGUID; } |
|||
} |
|||
|
|||
public string slotName |
|||
{ |
|||
get { return m_SlotName; } |
|||
} |
|||
|
|||
public void OnBeforeSerialize() |
|||
{ |
|||
m_NodeGUIDSerialized = m_NodeGUID.ToString(); |
|||
} |
|||
|
|||
public void OnAfterDeserialize() |
|||
{ |
|||
m_NodeGUID = new Guid(m_NodeGUIDSerialized); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a178e14960be0e944b4652535f2d12e4 |
|||
timeCreated: 1463576280 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
|
|||
namespace UnityEditor.MaterialGraph |
|||
{ |
|||
[Serializable] |
|||
public class SerializableGraph : ISerializationCallbackReceiver |
|||
{ |
|||
[SerializeField] |
|||
private List<Edge> m_Edges = new List<Edge>(); |
|||
|
|||
[NonSerialized] |
|||
private List<SerializableNode> m_Nodes = new List<SerializableNode>(); |
|||
|
|||
[SerializeField] |
|||
List<SerializationHelper.JSONSerializedElement> m_SerializableNodes = new List<SerializationHelper.JSONSerializedElement>(); |
|||
|
|||
public IEnumerable<SerializableNode> nodes |
|||
{ |
|||
get { return m_Nodes; } |
|||
} |
|||
|
|||
public IEnumerable<Edge> edges |
|||
{ |
|||
get { return m_Edges; } |
|||
} |
|||
|
|||
public virtual void AddNode(SerializableNode node) |
|||
{ |
|||
m_Nodes.Add(node); |
|||
ValidateGraph(); |
|||
} |
|||
|
|||
public virtual void RemoveNode(SerializableNode node) |
|||
{ |
|||
if (!node.canDeleteNode) |
|||
return; |
|||
|
|||
m_Nodes.Remove(node); |
|||
ValidateGraph(); |
|||
} |
|||
|
|||
private void RemoveNodeNoValidate(SerializableNode node) |
|||
{ |
|||
if (!node.canDeleteNode) |
|||
return; |
|||
|
|||
m_Nodes.Remove(node); |
|||
} |
|||
|
|||
public virtual Edge Connect(SerializableSlot fromSlot, SerializableSlot toSlot) |
|||
{ |
|||
SerializableSlot outputSlot = null; |
|||
SerializableSlot inputSlot = null; |
|||
|
|||
// output must connect to input
|
|||
if (fromSlot.isOutputSlot) |
|||
outputSlot = fromSlot; |
|||
else if (fromSlot.isInputSlot) |
|||
inputSlot = fromSlot; |
|||
|
|||
if (toSlot.isOutputSlot) |
|||
outputSlot = toSlot; |
|||
else if (toSlot.isInputSlot) |
|||
inputSlot = toSlot; |
|||
|
|||
if (inputSlot == null || outputSlot == null) |
|||
return null; |
|||
|
|||
var edges = GetEdges(inputSlot).ToList(); |
|||
// remove any inputs that exits before adding
|
|||
foreach (var edge in edges) |
|||
{ |
|||
Debug.Log("Removing existing edge:" + edge); |
|||
// call base here as we DO NOT want to
|
|||
// do expensive shader regeneration
|
|||
RemoveEdge(edge); |
|||
} |
|||
|
|||
var newEdge = new Edge(new SlotReference(outputSlot.owner.guid, outputSlot.name), new SlotReference(inputSlot.owner.guid, inputSlot.name)); |
|||
m_Edges.Add(newEdge); |
|||
|
|||
Debug.Log("Connected edge: " + newEdge); |
|||
return newEdge; |
|||
} |
|||
|
|||
public virtual void RemoveEdge(Edge e) |
|||
{ |
|||
m_Edges.Remove(e); |
|||
ValidateGraph(); |
|||
} |
|||
|
|||
public void RemoveElements(IEnumerable<SerializableNode> nodes, IEnumerable<Edge> edges) |
|||
{ |
|||
foreach (var edge in edges) |
|||
RemoveEdgeNoValidate(edge); |
|||
|
|||
foreach (var serializableNode in nodes) |
|||
RemoveNodeNoValidate(serializableNode); |
|||
|
|||
ValidateGraph(); |
|||
} |
|||
|
|||
private void RemoveEdgeNoValidate(Edge e) |
|||
{ |
|||
m_Edges.Remove(e); |
|||
} |
|||
|
|||
public SerializableNode GetNodeFromGuid(Guid guid) |
|||
{ |
|||
return m_Nodes.FirstOrDefault(x => x.guid == guid); |
|||
} |
|||
|
|||
public IEnumerable<Edge> GetEdges(SerializableSlot s) |
|||
{ |
|||
return m_Edges.Where(x => |
|||
(x.outputSlot.nodeGuid == s.owner.guid && x.outputSlot.slotName == s.name) |
|||
|| x.inputSlot.nodeGuid == s.owner.guid && x.inputSlot.slotName == s.name); |
|||
} |
|||
|
|||
public virtual void OnBeforeSerialize() |
|||
{ |
|||
m_SerializableNodes = SerializationHelper.Serialize(m_Nodes); |
|||
} |
|||
|
|||
public virtual void OnAfterDeserialize() |
|||
{ |
|||
m_Nodes = SerializationHelper.Deserialize<SerializableNode>(m_SerializableNodes, new object[] {this}); |
|||
m_SerializableNodes = null; |
|||
} |
|||
|
|||
public virtual void ValidateGraph() |
|||
{ |
|||
//First validate edges, remove any
|
|||
//orphans. This can happen if a user
|
|||
//manually modifies serialized data
|
|||
//of if they delete a node in the inspector
|
|||
//debug view.
|
|||
var allNodeGUIDs = nodes.Select(x => x.guid).ToList(); |
|||
|
|||
foreach (var edge in edges.ToArray()) |
|||
{ |
|||
if (allNodeGUIDs.Contains(edge.inputSlot.nodeGuid) && allNodeGUIDs.Contains(edge.outputSlot.nodeGuid)) |
|||
continue; |
|||
|
|||
//orphaned edge
|
|||
RemoveEdgeNoValidate(edge); |
|||
} |
|||
} |
|||
} |
|||
} |
撰写
预览
正在加载...
取消
保存
Reference in new issue