浏览代码

A bunch of stuff for blackboard

- Fix SelectionDropper, so that selection of properties work
- Hack in a ContextualMenuManipulator so that context menus work in collaboration with GraphView
- Add a "Delete" option to context menu for properties
- Only show context menu options for nodes if a node or GV is right-clicked
- When adding a new property it is now expanding initially
- Rename a few Action properties to match GraphView convention
- Add a regular Unity toolbar (using IMGUI) to Shader Graph, as it looked weird without one
- Remove old inspector
/main
Peter Bay Bastian 7 年前
当前提交
1749ff66
共有 5 个文件被更改,包括 64 次插入90 次删除
  1. 25
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Blackboard/BlackboardField.cs
  2. 15
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Blackboard/BlackboardProvider.cs
  3. 6
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/MaterialGraphEditWindow.cs
  4. 86
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/GraphEditorView.cs
  5. 22
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/MaterialGraphView.cs

25
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Blackboard/BlackboardField.cs


using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
using Debug = System.Diagnostics.Debug;
namespace UnityEditor.ShaderGraph.Drawing
{

public BlackboardField()
: this(null, "", "") { }
static Type s_ContextualMenuManipulator = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).FirstOrDefault(t => t.FullName == "UnityEngine.Experimental.UIElements.ContextualMenuManipulator");
public BlackboardField(Texture icon, string text, string typeText)
{
var tpl = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/UnityShaderEditor/Editor/Resources/UXML/GraphView/BlackboardField.uxml");

this.typeText = typeText;
m_SelectionDropper = new SelectionDropper(Handler);
typeof(SelectionDropper).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(f => f.Name == "m_Active").SetValue(m_SelectionDropper, false);
// Workaround bug causing SelectionDropper to not work (m_Active should be initialized to false rather than true)
var activeFieldInfo = typeof(SelectionDropper).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(f => f.Name == "m_Active");
Debug.Assert(activeFieldInfo != null, "activeFieldInfo != null");
activeFieldInfo.SetValue(m_SelectionDropper, false);
RegisterCallback<MouseUpEvent>(OnMouseUp);
var contextualMenuManipulator = (IManipulator)Activator.CreateInstance(s_ContextualMenuManipulator, (Action<ContextualMenuPopulateEvent>)BuildContextualMenu);
this.AddManipulator(contextualMenuManipulator);
void OnMouseUp(MouseUpEvent evt)
void BuildContextualMenu(ContextualMenuPopulateEvent evt)
if (evt.button == 1)
{
var gm = new GenericMenu();
gm.AddItem(new GUIContent("Rename"), false, RenameGo);
gm.ShowAsContext();
evt.StopPropagation();
evt.PreventDefault();
}
evt.menu.AppendAction("Rename", e => RenameGo(), ContextualMenu.MenuAction.AlwaysEnabled);
}
void Handler(IMGUIEvent evt, List<ISelectable> selection, IDropTarget dropTarget)

15
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Blackboard/BlackboardProvider.cs


readonly Dictionary<Guid, BlackboardRow> m_PropertyRows;
readonly BlackboardSection m_Section;
public Blackboard blackboard { get; private set; }
public Action updateAssetRequested { get; set; }
public BlackboardProvider(string assetName, AbstractMaterialGraph graph)
{

};
m_Section = new BlackboardSection { headerVisible = false };
m_Section.Add(new Button(OnClickSave) { text = "Save" });
foreach (var property in graph.properties)
AddProperty(property);
blackboard.Add(m_Section);

field.text = newText;
DirtyNodes();
}
}
void OnClickSave()
{
if (updateAssetRequested != null)
updateAssetRequested();
}
public void HandleGraphChanges()

AddProperty(property);
}
void AddProperty(IShaderProperty property, bool focus = false)
void AddProperty(IShaderProperty property, bool create = false)
{
if (m_PropertyRows.ContainsKey(property.guid))
throw new ArgumentException("Property already exists");

m_PropertyRows[property.guid] = row;
if (focus)
if (create)
{
row.expanded = true;
}
}
void DirtyNodes()

6
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/MaterialGraphEditWindow.cs


m_GraphEditorView = value;
if (m_GraphEditorView != null)
{
m_GraphEditorView.onUpdateAssetClick += UpdateAsset;
m_GraphEditorView.onConvertToSubgraphClick += ToSubGraph;
m_GraphEditorView.onShowInProjectClick += PingAsset;
m_GraphEditorView.saveRequested += UpdateAsset;
m_GraphEditorView.convertToSubgraphRequested += ToSubGraph;
m_GraphEditorView.showInProjectRequested += PingAsset;
this.GetRootVisualContainer().Add(graphEditorView);
}
}

86
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/GraphEditorView.cs


