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

409 行
15 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
using UnityEngine.Graphing;
using UnityEngine.MaterialGraph;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
namespace UnityEditor.MaterialGraph.Drawing
{
public interface IMaterialGraphEditWindow
{
void PingAsset();
void UpdateAsset();
void Repaint();
void ToggleRequiresTime();
void ToSubGraph();
void Show();
void Focus();
Object selected { get; set; }
void ChangeSelection(Object newSelection);
}
public abstract class HelperMaterialGraphEditWindow : EditorWindow, IMaterialGraphEditWindow
{
public abstract AbstractMaterialGraph GetMaterialGraph();
public abstract void PingAsset();
public abstract void UpdateAsset();
public abstract void ToggleRequiresTime();
public abstract void ToSubGraph();
public abstract Object selected { get; set; }
public abstract void ChangeSelection(Object newSelection);
}
public class MaterialGraphEditWindow : AbstractMaterialGraphEditWindow<UnityEngine.MaterialGraph.MaterialGraph>
{
public override AbstractMaterialGraph GetMaterialGraph()
{
return inMemoryAsset;
}
}
public class SubGraphEditWindow : AbstractMaterialGraphEditWindow<SubGraph>
{
public override AbstractMaterialGraph GetMaterialGraph()
{
return inMemoryAsset;
}
}
public abstract class AbstractMaterialGraphEditWindow<TGraphType> : HelperMaterialGraphEditWindow where TGraphType : AbstractMaterialGraph
{
public static bool allowAlwaysRepaint = true;
[SerializeField]
Object m_Selected;
[SerializeField]
TGraphType m_InMemoryAsset;
GraphEditorView m_GraphEditorView;
GraphEditorView graphEditorView
{
get { return m_GraphEditorView; }
set
{
if (m_GraphEditorView != null)
{
if (m_GraphEditorView.presenter != null)
m_GraphEditorView.presenter.Dispose();
m_GraphEditorView.Dispose();
}
m_GraphEditorView = value;
}
}
protected TGraphType inMemoryAsset
{
get { return m_InMemoryAsset; }
set { m_InMemoryAsset = value; }
}
public override Object selected
{
get { return m_Selected; }
set { m_Selected = value; }
}
void Update()
{
if (graphEditorView != null)
{
if (graphEditorView.presenter == null)
CreatePresenter();
if (graphEditorView.presenter != null)
graphEditorView.presenter.UpdatePreviews();
}
}
void OnEnable()
{
graphEditorView = new GraphEditorView();
rootVisualContainer.Add(graphEditorView);
}
void OnDisable()
{
rootVisualContainer.Clear();
graphEditorView = null;
}
void OnDestroy()
{
if (EditorUtility.DisplayDialog("Shader Graph Might Have Been Modified", "Do you want to save the changes you made in the shader graph?", "Save", "Don't Save"))
{
UpdateAsset();
}
graphEditorView = null;
}
void OnGUI()
{
var presenter = graphEditorView.presenter;
var e = Event.current;
if (e.type == EventType.ValidateCommand && (
e.commandName == "Copy" && presenter.graphPresenter.canCopy
|| e.commandName == "Paste" && presenter.graphPresenter.canPaste
|| e.commandName == "Duplicate" && presenter.graphPresenter.canDuplicate
|| e.commandName == "Cut" && presenter.graphPresenter.canCut
|| (e.commandName == "Delete" || e.commandName == "SoftDelete") && presenter.graphPresenter.canDelete))
{
e.Use();
}
if (e.type == EventType.ExecuteCommand)
{
if (e.commandName == "Copy")
presenter.graphPresenter.Copy();
if (e.commandName == "Paste")
presenter.graphPresenter.Paste();
if (e.commandName == "Duplicate")
presenter.graphPresenter.Duplicate();
if (e.commandName == "Cut")
presenter.graphPresenter.Cut();
if (e.commandName == "Delete" || e.commandName == "SoftDelete")
presenter.graphPresenter.Delete();
}
if (e.type == EventType.KeyDown)
{
if (e.keyCode == KeyCode.A)
graphEditorView.graphView.FrameAll();
if (e.keyCode == KeyCode.F)
graphEditorView.graphView.FrameSelection();
if (e.keyCode == KeyCode.O)
graphEditorView.graphView.FrameOrigin();
if (e.keyCode == KeyCode.Tab)
graphEditorView.graphView.FrameNext();
if (e.keyCode == KeyCode.Tab && e.modifiers == EventModifiers.Shift)
graphEditorView.graphView.FramePrev();
}
}
public override void PingAsset()
{
if (selected != null)
EditorGUIUtility.PingObject(selected);
}
public override void UpdateAsset()
{
if (selected != null && inMemoryAsset != null)
{
var path = AssetDatabase.GetAssetPath(selected);
if (string.IsNullOrEmpty(path) || inMemoryAsset == null)
{
return;
}
if (typeof(TGraphType) == typeof(UnityEngine.MaterialGraph.MaterialGraph))
UpdateShaderGraphOnDisk(path);
if (typeof(TGraphType) == typeof(SubGraph))
UpdateShaderSubGraphOnDisk(path);
}
}
public override void ToSubGraph()
{
string path = EditorUtility.SaveFilePanelInProject("Save subgraph", "New SubGraph", "ShaderSubGraph", "");
path = path.Replace(Application.dataPath, "Assets");
if (path.Length == 0)
return;
var graphPresenter = graphEditorView.presenter.graphPresenter;
var selected = graphPresenter.elements.Where(e => e.selected).ToArray();
var deserialized = MaterialGraphPresenter.DeserializeCopyBuffer(JsonUtility.ToJson(MaterialGraphPresenter.CreateCopyPasteGraph(selected)));
if (deserialized == null)
return;
var graph = new SubGraph();
graph.AddNode(new SubGraphInputNode());
graph.AddNode(new SubGraphOutputNode());
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.slotId);
var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
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 slotId = inputNode.AddSlot();
var outputSlotRef = new SlotReference(inputNode.guid, slotId);
foreach (var edge in group)
{
var newEdge = graph.Connect(outputSlotRef, new SlotReference(nodeGuidMap[edge.inputSlot.nodeGuid], edge.inputSlot.slotId));
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 slotId = outputNode.AddSlot();
var inputSlotRef = new SlotReference(outputNode.guid, slotId);
foreach (var edge in group)
{
var newEdge = graph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotId), inputSlotRef);
outputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge));
}
}
File.WriteAllText(path, EditorJsonUtility.ToJson(graph));
AssetDatabase.ImportAsset(path);
var subGraph = AssetDatabase.LoadAssetAtPath(path, typeof(MaterialSubGraphAsset)) as MaterialSubGraphAsset;
if (subGraph == null)
return;
var subGraphNode = new SubGraphNode();
graphPresenter.AddNode(subGraphNode);
subGraphNode.subGraphAsset = subGraph;
foreach (var edgeMap in inputsNeedingConnection)
{
graphPresenter.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.outputSlot.slotId));
}
foreach (var edgeMap in outputsNeedingConnection)
{
graphPresenter.graph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot);
}
var toDelete = graphPresenter.elements.Where(e => e.selected).OfType<MaterialNodePresenter>();
graphPresenter.RemoveElements(toDelete, new List<GraphEdgePresenter>());
}
private void UpdateShaderSubGraphOnDisk(string path)
{
var graph = inMemoryAsset as SubGraph;
if (graph == null)
return;
File.WriteAllText(path, EditorJsonUtility.ToJson(inMemoryAsset, true));
AssetDatabase.ImportAsset(path);
}
private void UpdateShaderGraphOnDisk(string path)
{
var graph = inMemoryAsset as UnityEngine.MaterialGraph.MaterialGraph;
if (graph == null)
return;
List<PropertyCollector.TextureInfo> configuredTextures = new List<PropertyCollector.TextureInfo>();
// graph.GetPreviewShader(graph.masterNode, GenerationMode.ForReals, Path.GetFileNameWithoutExtension(path), out configuredTextures);
var shaderImporter = AssetImporter.GetAtPath(path) as ShaderImporter;
if (shaderImporter == null)
return;
var textureNames = new List<string>();
var textures = new List<Texture>();
foreach (var textureInfo in configuredTextures.Where(x => x.modifiable))
{
var texture = EditorUtility.InstanceIDToObject(textureInfo.textureId) as Texture;
if (texture == null)
continue;
textureNames.Add(textureInfo.name);
textures.Add(texture);
}
shaderImporter.SetDefaultTextures(textureNames.ToArray(), textures.ToArray());
textureNames.Clear();
textures.Clear();
foreach (var textureInfo in configuredTextures.Where(x => !x.modifiable))
{
var texture = EditorUtility.InstanceIDToObject(textureInfo.textureId) as Texture;
if (texture == null)
continue;
textureNames.Add(textureInfo.name);
textures.Add(texture);
}
shaderImporter.SetNonModifiableTextures(textureNames.ToArray(), textures.ToArray());
File.WriteAllText(path, EditorJsonUtility.ToJson(inMemoryAsset, true));
shaderImporter.SaveAndReimport();
AssetDatabase.ImportAsset(path);
}
public override void ToggleRequiresTime()
{
allowAlwaysRepaint = !allowAlwaysRepaint;
}
public override void ChangeSelection(Object newSelection)
{
if (!EditorUtility.IsPersistent(newSelection))
return;
if (selected == newSelection)
return;
selected = newSelection;
var path = AssetDatabase.GetAssetPath(newSelection);
var textGraph = File.ReadAllText(path, Encoding.UTF8);
inMemoryAsset = JsonUtility.FromJson<TGraphType>(textGraph);
inMemoryAsset.OnEnable();
inMemoryAsset.ValidateGraph();
CreatePresenter();
titleContent = new GUIContent(selected.name);
Repaint();
}
void CreatePresenter()
{
if (graphEditorView.presenter != null)
graphEditorView.presenter.Dispose();
var presenter = CreateInstance<GraphEditorPresenter>();
presenter.Initialize(inMemoryAsset, this, selected.name);
graphEditorView.presenter = presenter;
graphEditorView.RegisterCallback<PostLayoutEvent>(OnPostLayout);
}
void OnPostLayout(PostLayoutEvent evt)
{
graphEditorView.UnregisterCallback<PostLayoutEvent>(OnPostLayout);
graphEditorView.graphView.FrameAll();
}
}
}