您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

393 行
16 KiB

using System;
using UnityEngine.MaterialGraph;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEditor.Graphing.Util;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Graphing;
using Debug = System.Diagnostics.Debug;
namespace UnityEditor.MaterialGraph.Drawing
{
[Serializable]
public class MaterialGraphPresenter : GraphViewPresenter
{
GraphTypeMapper typeMapper { get; set; }
PreviewSystem m_PreviewSystem;
public IGraph graph { get; private set; }
[SerializeField]
IMaterialGraphEditWindow m_Container;
protected MaterialGraphPresenter()
{
typeMapper = new GraphTypeMapper(typeof(MaterialNodePresenter));
typeMapper[typeof(AbstractMaterialNode)] = typeof(MaterialNodePresenter);
typeMapper[typeof(ColorNode)] = typeof(ColorNodePresenter);
typeMapper[typeof(GradientNode)] = typeof(GradientNodePresenter);
// typeMapper[typeof(ScatterNode)] = typeof(ScatterNodePresenter);
//typeMapper[typeof(TextureNode)] = typeof(TextureNodePresenter);
//typeMapper[typeof(SamplerAssetNode)] = typeof(SamplerAssetNodePresenter);
//typeMapper[typeof(TextureSamplerNode)] = typeof(TextureSamplerNodePresenter);
// typeMapper[typeof(Texture2DNode)] = typeof(TextureAssetNodePresenter);
// typeMapper[typeof(TextureLODNode)] = typeof(TextureLODNodePresenter);
typeMapper[typeof(SamplerStateNode)] = typeof(SamplerStateNodePresenter);
// typeMapper[typeof(CubemapNode)] = typeof(CubeNodePresenter);
// typeMapper[typeof(ToggleNode)] = typeof(ToggleNodePresenter);
typeMapper[typeof(UVNode)] = typeof(UVNodePresenter);
typeMapper[typeof(Vector1Node)] = typeof(Vector1NodePresenter);
typeMapper[typeof(Vector2Node)] = typeof(Vector2NodePresenter);
typeMapper[typeof(Vector3Node)] = typeof(Vector3NodePresenter);
typeMapper[typeof(Vector4Node)] = typeof(Vector4NodePresenter);
typeMapper[typeof(PropertyNode)] = typeof(PropertyNodePresenter);
/* typeMapper[typeof(ScaleOffsetNode)] = typeof(AnyNodePresenter); // anything derived from AnyNode should use the AnyNodePresenter
typeMapper[typeof(RadialShearNode)] = typeof(AnyNodePresenter); // anything derived from AnyNode should use the AnyNodePresenter
typeMapper[typeof(SphereWarpNode)] = typeof(AnyNodePresenter); // anything derived from AnyNode should use the AnyNodePresenter
typeMapper[typeof(SphericalIndentationNode)] = typeof(AnyNodePresenter); // anything derived from AnyNode should use the AnyNodePresenter
typeMapper[typeof(AACheckerboardNode)] = typeof(AnyNodePresenter); // anything derived from AnyNode should use the AnyNodePresenter
typeMapper[typeof(AACheckerboard3dNode)] = typeof(AnyNodePresenter); // anything derived from AnyNode should use the AnyNodePresenter*/
typeMapper[typeof(SubGraphNode)] = typeof(SubgraphNodePresenter);
typeMapper[typeof(MasterRemapNode)] = typeof(MasterRemapNodePresenter);
// typeMapper[typeof(MasterRemapInputNode)] = typeof(RemapInputNodePresenter);
typeMapper[typeof(AbstractSubGraphIONode)] = typeof(SubgraphIONodePresenter);
// typeMapper[typeof(AbstractSurfaceMasterNode)] = typeof(SurfaceMasterNodePresenter);
typeMapper[typeof(LevelsNode)] = typeof(LevelsNodePresenter);
typeMapper[typeof(ConstantsNode)] = typeof(ConstantsNodePresenter);
//typeMapper[typeof(SwizzleNode)] = typeof(SwizzleNodePresenter);
typeMapper[typeof(BlendModeNode)] = typeof(BlendModeNodePresenter);
// typeMapper[typeof(AddManyNode)] = typeof(AddManyNodePresenter);
typeMapper[typeof(IfNode)] = typeof(IfNodePresenter);
//typeMapper[typeof(CustomCodeNode)] = typeof(CustomCodePresenter);
typeMapper[typeof(Matrix2Node)] = typeof(Matrix2NodePresenter);
typeMapper[typeof(Matrix3Node)] = typeof(Matrix3NodePresenter);
typeMapper[typeof(Matrix4Node)] = typeof(Matrix4NodePresenter);
typeMapper[typeof(MatrixCommonNode)] = typeof(MatrixCommonNodePresenter);
typeMapper[typeof(TransformNode)] = typeof(TransformNodePresenter);
// typeMapper[typeof(ConvolutionFilterNode)] = typeof(ConvolutionFilterNodePresenter);
}
public override List<NodeAnchorPresenter> GetCompatibleAnchors(NodeAnchorPresenter startAnchor, NodeAdapter nodeAdapter)
{
var compatibleAnchors = new List<NodeAnchorPresenter>();
var startAnchorPresenter = startAnchor as GraphAnchorPresenter;
if (startAnchorPresenter == null)
return compatibleAnchors;
var startSlot = startAnchorPresenter.slot as MaterialSlot;
if (startSlot == null)
return compatibleAnchors;
var goingBackwards = startSlot.isOutputSlot;
var startStage = startSlot.shaderStage;
if (startStage == ShaderStage.Dynamic)
startStage = NodeUtils.FindEffectiveShaderStage(startSlot.owner, startSlot.isOutputSlot);
foreach (var candidateAnchorPresenter in allChildren.OfType<GraphAnchorPresenter>())
{
if (!candidateAnchorPresenter.IsConnectable())
continue;
if (candidateAnchorPresenter.orientation != startAnchor.orientation)
continue;
if (candidateAnchorPresenter.direction == startAnchor.direction)
continue;
if (nodeAdapter.GetAdapter(candidateAnchorPresenter.source, startAnchor.source) == null)
continue;
var candidateSlot = candidateAnchorPresenter.slot as MaterialSlot;
if (candidateSlot == null)
continue;
if (candidateSlot.owner == startSlot.owner)
continue;
if (!startSlot.IsCompatibleWithInputSlotType(candidateSlot.valueType))
continue;
if (startStage != ShaderStage.Dynamic)
{
var candidateStage = candidateSlot.shaderStage;
if (candidateStage == ShaderStage.Dynamic)
candidateStage = NodeUtils.FindEffectiveShaderStage(candidateSlot.owner, !startSlot.isOutputSlot);
if (candidateStage != ShaderStage.Dynamic && candidateStage != startStage)
continue;
}
compatibleAnchors.Add(candidateAnchorPresenter);
}
return compatibleAnchors;
}
void OnNodeChanged(INode inNode, ModificationScope scope)
{
var dependentNodes = new List<INode>();
NodeUtils.CollectNodesNodeFeedsInto(dependentNodes, inNode);
foreach (var node in dependentNodes)
{
var theElements = m_Elements.OfType<MaterialNodePresenter>().ToList();
var found = theElements.Where(x => x.node.guid == node.guid).ToList();
foreach (var drawableNodeData in found)
drawableNodeData.OnModified(scope);
}
// We might need to do something here
// if (scope == ModificationScope.Topological)
}
public virtual void Initialize(IGraph graph, IMaterialGraphEditWindow container, PreviewSystem previewSystem)
{
m_PreviewSystem = previewSystem;
this.graph = graph;
m_Container = container;
if (graph == null)
return;
foreach (var node in graph.GetNodes<INode>())
NodeAdded(new NodeAddedGraphChange(node));
foreach (var edge in graph.edges)
EdgeAdded(new EdgeAddedGraphChange(edge));
this.graph.onChange += OnChange;
}
void OnChange(GraphChange change)
{
change.Match(NodeAdded, NodeRemoved, EdgeAdded, EdgeRemoved);
}
void NodeAdded(NodeAddedGraphChange change)
{
var nodePresenter = (MaterialNodePresenter)typeMapper.Create(change.node);
change.node.onModified += OnNodeChanged;
nodePresenter.Initialize(change.node, m_PreviewSystem);
m_Elements.Add(nodePresenter);
}
void NodeRemoved(NodeRemovedGraphChange change)
{
change.node.onModified -= OnNodeChanged;
var nodePresenter = m_Elements.OfType<MaterialNodePresenter>().FirstOrDefault(p => p.node.guid == change.node.guid);
if (nodePresenter != null)
m_Elements.Remove(nodePresenter);
}
void EdgeAdded(EdgeAddedGraphChange change)
{
var edge = change.edge;
var sourceNode = graph.GetNodeFromGuid(edge.outputSlot.nodeGuid);
var sourceSlot = sourceNode.FindOutputSlot<ISlot>(edge.outputSlot.slotId);
var sourceNodePresenter = m_Elements.OfType<MaterialNodePresenter>().FirstOrDefault(x => x.node == sourceNode);
var sourceAnchorPresenter = sourceNodePresenter.outputAnchors.OfType<GraphAnchorPresenter>().FirstOrDefault(x => x.slot == sourceSlot);
var targetNode = graph.GetNodeFromGuid(edge.inputSlot.nodeGuid);
var targetSlot = targetNode.FindInputSlot<ISlot>(edge.inputSlot.slotId);
var targetNodePresenter = m_Elements.OfType<MaterialNodePresenter>().FirstOrDefault(x => x.node == targetNode);
var targetAnchor = targetNodePresenter.inputAnchors.OfType<GraphAnchorPresenter>().FirstOrDefault(x => x.slot == targetSlot);
var edgePresenter = CreateInstance<GraphEdgePresenter>();
edgePresenter.Initialize(edge);
edgePresenter.output = sourceAnchorPresenter;
edgePresenter.output.Connect(edgePresenter);
edgePresenter.input = targetAnchor;
edgePresenter.input.Connect(edgePresenter);
m_Elements.Add(edgePresenter);
}
void EdgeRemoved(EdgeRemovedGraphChange change)
{
var edgePresenter = m_Elements.OfType<GraphEdgePresenter>().FirstOrDefault(p => p.edge == change.edge);
if (edgePresenter != null)
{
edgePresenter.output.Disconnect(edgePresenter);
edgePresenter.input.Disconnect(edgePresenter);
m_Elements.Remove(edgePresenter);
}
}
public void AddNode(INode node)
{
graph.AddNode(node);
}
public void RemoveElements(IEnumerable<MaterialNodePresenter> nodes, IEnumerable<GraphEdgePresenter> edges)
{
graph.RemoveElements(nodes.Select(x => x.node as INode), edges.Select(x => x.edge));
graph.ValidateGraph();
}
public void Connect(GraphAnchorPresenter left, GraphAnchorPresenter right)
{
if (left != null && right != null)
{
graph.Connect(left.slot.slotReference, right.slot.slotReference);
}
}
internal static CopyPasteGraph CreateCopyPasteGraph(IEnumerable<GraphElementPresenter> selection)
{
var graph = new CopyPasteGraph();
foreach (var presenter in selection)
{
var nodePresenter = presenter as MaterialNodePresenter;
if (nodePresenter != null)
{
graph.AddNode(nodePresenter.node);
foreach (var edge in NodeUtils.GetAllEdges(nodePresenter.node))
graph.AddEdge(edge);
}
var edgePresenter = presenter as GraphEdgePresenter;
if (edgePresenter != null)
graph.AddEdge(edgePresenter.edge);
}
return graph;
}
internal static CopyPasteGraph DeserializeCopyBuffer(string copyBuffer)
{
try
{
return JsonUtility.FromJson<CopyPasteGraph>(copyBuffer);
}
catch
{
// ignored. just means copy buffer was not a graph :(
return null;
}
}
void InsertCopyPasteGraph(CopyPasteGraph copyGraph)
{
if (copyGraph == null || graph == null)
return;
var addedNodes = new List<INode>();
var nodeGuidMap = new Dictionary<Guid, Guid>();
foreach (var node in copyGraph.GetNodes<INode>())
{
var oldGuid = node.guid;
var newGuid = node.RewriteGuid();
nodeGuidMap[oldGuid] = newGuid;
var drawState = node.drawState;
var position = drawState.position;
position.x += 30;
position.y += 30;
drawState.position = position;
node.drawState = drawState;
graph.AddNode(node);
addedNodes.Add(node);
}
// only connect edges within pasted elements, discard
// external edges.
foreach (var edge in copyGraph.edges)
{
var outputSlot = edge.outputSlot;
var inputSlot = edge.inputSlot;
Guid remappedOutputNodeGuid;
Guid remappedInputNodeGuid;
if (nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid)
&& nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid))
{
var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId);
var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
graph.Connect(outputSlotRef, inputSlotRef);
}
}
graph.ValidateGraph();
if (onSelectionChanged != null)
onSelectionChanged(addedNodes);
}
public bool canCopy
{
get { return elements.Any(e => e.selected); }
}
public void Copy()
{
var graph = CreateCopyPasteGraph(elements.Where(e => e.selected));
EditorGUIUtility.systemCopyBuffer = JsonUtility.ToJson(graph, true);
}
public bool canCut
{
get { return canCopy; }
}
public void Cut()
{
Copy();
RemoveElements(elements.OfType<MaterialNodePresenter>().Where(e => e.selected), elements.OfType<GraphEdgePresenter>().Where(e => e.selected));
}
public bool canPaste
{
get { return DeserializeCopyBuffer(EditorGUIUtility.systemCopyBuffer) != null; }
}
public void Paste()
{
var pastedGraph = DeserializeCopyBuffer(EditorGUIUtility.systemCopyBuffer);
InsertCopyPasteGraph(pastedGraph);
}
public bool canDuplicate
{
get { return canCopy; }
}
public void Duplicate()
{
var graph = DeserializeCopyBuffer(JsonUtility.ToJson(CreateCopyPasteGraph(elements.Where(e => e.selected)), true));
InsertCopyPasteGraph(graph);
}
public bool canDelete
{
get { return canCopy; }
}
public void Delete()
{
RemoveElements(elements.OfType<MaterialNodePresenter>().Where(e => e.selected), elements.OfType<GraphEdgePresenter>().Where(e => e.selected));
}
public override void AddElement(EdgePresenter edge)
{
Connect(edge.output as GraphAnchorPresenter, edge.input as GraphAnchorPresenter);
}
public delegate void OnSelectionChanged(IEnumerable<INode> presenters);
public OnSelectionChanged onSelectionChanged;
public void UpdateSelection(IEnumerable<MaterialNodePresenter> presenters)
{
if (graph == null)
return;
if (onSelectionChanged != null)
onSelectionChanged(presenters.Select(x => x.node as INode));
}
public override void AddElement(GraphElementPresenter element)
{
throw new ArgumentException("Not supported on Serializable Graph, data comes from data store");
}
public override void RemoveElement(GraphElementPresenter element)
{
throw new ArgumentException("Not supported on Serializable Graph, data comes from data store");
}
}
}