public class GraphEditorView : VisualElement, IDisposable
{
MaterialGraphView m_GraphView;
GraphInspectorView m_GraphInspectorView;
private EditorWindow m_EditorWindow;
AbstractMaterialGraph m_Graph;

public Action onUpdateAssetClick
{
get { return m_GraphInspectorView.onUpdateAssetClick; }
set { m_GraphInspectorView.onUpdateAssetClick = value; }
}
public Action saveRequested { get; set; }
public Action onConvertToSubgraphClick
public Action convertToSubgraphRequested
public Action onShowInProjectClick
{
get { return m_GraphInspectorView.onShowInProjectClick; }
set { m_GraphInspectorView.onShowInProjectClick = value; }
}
public Action showInProjectRequested { get; set; }
public MaterialGraphView graphView
{

set { m_PreviewManager = value; }
}
GraphInspectorView inspectorView
{
get { return m_GraphInspectorView; }
}
public GraphEditorView(EditorWindow editorWindow, AbstractMaterialGraph graph, string assetName)
{
m_Graph = graph;

var toolbar = new IMGUIContainer(() =>
{
GUILayout.BeginHorizontal(EditorStyles.toolbar);
if (GUILayout.Button("Save Asset", EditorStyles.toolbarButton))
{
if (saveRequested != null)
saveRequested();
}
GUILayout.Space(6);
if (GUILayout.Button("Show In Project", EditorStyles.toolbarButton))
{
if (showInProjectRequested != null)
showInProjectRequested();
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
});
Add(toolbar);
var content = new VisualElement { name = "content" };
{
m_GraphView = new MaterialGraphView(graph) { name = "GraphView", persistenceKey = "MaterialGraphView" };

m_GraphView.RegisterCallback<KeyDownEvent>(OnSpaceDown);
content.Add(m_GraphView);
m_GraphInspectorView = new GraphInspectorView(assetName, previewManager, graph) { name = "inspector" };
m_GraphInspectorView.AddManipulator(new Draggable(OnMouseDrag, true));
m_GraphView.RegisterCallback<PostLayoutEvent>(OnPostLayout);
m_GraphInspectorView.RegisterCallback<PostLayoutEvent>(OnPostLayout);
m_GraphView.Add(m_GraphInspectorView);
m_BlackboardProvider = new BlackboardProvider(assetName, graph);
m_GraphView.Add(m_BlackboardProvider.blackboard);

Add(content);
}
void OnPostLayout(PostLayoutEvent evt)
{
const float minimumVisibility = 60f;
Rect inspectorViewRect = m_GraphInspectorView.layout;
float minimumXPosition = minimumVisibility - inspectorViewRect.width;
float maximumXPosition = m_GraphView.layout.width - minimumVisibility;
float minimumYPosition = minimumVisibility - inspectorViewRect.height;
float maximumYPosition = m_GraphView.layout.height - minimumVisibility;
inspectorViewRect.x = Mathf.Clamp(inspectorViewRect.x, minimumXPosition, maximumXPosition);
inspectorViewRect.y = Mathf.Clamp(inspectorViewRect.y, minimumYPosition, maximumYPosition);
inspectorViewRect.width = Mathf.Min(inspectorViewRect.width, layout.width);
inspectorViewRect.height = Mathf.Min(inspectorViewRect.height, layout.height);
m_GraphInspectorView.layout = inspectorViewRect;
}
void OnSpaceDown(KeyDownEvent evt)
{
if( evt.keyCode == KeyCode.Space)

graphView.nodeCreationRequest(new NodeCreationContext() { screenMousePosition = screenPoint });
}
}
void OnMouseDrag(Vector2 mouseDelta)
{
Vector2 normalizedDelta = mouseDelta / 2f;
Rect inspectorWindowRect = m_GraphInspectorView.layout;
inspectorWindowRect.x += normalizedDelta.x;
inspectorWindowRect.y += normalizedDelta.y;
m_GraphInspectorView.layout = inspectorWindowRect;
}
GraphViewChange GraphViewChanged(GraphViewChange graphViewChange)

{
previewManager.HandleGraphChanges();
previewManager.RenderPreviews();
inspectorView.HandleGraphChanges();
m_BlackboardProvider.HandleGraphChanges();
foreach (var node in m_Graph.removedNodes)

public void Dispose()
{
onUpdateAssetClick = null;
onConvertToSubgraphClick = null;
onShowInProjectClick = null;
saveRequested = null;
convertToSubgraphRequested = null;
showInProjectRequested = null;
if (m_GraphView != null)
{
foreach (var node in m_GraphView.Children().OfType<MaterialNodeView>())

if (m_GraphInspectorView != null) m_GraphInspectorView.Dispose();
if (previewManager != null)
{
previewManager.Dispose();

22
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/MaterialGraphView.cs


public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
base.BuildContextualMenu(evt);
evt.menu.AppendAction("Convert To Sub-graph", ConvertToSubgraph, ConvertToSubgraphStatus);
evt.menu.AppendAction("Convert To Inline Node", ConvertToInlineNode, ConvertToInlineNodeStatus);
evt.menu.AppendAction("Convert To Property", ConvertToProperty, ConvertToPropertyStatus);
if (evt.target is GraphView || evt.target is Node)
{
evt.menu.AppendAction("Convert To Sub-graph", ConvertToSubgraph, ConvertToSubgraphStatus);
evt.menu.AppendAction("Convert To Inline Node", ConvertToInlineNode, ConvertToInlineNodeStatus);
evt.menu.AppendAction("Convert To Property", ConvertToProperty, ConvertToPropertyStatus);
}
else if (evt.target is BlackboardField)
{
evt.menu.AppendAction("Delete", (e) => DeleteSelectionImplementation("Delete", AskUser.DontAskUser), (e) => canDeleteSelection ? ContextualMenu.MenuAction.StatusFlags.Normal : ContextualMenu.MenuAction.StatusFlags.Disabled);
}
}
ContextualMenu.MenuAction.StatusFlags ConvertToPropertyStatus(EventBase eventBase)

{
graph.owner.RegisterCompleteObjectUndo(operationName);
graph.RemoveElements(selection.OfType<MaterialNodeView>().Select(x => (INode)x.node), selection.OfType<Edge>().Select(x => x.userData).OfType<IEdge>());
foreach (var selectable in selection)
{
var field = selectable as BlackboardField;
if (field != null && field.userData != null)
{
var property = (IShaderProperty)field.userData;
graph.RemoveShaderProperty(property.guid);
}
}
}
}

正在加载...
取消
保存