public override GraphicsPath MakePath() { GraphicsPath path1 = base.MakePath(); SubGraphNode graph1 = base.Parent as SubGraphNode; if (graph1 != null) { RectangleF ef1 = this.Bounds; if (graph1.Collapsible) { float single1 = ef1.Y + (ef1.Height / 2f); path1.StartFigure(); path1.AddLine((float)(ef1.X + (ef1.Width / 4f)), single1, (float)(ef1.X + ((ef1.Width * 3f) / 4f)), single1); if (!graph1.IsExpanded) { float single2 = ef1.X + (ef1.Width / 2f); path1.StartFigure(); path1.AddLine(single2, (float)(ef1.Y + (ef1.Height / 4f)), single2, (float)(ef1.Y + ((ef1.Height * 3f) / 4f))); } return(path1); } path1.AddEllipse((float)(ef1.X + (ef1.Width / 4f)), (float)(ef1.Y + (ef1.Height / 4f)), (float)(ef1.Width / 2f), (float)(ef1.Height / 2f)); } return(path1); }
void OpenSubGraph(DropdownMenuAction action) { SubGraphNode subgraphNode = selection.OfType<MaterialNodeView>().First().node as SubGraphNode; var path = AssetDatabase.GetAssetPath(subgraphNode.subGraphAsset); ShaderGraphImporterEditor.ShowGraphEditWindow(path); }
public override bool OnSingleClick(InputEventArgs evt, DiagramView view) { SubGraphNode graph1 = base.Parent as SubGraphNode; if ((graph1 == null) || !graph1.Collapsible) { return(false); } if (view != null) { view.StartTransaction(); } string text1 = null; if (graph1.IsExpanded) { graph1.Collapse(); text1 = "Collapsed SubGraph"; } else if (evt.Control) { graph1.ExpandAll(); text1 = "Expanded All SubGraphs"; } else { graph1.Expand(); text1 = "Expanded SubGraph"; } if (view != null) { view.FinishTransaction(text1); } return(true); }
public static SubGraphNode CreateInstance(GameObject go, GameObject parent, Vector3 pos, string text, bool showMesh = false) { SubGraphNode sgn = CreateInstance <SubGraphNode>(); sgn.Init(go, parent, pos, text, showMesh); return(sgn); }
public static SubGraphNode CreateInstance(GameObject go, Vector3 pos, string text, bool hide = false) { SubGraphNode sgn = CreateInstance <SubGraphNode>(); sgn.Init(go, pos, text, hide); return(sgn); }
public GraphTab(Graph graph, SubGraphNode subGraphNode, float zoom, Vector2 panOffset, List <Node> selectedNodes, List <Node> deletedNodes) { IsRootTab = false; Graph = graph; SubGraphNode = subGraphNode; Zoom = zoom; PanOffset = panOffset; SelectedNodes = new List <Node>(selectedNodes); DeletedNodes = new List <Node>(deletedNodes); }
void OnSubGraphDoubleClick(MouseDownEvent evt) { if (evt.clickCount == 2 && evt.button == 0) { SubGraphNode subgraphNode = node as SubGraphNode; var path = AssetDatabase.GUIDToAssetPath(subgraphNode.subGraphGuid); ShaderGraphImporterEditor.ShowGraphEditWindow(path); } }
public void InitSubNodes(string[] subs, GameObject go) { // it would be improper to call this function to add sub nodes // this is only for initial creation subNodes = new SubGraphNode[subs.Length]; int i = 0; foreach (string str in subs) { SubGraphNode sgn = SubGraphNode.CreateInstance(go, Vector3.zero, str); sgn.getObject().transform.parent = thisObject.transform; subNodes[i++] = sgn; } positionSubNodes(); }
public void OpenSubGraph(SubGraphNode subGraphNode) { if (subGraphNode == null || subGraphNode.SubGraph == null) { return; } GraphTab currentTab = GraphTabs[GraphTabs.Count - 1]; currentTab.Zoom = CurrentZoom; currentTab.PanOffset = CurrentPanOffset; currentTab.SelectedNodes = new List <Node>(SelectedNodes); var newTab = new GraphTab(CurrentGraph, subGraphNode, CurrentZoom, CurrentPanOffset, SelectedNodes, DeletedNodes); OpenGraph(subGraphNode.SubGraph, true, false, true); GraphTabs.Add(newTab); }
public virtual IDiagramShapeCollection AddCollection(IDiagramShapeCollection coll, bool reparentLinks) { foreach (DiagramShape obj1 in coll) { if (!base.IsChildOf(obj1) && (this != obj1)) { continue; } throw new ArgumentException("Cannot add a group to itself or to one of its own children."); } DiagramShapeCollection collection1 = new DiagramShapeCollection(); foreach (DiagramShape obj2 in coll) { collection1.Add(obj2); } CollectionEnumerator enumerator2 = collection1.GetEnumerator(); while (enumerator2.MoveNext()) { DiagramShape obj3 = enumerator2.Current; bool flag1 = obj3.Layer != null; if (flag1) { GroupShape.setAllNoClear(obj3, true); obj3.Remove(); } this.Add(obj3); if (flag1) { GroupShape.setAllNoClear(obj3, false); } } if (reparentLinks && base.IsInDocument) { SubGraphNode.ReparentAllLinksToSubGraphs(collection1, true, base.Document.LinksLayer); } return(collection1); }
protected virtual void PaintHandle(Graphics g, DiagramView view) { SubGraphNode graph1 = base.Parent as SubGraphNode; if (graph1 != null) { RectangleF ef1 = this.Bounds; if (graph1.Collapsible) { float single1 = ef1.Y + (ef1.Height / 2f); DiagramGraph.DrawLine(g, view, this.Pen, ef1.X + (ef1.Width / 4f), single1, ef1.X + ((ef1.Width * 3f) / 4f), single1); if (graph1.IsExpanded) { return; } float single2 = ef1.X + (ef1.Width / 2f); DiagramGraph.DrawLine(g, view, this.Pen, single2, ef1.Y + (ef1.Height / 4f), single2, ef1.Y + ((ef1.Height * 3f) / 4f)); } else { DiagramGraph.DrawEllipse(g, view, this.Pen, null, ef1.X + (ef1.Width / 4f), ef1.Y + (ef1.Height / 4f), ef1.Width / 2f, ef1.Height / 2f); } } }
public void ToSubGraph() { var path = EditorUtility.SaveFilePanelInProject("Save Sub Graph", "New Shader Sub Graph", ShaderSubGraphImporter.Extension, ""); path = path.Replace(Application.dataPath, "Assets"); if (path.Length == 0) { return; } graphObject.RegisterCompleteObjectUndo("Convert To Subgraph"); var graphView = graphEditorView.graphView; var nodes = graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode)).Select(x => x.node as AbstractMaterialNode).ToArray(); var bounds = Rect.MinMaxRect(float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity); foreach (var node in nodes) { var center = node.drawState.position.center; bounds = Rect.MinMaxRect( Mathf.Min(bounds.xMin, center.x), Mathf.Min(bounds.yMin, center.y), Mathf.Max(bounds.xMax, center.x), Mathf.Max(bounds.yMax, center.y)); } var middle = bounds.center; bounds.center = Vector2.zero; // Collect the property nodes and get the corresponding properties var propertyNodeGuids = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is PropertyNode)).Select(x => ((PropertyNode)x.node).propertyGuid); var metaProperties = graphView.graph.properties.Where(x => propertyNodeGuids.Contains(x.guid)); var copyPasteGraph = new CopyPasteGraph( graphView.graph.guid, graphView.selection.OfType <ShaderGroup>().Select(x => x.userData), graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode)).Select(x => x.node as AbstractMaterialNode), graphView.selection.OfType <Edge>().Select(x => x.userData as IEdge), graphView.selection.OfType <BlackboardField>().Select(x => x.userData as AbstractShaderProperty), metaProperties); var deserialized = CopyPasteGraph.FromJson(JsonUtility.ToJson(copyPasteGraph, false)); if (deserialized == null) { return; } var subGraph = new GraphData { isSubGraph = true }; subGraph.path = "Sub Graphs"; var subGraphOutputNode = new SubGraphOutputNode(); { var drawState = subGraphOutputNode.drawState; drawState.position = new Rect(new Vector2(bounds.xMax + 200f, 0f), drawState.position.size); subGraphOutputNode.drawState = drawState; } subGraph.AddNode(subGraphOutputNode); var nodeGuidMap = new Dictionary <Guid, Guid>(); foreach (var node in deserialized.GetNodes <AbstractMaterialNode>()) { var oldGuid = node.guid; var newGuid = node.RewriteGuid(); nodeGuidMap[oldGuid] = newGuid; var drawState = node.drawState; drawState.position = new Rect(drawState.position.position - middle, drawState.position.size); node.drawState = drawState; subGraph.AddNode(node); } // 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; var inputSlot = edge.inputSlot; Guid remappedOutputNodeGuid; Guid remappedInputNodeGuid; var outputSlotExistsInSubgraph = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid); var inputSlotExistsInSubgraph = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid); // pasting nice internal links! if (outputSlotExistsInSubgraph && inputSlotExistsInSubgraph) { var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId); var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotId); subGraph.Connect(outputSlotRef, inputSlotRef); } // one edge needs to go to outside world else if (outputSlotExistsInSubgraph) { externalInputSlots.Add(edge); } else if (inputSlotExistsInSubgraph) { externalOutputSlots.Add(edge); } } // Find the unique edges coming INTO the graph var uniqueIncomingEdges = externalOutputSlots.GroupBy( edge => edge.outputSlot, edge => edge, (key, edges) => new { slotRef = key, edges = edges.ToList() }); var externalInputNeedingConnection = new List <KeyValuePair <IEdge, AbstractShaderProperty> >(); foreach (var group in uniqueIncomingEdges) { var sr = group.slotRef; var fromNode = graphObject.graph.GetNodeFromGuid(sr.nodeGuid); var fromSlot = fromNode.FindOutputSlot <MaterialSlot>(sr.slotId); AbstractShaderProperty prop; switch (fromSlot.concreteValueType) { case ConcreteSlotValueType.Texture2D: prop = new TextureShaderProperty(); break; case ConcreteSlotValueType.Texture2DArray: prop = new Texture2DArrayShaderProperty(); break; case ConcreteSlotValueType.Texture3D: prop = new Texture3DShaderProperty(); break; case ConcreteSlotValueType.Cubemap: prop = new CubemapShaderProperty(); break; case ConcreteSlotValueType.Vector4: prop = new Vector4ShaderProperty(); break; case ConcreteSlotValueType.Vector3: prop = new Vector3ShaderProperty(); break; case ConcreteSlotValueType.Vector2: prop = new Vector2ShaderProperty(); break; case ConcreteSlotValueType.Vector1: prop = new Vector1ShaderProperty(); break; case ConcreteSlotValueType.Boolean: prop = new BooleanShaderProperty(); break; default: throw new ArgumentOutOfRangeException(); } if (prop != null) { var materialGraph = (GraphData)graphObject.graph; var fromPropertyNode = fromNode as PropertyNode; var fromProperty = fromPropertyNode != null?materialGraph.properties.FirstOrDefault(p => p.guid == fromPropertyNode.propertyGuid) : null; prop.displayName = fromProperty != null ? fromProperty.displayName : fromSlot.concreteValueType.ToString(); subGraph.AddShaderProperty(prop); var propNode = new PropertyNode(); { var drawState = propNode.drawState; drawState.position = new Rect(new Vector2(bounds.xMin - 300f, 0f), drawState.position.size); propNode.drawState = drawState; } 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, AbstractShaderProperty>(edge, prop)); } } } var uniqueOutgoingEdges = externalInputSlots.GroupBy( edge => edge.inputSlot, edge => edge, (key, edges) => new { slot = key, edges = edges.ToList() }); var externalOutputsNeedingConnection = new List <KeyValuePair <IEdge, IEdge> >(); foreach (var group in uniqueOutgoingEdges) { var outputNode = subGraph.outputNode as SubGraphOutputNode; AbstractMaterialNode node = graphView.graph.GetNodeFromGuid(group.edges[0].outputSlot.nodeGuid); MaterialSlot slot = node.FindSlot <MaterialSlot>(group.edges[0].outputSlot.slotId); var slotId = outputNode.AddSlot(slot.concreteValueType); var inputSlotRef = new SlotReference(outputNode.guid, slotId); foreach (var edge in group.edges) { 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(subGraph)); AssetDatabase.ImportAsset(path); var loadedSubGraph = AssetDatabase.LoadAssetAtPath(path, typeof(MaterialSubGraphAsset)) as MaterialSubGraphAsset; if (loadedSubGraph == null) { return; } var subGraphNode = new SubGraphNode(); var ds = subGraphNode.drawState; ds.position = new Rect(middle - new Vector2(100f, 150f), Vector2.zero); subGraphNode.drawState = ds; graphObject.graph.AddNode(subGraphNode); subGraphNode.subGraphAsset = loadedSubGraph; foreach (var edgeMap in externalInputNeedingConnection) { graphObject.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.guid.GetHashCode())); } foreach (var edgeMap in externalOutputsNeedingConnection) { graphObject.graph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot); } graphObject.graph.RemoveElements( graphView.selection.OfType <IShaderNodeView>().Select(x => x.node as AbstractMaterialNode), Enumerable.Empty <IEdge>(), Enumerable.Empty <GroupData>()); graphObject.graph.ValidateGraph(); }
public List <SearchTreeEntry> CreateSearchTree(SearchWindowContext context) { // First build up temporary data structure containing group & title as an array of strings (the last one is the actual title) and associated node type. var nodeEntries = new List <NodeEntry>(); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var type in assembly.GetTypesOrNothing()) { if (type.IsClass && !type.IsAbstract && (type.IsSubclassOf(typeof(AbstractMaterialNode))) && type != typeof(PropertyNode) && type != typeof(SubGraphNode)) { var attrs = type.GetCustomAttributes(typeof(TitleAttribute), false) as TitleAttribute[]; if (attrs != null && attrs.Length > 0) { var node = (AbstractMaterialNode)Activator.CreateInstance(type); AddEntries(node, attrs[0].title, nodeEntries); } } } } foreach (var guid in AssetDatabase.FindAssets(string.Format("t:{0}", typeof(SubGraphAsset)))) { var asset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(guid)); var node = new SubGraphNode { asset = asset }; var title = asset.path.Split('/').ToList(); if (asset.descendents.Contains(m_Graph.assetGuid) || asset.assetGuid == m_Graph.assetGuid) { continue; } if (string.IsNullOrEmpty(asset.path)) { AddEntries(node, new string[1] { asset.name }, nodeEntries); } else if (title[0] != k_HiddenFolderName) { title.Add(asset.name); AddEntries(node, title.ToArray(), nodeEntries); } } foreach (var property in m_Graph.properties) { var node = new PropertyNode(); node.owner = m_Graph; node.propertyGuid = property.guid; node.owner = null; AddEntries(node, new[] { "Properties", "Property: " + property.displayName }, nodeEntries); } // Sort the entries lexicographically by group then title with the requirement that items always comes before sub-groups in the same group. // Example result: // - Art/BlendMode // - Art/Adjustments/ColorBalance // - Art/Adjustments/Contrast nodeEntries.Sort((entry1, entry2) => { for (var i = 0; i < entry1.title.Length; i++) { if (i >= entry2.title.Length) { return(1); } var value = entry1.title[i].CompareTo(entry2.title[i]); if (value != 0) { // Make sure that leaves go before nodes if (entry1.title.Length != entry2.title.Length && (i == entry1.title.Length - 1 || i == entry2.title.Length - 1)) { return(entry1.title.Length < entry2.title.Length ? -1 : 1); } return(value); } } return(0); }); //* Build up the data structure needed by SearchWindow. // `groups` contains the current group path we're in. var groups = new List <string>(); // First item in the tree is the title of the window. var tree = new List <SearchTreeEntry> { new SearchTreeGroupEntry(new GUIContent("Create Node"), 0), }; foreach (var nodeEntry in nodeEntries) { // `createIndex` represents from where we should add new group entries from the current entry's group path. var createIndex = int.MaxValue; // Compare the group path of the current entry to the current group path. for (var i = 0; i < nodeEntry.title.Length - 1; i++) { var group = nodeEntry.title[i]; if (i >= groups.Count) { // The current group path matches a prefix of the current entry's group path, so we add the // rest of the group path from the currrent entry. createIndex = i; break; } if (groups[i] != group) { // A prefix of the current group path matches a prefix of the current entry's group path, // so we remove everyfrom from the point where it doesn't match anymore, and then add the rest // of the group path from the current entry. groups.RemoveRange(i, groups.Count - i); createIndex = i; break; } } // Create new group entries as needed. // If we don't need to modify the group path, `createIndex` will be `int.MaxValue` and thus the loop won't run. for (var i = createIndex; i < nodeEntry.title.Length - 1; i++) { var group = nodeEntry.title[i]; groups.Add(group); tree.Add(new SearchTreeGroupEntry(new GUIContent(group)) { level = i + 1 }); } // Finally, add the actual entry. tree.Add(new SearchTreeEntry(new GUIContent(nodeEntry.title.Last(), m_Icon)) { level = nodeEntry.title.Length, userData = nodeEntry }); } return(tree); }
public void ToSubGraph() { var graphView = graphEditorView.graphView; string path; string sessionStateResult = SessionState.GetString(k_PrevSubGraphPathKey, k_PrevSubGraphPathDefaultValue); string pathToOriginSG = Path.GetDirectoryName(AssetDatabase.GUIDToAssetPath(selectedGuid)); if (!sessionStateResult.Equals(k_PrevSubGraphPathDefaultValue)) { path = sessionStateResult; } else { path = pathToOriginSG; } path = EditorUtility.SaveFilePanelInProject("Save Sub Graph", "New Shader Sub Graph", ShaderSubGraphImporter.Extension, "", path); path = path.Replace(Application.dataPath, "Assets"); if (path.Length == 0) { return; } graphObject.RegisterCompleteObjectUndo("Convert To Subgraph"); var nodes = graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(); var bounds = Rect.MinMaxRect(float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity); foreach (var node in nodes) { var center = node.drawState.position.center; bounds = Rect.MinMaxRect( Mathf.Min(bounds.xMin, center.x), Mathf.Min(bounds.yMin, center.y), Mathf.Max(bounds.xMax, center.x), Mathf.Max(bounds.yMax, center.y)); } var middle = bounds.center; bounds.center = Vector2.zero; // Collect graph inputs var graphInputs = graphView.selection.OfType <BlackboardField>().Select(x => x.userData as ShaderInput); // Collect the property nodes and get the corresponding properties var propertyNodes = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is PropertyNode)).Select(x => ((PropertyNode)x.node).property); var metaProperties = graphView.graph.properties.Where(x => propertyNodes.Contains(x)); // Collect the keyword nodes and get the corresponding keywords var keywordNodes = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is KeywordNode)).Select(x => ((KeywordNode)x.node).keyword); var metaKeywords = graphView.graph.keywords.Where(x => keywordNodes.Contains(x)); var copyPasteGraph = new CopyPasteGraph(graphView.selection.OfType <ShaderGroup>().Select(x => x.userData), graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(), graphView.selection.OfType <Edge>().Select(x => x.userData as Graphing.Edge), graphInputs, metaProperties, metaKeywords, graphView.selection.OfType <StickyNote>().Select(x => x.userData), true); // why do we serialize and deserialize only to make copies of everything in the steps below? // is this just to clear out all non-serialized data? var deserialized = CopyPasteGraph.FromJson(MultiJson.Serialize(copyPasteGraph), graphView.graph); if (deserialized == null) { return; } var subGraph = new GraphData { isSubGraph = true, path = "Sub Graphs" }; var subGraphOutputNode = new SubGraphOutputNode(); { var drawState = subGraphOutputNode.drawState; drawState.position = new Rect(new Vector2(bounds.xMax + 200f, 0f), drawState.position.size); subGraphOutputNode.drawState = drawState; } subGraph.AddNode(subGraphOutputNode); subGraph.outputNode = subGraphOutputNode; // Always copy deserialized keyword inputs foreach (ShaderKeyword keyword in deserialized.metaKeywords) { var copiedInput = (ShaderKeyword)keyword.Copy(); subGraph.SanitizeGraphInputName(copiedInput); subGraph.SanitizeGraphInputReferenceName(copiedInput, keyword.overrideReferenceName); subGraph.AddGraphInput(copiedInput); // Update the keyword nodes that depends on the copied keyword var dependentKeywordNodes = deserialized.GetNodes <KeywordNode>().Where(x => x.keyword == keyword); foreach (var node in dependentKeywordNodes) { node.owner = graphView.graph; node.keyword = copiedInput; } } foreach (GroupData groupData in deserialized.groups) { subGraph.CreateGroup(groupData); } foreach (var node in deserialized.GetNodes <AbstractMaterialNode>()) { var drawState = node.drawState; drawState.position = new Rect(drawState.position.position - middle, drawState.position.size); node.drawState = drawState; // Checking if the group guid is also being copied. // If not then nullify that guid if (node.group != null && !subGraph.groups.Contains(node.group)) { node.group = null; } subGraph.AddNode(node); } foreach (var note in deserialized.stickyNotes) { if (note.group != null && !subGraph.groups.Contains(note.group)) { note.group = null; } subGraph.AddStickyNote(note); } // figure out what needs remapping var externalOutputSlots = new List <Graphing.Edge>(); var externalInputSlots = new List <Graphing.Edge>(); foreach (var edge in deserialized.edges) { var outputSlot = edge.outputSlot; var inputSlot = edge.inputSlot; var outputSlotExistsInSubgraph = subGraph.ContainsNode(outputSlot.node); var inputSlotExistsInSubgraph = subGraph.ContainsNode(inputSlot.node); // pasting nice internal links! if (outputSlotExistsInSubgraph && inputSlotExistsInSubgraph) { subGraph.Connect(outputSlot, inputSlot); } // one edge needs to go to outside world else if (outputSlotExistsInSubgraph) { externalInputSlots.Add(edge); } else if (inputSlotExistsInSubgraph) { externalOutputSlots.Add(edge); } } // Find the unique edges coming INTO the graph var uniqueIncomingEdges = externalOutputSlots.GroupBy( edge => edge.outputSlot, edge => edge, (key, edges) => new { slotRef = key, edges = edges.ToList() }); var externalInputNeedingConnection = new List <KeyValuePair <IEdge, AbstractShaderProperty> >(); var amountOfProps = uniqueIncomingEdges.Count(); const int height = 40; const int subtractHeight = 20; var propPos = new Vector2(0, -((amountOfProps / 2) + height) - subtractHeight); foreach (var group in uniqueIncomingEdges) { var sr = group.slotRef; var fromNode = sr.node; var fromSlot = sr.slot; var materialGraph = graphObject.graph; var fromProperty = fromNode is PropertyNode fromPropertyNode ? materialGraph.properties.FirstOrDefault(p => p == fromPropertyNode.property) : null; AbstractShaderProperty prop; switch (fromSlot.concreteValueType) { case ConcreteSlotValueType.Texture2D: prop = new Texture2DShaderProperty(); break; case ConcreteSlotValueType.Texture2DArray: prop = new Texture2DArrayShaderProperty(); break; case ConcreteSlotValueType.Texture3D: prop = new Texture3DShaderProperty(); break; case ConcreteSlotValueType.Cubemap: prop = new CubemapShaderProperty(); break; case ConcreteSlotValueType.Vector4: prop = new Vector4ShaderProperty(); break; case ConcreteSlotValueType.Vector3: prop = new Vector3ShaderProperty(); break; case ConcreteSlotValueType.Vector2: prop = new Vector2ShaderProperty(); break; case ConcreteSlotValueType.Vector1: prop = new Vector1ShaderProperty(); break; case ConcreteSlotValueType.Boolean: prop = new BooleanShaderProperty(); break; case ConcreteSlotValueType.Matrix2: prop = new Matrix2ShaderProperty(); break; case ConcreteSlotValueType.Matrix3: prop = new Matrix3ShaderProperty(); break; case ConcreteSlotValueType.Matrix4: prop = new Matrix4ShaderProperty(); break; case ConcreteSlotValueType.SamplerState: prop = new SamplerStateShaderProperty(); break; case ConcreteSlotValueType.Gradient: prop = new GradientShaderProperty(); break; case ConcreteSlotValueType.VirtualTexture: prop = new VirtualTextureShaderProperty() { // also copy the VT settings over from the original property (if there is one) value = (fromProperty as VirtualTextureShaderProperty)?.value ?? new SerializableVirtualTexture() }; break; default: throw new ArgumentOutOfRangeException(); } prop.displayName = fromProperty != null ? fromProperty.displayName : fromSlot.concreteValueType.ToString(); prop.displayName = GraphUtil.SanitizeName(subGraph.addedInputs.Select(p => p.displayName), "{0} ({1})", prop.displayName); subGraph.AddGraphInput(prop); var propNode = new PropertyNode(); { var drawState = propNode.drawState; drawState.position = new Rect(new Vector2(bounds.xMin - 300f, 0f) + propPos, drawState.position.size); propPos += new Vector2(0, height); propNode.drawState = drawState; } subGraph.AddNode(propNode); propNode.property = prop; foreach (var edge in group.edges) { subGraph.Connect( new SlotReference(propNode, PropertyNode.OutputSlotId), edge.inputSlot); externalInputNeedingConnection.Add(new KeyValuePair <IEdge, AbstractShaderProperty>(edge, prop)); } } var uniqueOutgoingEdges = externalInputSlots.GroupBy( edge => edge.outputSlot, edge => edge, (key, edges) => new { slot = key, edges = edges.ToList() }); var externalOutputsNeedingConnection = new List <KeyValuePair <IEdge, IEdge> >(); foreach (var group in uniqueOutgoingEdges) { var outputNode = subGraph.outputNode as SubGraphOutputNode; AbstractMaterialNode node = group.edges[0].outputSlot.node; MaterialSlot slot = node.FindSlot <MaterialSlot>(group.edges[0].outputSlot.slotId); var slotId = outputNode.AddSlot(slot.concreteValueType); var inputSlotRef = new SlotReference(outputNode, slotId); foreach (var edge in group.edges) { var newEdge = subGraph.Connect(edge.outputSlot, inputSlotRef); externalOutputsNeedingConnection.Add(new KeyValuePair <IEdge, IEdge>(edge, newEdge)); } } if (FileUtilities.WriteShaderGraphToDisk(path, subGraph)) { AssetDatabase.ImportAsset(path); } // Store path for next time if (!pathToOriginSG.Equals(Path.GetDirectoryName(path))) { SessionState.SetString(k_PrevSubGraphPathKey, Path.GetDirectoryName(path)); } else { // Or continue to make it so that next time it will open up in the converted-from SG's directory SessionState.EraseString(k_PrevSubGraphPathKey); } var loadedSubGraph = AssetDatabase.LoadAssetAtPath(path, typeof(SubGraphAsset)) as SubGraphAsset; if (loadedSubGraph == null) { return; } var subGraphNode = new SubGraphNode(); var ds = subGraphNode.drawState; ds.position = new Rect(middle - new Vector2(100f, 150f), Vector2.zero); subGraphNode.drawState = ds; // Add the subgraph into the group if the nodes was all in the same group group var firstNode = copyPasteGraph.GetNodes <AbstractMaterialNode>().FirstOrDefault(); if (firstNode != null && copyPasteGraph.GetNodes <AbstractMaterialNode>().All(x => x.group == firstNode.group)) { subGraphNode.group = firstNode.group; } subGraphNode.asset = loadedSubGraph; graphObject.graph.AddNode(subGraphNode); foreach (var edgeMap in externalInputNeedingConnection) { graphObject.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode, edgeMap.Value.guid.GetHashCode())); } foreach (var edgeMap in externalOutputsNeedingConnection) { graphObject.graph.Connect(new SlotReference(subGraphNode, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot); } graphObject.graph.RemoveElements( graphView.selection.OfType <IShaderNodeView>().Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(), new IEdge[] {}, new GroupData[] {}, graphView.selection.OfType <StickyNote>().Select(x => x.userData).ToArray()); graphObject.graph.ValidateGraph(); }
public void GenerateNodeEntries() { Profiler.BeginSample("SearchWindowProvider.GenerateNodeEntries"); // First build up temporary data structure containing group & title as an array of strings (the last one is the actual title) and associated node type. List <NodeEntry> nodeEntries = new List <NodeEntry>(); bool hideCustomInterpolators = m_Graph.activeTargets.All(at => at.ignoreCustomInterpolators); if (target is ContextView contextView) { // Iterate all BlockFieldDescriptors currently cached on GraphData foreach (var field in m_Graph.blockFieldDescriptors) { if (field.isHidden) { continue; } // Test stage if (field.shaderStage != contextView.contextData.shaderStage) { continue; } // Create title List <string> title = ListPool <string> .Get(); if (!string.IsNullOrEmpty(field.path)) { var path = field.path.Split('/').ToList(); title.AddRange(path); } title.Add(field.displayName); // Create and initialize BlockNode instance then add entry var node = (BlockNode)Activator.CreateInstance(typeof(BlockNode)); node.Init(field); AddEntries(node, title.ToArray(), nodeEntries); } SortEntries(nodeEntries); if (contextView.contextData.shaderStage == ShaderStage.Vertex && !hideCustomInterpolators) { var customBlockNodeStub = (BlockNode)Activator.CreateInstance(typeof(BlockNode)); customBlockNodeStub.InitCustomDefault(); AddEntries(customBlockNodeStub, new string[] { "Custom Interpolator" }, nodeEntries); } currentNodeEntries = nodeEntries; return; } Profiler.BeginSample("SearchWindowProvider.GenerateNodeEntries.IterateKnowNodes"); foreach (var type in NodeClassCache.knownNodeTypes) { if ((!type.IsClass || type.IsAbstract) || type == typeof(PropertyNode) || type == typeof(KeywordNode) || type == typeof(DropdownNode) || type == typeof(SubGraphNode)) { continue; } TitleAttribute titleAttribute = NodeClassCache.GetAttributeOnNodeType <TitleAttribute>(type); if (titleAttribute != null) { var node = (AbstractMaterialNode)Activator.CreateInstance(type); if (!node.ExposeToSearcher) { continue; } if (ShaderGraphPreferences.allowDeprecatedBehaviors && node.latestVersion > 0) { var versions = node.allowedNodeVersions ?? Enumerable.Range(0, node.latestVersion + 1); bool multiple = (versions.Count() > 1); foreach (int i in versions) { var depNode = (AbstractMaterialNode)Activator.CreateInstance(type); depNode.ChangeVersion(i); if (multiple) { AddEntries(depNode, titleAttribute.title.Append($"v{i}").ToArray(), nodeEntries); } else { AddEntries(depNode, titleAttribute.title, nodeEntries); } } } else { AddEntries(node, titleAttribute.title, nodeEntries); } } } Profiler.EndSample(); Profiler.BeginSample("SearchWindowProvider.GenerateNodeEntries.IterateSubgraphAssets"); foreach (var asset in NodeClassCache.knownSubGraphAssets) { if (asset == null) { continue; } var node = new SubGraphNode { asset = asset }; var title = asset.path.Split('/').ToList(); if (asset.descendents.Contains(m_Graph.assetGuid) || asset.assetGuid == m_Graph.assetGuid) { continue; } if (string.IsNullOrEmpty(asset.path)) { AddEntries(node, new string[1] { asset.name }, nodeEntries); } else if (title[0] != k_HiddenFolderName) { title.Add(asset.name); AddEntries(node, title.ToArray(), nodeEntries); } } Profiler.EndSample(); Profiler.BeginSample("SearchWindowProvider.GenerateNodeEntries.IterateGraphInputs"); foreach (var property in m_Graph.properties) { if (property is Serialization.MultiJsonInternal.UnknownShaderPropertyType) { continue; } var node = new PropertyNode(); node.property = property; AddEntries(node, new[] { "Properties", "Property: " + property.displayName }, nodeEntries); } foreach (var keyword in m_Graph.keywords) { var node = new KeywordNode(); node.keyword = keyword; AddEntries(node, new[] { "Keywords", "Keyword: " + keyword.displayName }, nodeEntries); } foreach (var dropdown in m_Graph.dropdowns) { var node = new DropdownNode(); node.dropdown = dropdown; AddEntries(node, new[] { "Dropdowns", "dropdown: " + dropdown.displayName }, nodeEntries); } if (!hideCustomInterpolators) { foreach (var cibnode in m_Graph.vertexContext.blocks.Where(b => b.value.isCustomBlock)) { var node = Activator.CreateInstance <CustomInterpolatorNode>(); node.ConnectToCustomBlock(cibnode.value); AddEntries(node, new[] { "Custom Interpolator", cibnode.value.customName }, nodeEntries); } } Profiler.EndSample(); SortEntries(nodeEntries); currentNodeEntries = nodeEntries; Profiler.EndSample(); }
public IEnumerator MoveDirectoryTests() { yield return(null); // rename the directory AssetDatabase.MoveAsset(targetUnityDirectoryPath, targetUnityDirectoryPath2); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); var graphPath = targetUnityDirectoryPath2 + "/ShaderGraph.shadergraph"; OpenGraphWindow(graphPath); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); // try adding the subgraph node -- see if the asset still works after the files have been moved m_Graph = m_Window.graphObject.graph as GraphData; var subgraph = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(graphPath); var node = new SubGraphNode { asset = subgraph }; m_Graph.AddNode(node); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); yield return(null); CloseGraphWindow(); }
public void GenerateNodeEntries() { // First build up temporary data structure containing group & title as an array of strings (the last one is the actual title) and associated node type. List <NodeEntry> nodeEntries = new List <NodeEntry>(); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var type in assembly.GetTypesOrNothing()) { if (type.IsClass && !type.IsAbstract && (type.IsSubclassOf(typeof(AbstractMaterialNode))) && type != typeof(PropertyNode) && type != typeof(KeywordNode) && type != typeof(SubGraphNode)) { var attrs = type.GetCustomAttributes(typeof(TitleAttribute), false) as TitleAttribute[]; if (attrs != null && attrs.Length > 0) { var node = (AbstractMaterialNode)Activator.CreateInstance(type); AddEntries(node, attrs[0].title, nodeEntries); } } } } foreach (var guid in AssetDatabase.FindAssets(string.Format("t:{0}", typeof(SubGraphAsset)))) { var asset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(guid)); var node = new SubGraphNode { asset = asset }; var title = asset.path.Split('/').ToList(); if (asset.descendents.Contains(m_Graph.assetGuid) || asset.assetGuid == m_Graph.assetGuid) { continue; } if (string.IsNullOrEmpty(asset.path)) { AddEntries(node, new string[1] { asset.name }, nodeEntries); } else if (title[0] != k_HiddenFolderName) { title.Add(asset.name); AddEntries(node, title.ToArray(), nodeEntries); } } foreach (var property in m_Graph.properties) { var node = new PropertyNode(); node.owner = m_Graph; node.propertyGuid = property.guid; node.owner = null; AddEntries(node, new[] { "Properties", "Property: " + property.displayName }, nodeEntries); } foreach (var keyword in m_Graph.keywords) { var node = new KeywordNode(); node.owner = m_Graph; node.keywordGuid = keyword.guid; node.owner = null; AddEntries(node, new[] { "Keywords", "Keyword: " + keyword.displayName }, nodeEntries); } // Sort the entries lexicographically by group then title with the requirement that items always comes before sub-groups in the same group. // Example result: // - Art/BlendMode // - Art/Adjustments/ColorBalance // - Art/Adjustments/Contrast nodeEntries.Sort((entry1, entry2) => { for (var i = 0; i < entry1.title.Length; i++) { if (i >= entry2.title.Length) { return(1); } var value = entry1.title[i].CompareTo(entry2.title[i]); if (value != 0) { // Make sure that leaves go before nodes if (entry1.title.Length != entry2.title.Length && (i == entry1.title.Length - 1 || i == entry2.title.Length - 1)) { //once nodes are sorted, sort slot entries by slot order instead of alphebetically var alphaOrder = entry1.title.Length < entry2.title.Length ? -1 : 1; var slotOrder = entry1.compatibleSlotId.CompareTo(entry2.compatibleSlotId); return(alphaOrder.CompareTo(slotOrder)); } return(value); } } return(0); }); currentNodeEntries = nodeEntries; }
void CreateNode(object obj, Vector2 nodePosition) { var texture2D = obj as Texture2D; if (texture2D != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture"); bool isNormalMap = false; if (EditorUtility.IsPersistent(texture2D) && !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(texture2D))) { var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture2D)) as TextureImporter; if (importer != null) { isNormalMap = importer.textureType == TextureImporterType.NormalMap; } } var node = new SampleTexture2DNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); if (isNormalMap) { node.textureType = TextureType.Normal; } var inputslot = node.FindInputSlot <Texture2DInputMaterialSlot>(SampleTexture2DNode.TextureInputId); if (inputslot != null) { inputslot.texture = texture2D; } } var textureArray = obj as Texture2DArray; if (textureArray != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture Array"); var node = new SampleTexture2DArrayNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindSlot <Texture2DArrayInputMaterialSlot>(SampleTexture2DArrayNode.TextureInputId); if (inputslot != null) { inputslot.textureArray = textureArray; } } var texture3D = obj as Texture3D; if (texture3D != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture 3D"); var node = new SampleTexture3DNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindSlot <Texture3DInputMaterialSlot>(SampleTexture3DNode.TextureInputId); if (inputslot != null) { inputslot.texture = texture3D; } } var cubemap = obj as Cubemap; if (cubemap != null) { graph.owner.RegisterCompleteObjectUndo("Drag Cubemap"); var node = new SampleCubemapNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindInputSlot <CubemapInputMaterialSlot>(SampleCubemapNode.CubemapInputId); if (inputslot != null) { inputslot.cubemap = cubemap; } } var subGraphAsset = obj as SubGraphAsset; if (subGraphAsset != null) { graph.owner.RegisterCompleteObjectUndo("Drag Sub-Graph"); var node = new SubGraphNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; node.asset = subGraphAsset; graph.AddNode(node); } var blackboardField = obj as BlackboardField; if (blackboardField != null) { graph.owner.RegisterCompleteObjectUndo("Drag Graph Input"); switch (blackboardField.userData) { case AbstractShaderProperty property: { var node = new PropertyNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); // Setting the guid requires the graph to be set first. node.propertyGuid = property.guid; break; } case ShaderKeyword keyword: { var node = new KeywordNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); // Setting the guid requires the graph to be set first. node.keywordGuid = keyword.guid; break; } default: throw new ArgumentOutOfRangeException(); } } }
public void GenerateNodeEntries() { // First build up temporary data structure containing group & title as an array of strings (the last one is the actual title) and associated node type. List <NodeEntry> nodeEntries = new List <NodeEntry>(); if (target is ContextView contextView) { // Iterate all BlockFieldDescriptors currently cached on GraphData foreach (var field in m_Graph.blockFieldDescriptors) { if (field.isHidden) { continue; } // Test stage if (field.shaderStage != contextView.contextData.shaderStage) { continue; } // Create title List <string> title = ListPool <string> .Get(); if (!string.IsNullOrEmpty(field.path)) { var path = field.path.Split('/').ToList(); title.AddRange(path); } title.Add(field.displayName); // Create and initialize BlockNode instance then add entry var node = (BlockNode)Activator.CreateInstance(typeof(BlockNode)); node.Init(field); AddEntries(node, title.ToArray(), nodeEntries); } SortEntries(nodeEntries); currentNodeEntries = nodeEntries; return; } foreach (var type in TypeCache.GetTypesDerivedFrom <AbstractMaterialNode>()) { if ((!type.IsClass || type.IsAbstract) || type == typeof(PropertyNode) || type == typeof(KeywordNode) || type == typeof(SubGraphNode)) { continue; } if (type.GetCustomAttributes(typeof(TitleAttribute), false) is TitleAttribute[] attrs && attrs.Length > 0) { var node = (AbstractMaterialNode)Activator.CreateInstance(type); AddEntries(node, attrs[0].title, nodeEntries); } } foreach (var guid in AssetDatabase.FindAssets(string.Format("t:{0}", typeof(SubGraphAsset)))) { var asset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(guid)); var node = new SubGraphNode { asset = asset }; var title = asset.path.Split('/').ToList(); if (asset.descendents.Contains(m_Graph.assetGuid) || asset.assetGuid == m_Graph.assetGuid) { continue; } if (string.IsNullOrEmpty(asset.path)) { AddEntries(node, new string[1] { asset.name }, nodeEntries); } else if (title[0] != k_HiddenFolderName) { title.Add(asset.name); AddEntries(node, title.ToArray(), nodeEntries); } } foreach (var property in m_Graph.properties) { var node = new PropertyNode(); node.property = property; AddEntries(node, new[] { "Properties", "Property: " + property.displayName }, nodeEntries); } foreach (var keyword in m_Graph.keywords) { var node = new KeywordNode(); node.keyword = keyword; AddEntries(node, new[] { "Keywords", "Keyword: " + keyword.displayName }, nodeEntries); } SortEntries(nodeEntries); currentNodeEntries = nodeEntries; }
public void ToSubGraph() { var graphView = graphEditorView.graphView; var path = EditorUtility.SaveFilePanelInProject("Save Sub Graph", "New Shader Sub Graph", ShaderSubGraphImporter.Extension, ""); path = path.Replace(Application.dataPath, "Assets"); if (path.Length == 0) { return; } graphObject.RegisterCompleteObjectUndo("Convert To Subgraph"); var nodes = graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(); var bounds = Rect.MinMaxRect(float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity); foreach (var node in nodes) { var center = node.drawState.position.center; bounds = Rect.MinMaxRect( Mathf.Min(bounds.xMin, center.x), Mathf.Min(bounds.yMin, center.y), Mathf.Max(bounds.xMax, center.x), Mathf.Max(bounds.yMax, center.y)); } var middle = bounds.center; bounds.center = Vector2.zero; // Collect graph inputs var graphInputs = graphView.selection.OfType <BlackboardField>().Select(x => x.userData as ShaderInput); // Collect the property nodes and get the corresponding properties var propertyNodeGuids = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is PropertyNode)).Select(x => ((PropertyNode)x.node).propertyGuid); var metaProperties = graphView.graph.properties.Where(x => propertyNodeGuids.Contains(x.guid)); // Collect the keyword nodes and get the corresponding keywords var keywordNodeGuids = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is KeywordNode)).Select(x => ((KeywordNode)x.node).keywordGuid); var metaKeywords = graphView.graph.keywords.Where(x => keywordNodeGuids.Contains(x.guid)); var copyPasteGraph = new CopyPasteGraph( graphView.graph.assetGuid, graphView.selection.OfType <ShaderGroup>().Select(x => x.userData), graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(), graphView.selection.OfType <Edge>().Select(x => x.userData as IEdge), graphInputs, metaProperties, metaKeywords, graphView.selection.OfType <StickyNote>().Select(x => x.userData)); var deserialized = CopyPasteGraph.FromJson(JsonUtility.ToJson(copyPasteGraph, false)); if (deserialized == null) { return; } var subGraph = new GraphData { isSubGraph = true }; subGraph.path = "Sub Graphs"; var subGraphOutputNode = new SubGraphOutputNode(); { var drawState = subGraphOutputNode.drawState; drawState.position = new Rect(new Vector2(bounds.xMax + 200f, 0f), drawState.position.size); subGraphOutputNode.drawState = drawState; } subGraph.AddNode(subGraphOutputNode); // Always copy deserialized keyword inputs foreach (ShaderKeyword keyword in deserialized.metaKeywords) { ShaderInput copiedInput = keyword.Copy(); subGraph.SanitizeGraphInputName(copiedInput); subGraph.SanitizeGraphInputReferenceName(copiedInput, keyword.overrideReferenceName); subGraph.AddGraphInput(copiedInput); // Update the keyword nodes that depends on the copied keyword var dependentKeywordNodes = deserialized.GetNodes <KeywordNode>().Where(x => x.keywordGuid == keyword.guid); foreach (var node in dependentKeywordNodes) { node.owner = graphView.graph; node.keywordGuid = copiedInput.guid; } } var groupGuidMap = new Dictionary <Guid, Guid>(); foreach (GroupData groupData in deserialized.groups) { var oldGuid = groupData.guid; var newGuid = groupData.RewriteGuid(); groupGuidMap[oldGuid] = newGuid; subGraph.CreateGroup(groupData); } List <Guid> groupGuids = new List <Guid>(); var nodeGuidMap = new Dictionary <Guid, Guid>(); foreach (var node in deserialized.GetNodes <AbstractMaterialNode>()) { var oldGuid = node.guid; var newGuid = node.RewriteGuid(); nodeGuidMap[oldGuid] = newGuid; var drawState = node.drawState; drawState.position = new Rect(drawState.position.position - middle, drawState.position.size); node.drawState = drawState; if (!groupGuids.Contains(node.groupGuid)) { groupGuids.Add(node.groupGuid); } // Checking if the group guid is also being copied. // If not then nullify that guid if (node.groupGuid != Guid.Empty) { node.groupGuid = !groupGuidMap.ContainsKey(node.groupGuid) ? Guid.Empty : groupGuidMap[node.groupGuid]; } subGraph.AddNode(node); } foreach (var note in deserialized.stickyNotes) { if (!groupGuids.Contains(note.groupGuid)) { groupGuids.Add(note.groupGuid); } if (note.groupGuid != Guid.Empty) { note.groupGuid = !groupGuidMap.ContainsKey(note.groupGuid) ? Guid.Empty : groupGuidMap[note.groupGuid]; } note.RewriteGuid(); subGraph.AddStickyNote(note); } // 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; var inputSlot = edge.inputSlot; Guid remappedOutputNodeGuid; Guid remappedInputNodeGuid; var outputSlotExistsInSubgraph = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid); var inputSlotExistsInSubgraph = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid); // pasting nice internal links! if (outputSlotExistsInSubgraph && inputSlotExistsInSubgraph) { var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId); var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotId); subGraph.Connect(outputSlotRef, inputSlotRef); } // one edge needs to go to outside world else if (outputSlotExistsInSubgraph) { externalInputSlots.Add(edge); } else if (inputSlotExistsInSubgraph) { externalOutputSlots.Add(edge); } } // Find the unique edges coming INTO the graph var uniqueIncomingEdges = externalOutputSlots.GroupBy( edge => edge.outputSlot, edge => edge, (key, edges) => new { slotRef = key, edges = edges.ToList() }); var externalInputNeedingConnection = new List <KeyValuePair <IEdge, AbstractShaderProperty> >(); var amountOfProps = uniqueIncomingEdges.Count(); const int height = 40; const int subtractHeight = 20; var propPos = new Vector2(0, -((amountOfProps / 2) + height) - subtractHeight); foreach (var group in uniqueIncomingEdges) { var sr = group.slotRef; var fromNode = graphObject.graph.GetNodeFromGuid(sr.nodeGuid); var fromSlot = fromNode.FindOutputSlot <MaterialSlot>(sr.slotId); AbstractShaderProperty prop; switch (fromSlot.concreteValueType) { case ConcreteSlotValueType.Texture2D: prop = new Texture2DShaderProperty(); break; case ConcreteSlotValueType.Texture2DArray: prop = new Texture2DArrayShaderProperty(); break; case ConcreteSlotValueType.Texture3D: prop = new Texture3DShaderProperty(); break; case ConcreteSlotValueType.Cubemap: prop = new CubemapShaderProperty(); break; case ConcreteSlotValueType.Vector4: prop = new Vector4ShaderProperty(); break; case ConcreteSlotValueType.Vector3: prop = new Vector3ShaderProperty(); break; case ConcreteSlotValueType.Vector2: prop = new Vector2ShaderProperty(); break; case ConcreteSlotValueType.Vector1: prop = new Vector1ShaderProperty(); break; case ConcreteSlotValueType.Boolean: prop = new BooleanShaderProperty(); break; case ConcreteSlotValueType.Matrix2: prop = new Matrix2ShaderProperty(); break; case ConcreteSlotValueType.Matrix3: prop = new Matrix3ShaderProperty(); break; case ConcreteSlotValueType.Matrix4: prop = new Matrix4ShaderProperty(); break; case ConcreteSlotValueType.SamplerState: prop = new SamplerStateShaderProperty(); break; case ConcreteSlotValueType.Gradient: prop = new GradientShaderProperty(); break; default: throw new ArgumentOutOfRangeException(); } if (prop != null) { var materialGraph = (GraphData)graphObject.graph; var fromPropertyNode = fromNode as PropertyNode; var fromProperty = fromPropertyNode != null?materialGraph.properties.FirstOrDefault(p => p.guid == fromPropertyNode.propertyGuid) : null; prop.displayName = fromProperty != null ? fromProperty.displayName : fromSlot.concreteValueType.ToString(); subGraph.AddGraphInput(prop); var propNode = new PropertyNode(); { var drawState = propNode.drawState; drawState.position = new Rect(new Vector2(bounds.xMin - 300f, 0f) + propPos, drawState.position.size); propPos += new Vector2(0, height); propNode.drawState = drawState; } 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, AbstractShaderProperty>(edge, prop)); } } } var uniqueOutgoingEdges = externalInputSlots.GroupBy( edge => edge.outputSlot, edge => edge, (key, edges) => new { slot = key, edges = edges.ToList() }); var externalOutputsNeedingConnection = new List <KeyValuePair <IEdge, IEdge> >(); foreach (var group in uniqueOutgoingEdges) { var outputNode = subGraph.outputNode as SubGraphOutputNode; AbstractMaterialNode node = graphView.graph.GetNodeFromGuid(group.edges[0].outputSlot.nodeGuid); MaterialSlot slot = node.FindSlot <MaterialSlot>(group.edges[0].outputSlot.slotId); var slotId = outputNode.AddSlot(slot.concreteValueType); var inputSlotRef = new SlotReference(outputNode.guid, slotId); foreach (var edge in group.edges) { var newEdge = subGraph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotId), inputSlotRef); externalOutputsNeedingConnection.Add(new KeyValuePair <IEdge, IEdge>(edge, newEdge)); } } if (FileUtilities.WriteShaderGraphToDisk(path, subGraph)) { AssetDatabase.ImportAsset(path); } var loadedSubGraph = AssetDatabase.LoadAssetAtPath(path, typeof(SubGraphAsset)) as SubGraphAsset; if (loadedSubGraph == null) { return; } var subGraphNode = new SubGraphNode(); var ds = subGraphNode.drawState; ds.position = new Rect(middle - new Vector2(100f, 150f), Vector2.zero); subGraphNode.drawState = ds; // Add the subgraph into the group if the nodes was all in the same group group if (groupGuids.Count == 1) { subGraphNode.groupGuid = groupGuids[0]; } graphObject.graph.AddNode(subGraphNode); subGraphNode.asset = loadedSubGraph; foreach (var edgeMap in externalInputNeedingConnection) { graphObject.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.guid.GetHashCode())); } foreach (var edgeMap in externalOutputsNeedingConnection) { graphObject.graph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot); } graphObject.graph.RemoveElements( graphView.selection.OfType <IShaderNodeView>().Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(), new IEdge[] {}, new GroupData[] {}, graphView.selection.OfType <StickyNote>().Select(x => x.userData).ToArray()); graphObject.graph.ValidateGraph(); }
void CreateNode(object obj, Vector2 nodePosition) { var texture2D = obj as Texture2D; if (texture2D != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture"); bool isNormalMap = false; if (EditorUtility.IsPersistent(texture2D) && !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(texture2D))) { var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture2D)) as TextureImporter; if (importer != null) { isNormalMap = importer.textureType == TextureImporterType.NormalMap; } } var node = new SampleTexture2DNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); if (isNormalMap) { node.textureType = TextureType.Normal; } var inputslot = node.FindInputSlot <Texture2DInputMaterialSlot>(SampleTexture2DNode.TextureInputId); if (inputslot != null) { inputslot.texture = texture2D; } } var textureArray = obj as Texture2DArray; if (textureArray != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture Array"); var property = new Texture2DArrayShaderProperty { displayName = textureArray.name, value = { textureArray = textureArray } }; graph.AddShaderProperty(property); var node = new SampleTexture2DArrayNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindSlot <Texture2DArrayInputMaterialSlot>(SampleTexture2DArrayNode.TextureInputId); if (inputslot != null) { inputslot.textureArray = textureArray; } } var texture3D = obj as Texture3D; if (texture3D != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture 3D"); var property = new Texture3DShaderProperty { displayName = texture3D.name, value = { texture = texture3D } }; graph.AddShaderProperty(property); var node = new SampleTexture3DNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindSlot <Texture3DInputMaterialSlot>(SampleTexture3DNode.TextureInputId); if (inputslot != null) { inputslot.texture = texture3D; } } var cubemap = obj as Cubemap; if (cubemap != null) { graph.owner.RegisterCompleteObjectUndo("Drag Cubemap"); var property = new CubemapShaderProperty { displayName = cubemap.name, value = { cubemap = cubemap } }; graph.AddShaderProperty(property); var node = new SampleCubemapNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindInputSlot <CubemapInputMaterialSlot>(SampleCubemapNode.CubemapInputId); if (inputslot != null) { inputslot.cubemap = cubemap; } } var subGraphAsset = obj as SubGraphAsset; if (subGraphAsset != null) { graph.owner.RegisterCompleteObjectUndo("Drag Sub-Graph"); var node = new SubGraphNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; node.subGraphAsset = subGraphAsset; graph.AddNode(node); } var blackboardField = obj as BlackboardField; if (blackboardField != null) { AbstractShaderProperty property = blackboardField.userData as AbstractShaderProperty; if (property != null) { graph.owner.RegisterCompleteObjectUndo("Drag Property"); var node = new PropertyNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); // Setting the guid requires the graph to be set first. node.propertyGuid = property.guid; } } }
void CreateNode(object obj, Vector2 nodePosition) { var texture2D = obj as Texture2D; if (texture2D != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture"); bool isNormalMap = false; if (EditorUtility.IsPersistent(texture2D) && !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(texture2D))) { var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture2D)) as TextureImporter; if (importer != null) { isNormalMap = importer.textureType == TextureImporterType.NormalMap; } } var node = new SampleTexture2DNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); if (isNormalMap) { node.textureType = TextureType.Normal; } var inputslot = node.FindInputSlot <Texture2DInputMaterialSlot>(SampleTexture2DNode.TextureInputId); if (inputslot != null) { inputslot.texture = texture2D; } } var textureArray = obj as Texture2DArray; if (textureArray != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture Array"); var node = new SampleTexture2DArrayNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindSlot <Texture2DArrayInputMaterialSlot>(SampleTexture2DArrayNode.TextureInputId); if (inputslot != null) { inputslot.textureArray = textureArray; } } var texture3D = obj as Texture3D; if (texture3D != null) { graph.owner.RegisterCompleteObjectUndo("Drag Texture 3D"); var node = new SampleTexture3DNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindSlot <Texture3DInputMaterialSlot>(SampleTexture3DNode.TextureInputId); if (inputslot != null) { inputslot.texture = texture3D; } } var cubemap = obj as Cubemap; if (cubemap != null) { graph.owner.RegisterCompleteObjectUndo("Drag Cubemap"); var node = new SampleCubemapNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); var inputslot = node.FindInputSlot <CubemapInputMaterialSlot>(SampleCubemapNode.CubemapInputId); if (inputslot != null) { inputslot.cubemap = cubemap; } } var subGraphAsset = obj as SubGraphAsset; if (subGraphAsset != null) { graph.owner.RegisterCompleteObjectUndo("Drag Sub-Graph"); var node = new SubGraphNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; node.asset = subGraphAsset; graph.AddNode(node); } var blackboardField = obj as BlackboardField; if (blackboardField != null) { graph.owner.RegisterCompleteObjectUndo("Drag Graph Input"); switch (blackboardField.userData) { case AbstractShaderProperty property: { // This could be from another graph, in which case we add a copy of the ShaderInput to this graph. if (graph.properties.FirstOrDefault(p => p.guid == property.guid) == null) { var copy = (AbstractShaderProperty)property.Copy(); graph.SanitizeGraphInputName(copy); graph.SanitizeGraphInputReferenceName(copy, property.overrideReferenceName); // We do want to copy the overrideReferenceName property = copy; graph.AddGraphInput(property); } var node = new PropertyNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); // Setting the guid requires the graph to be set first. node.propertyGuid = property.guid; break; } case ShaderKeyword keyword: { // This could be from another graph, in which case we add a copy of the ShaderInput to this graph. if (graph.keywords.FirstOrDefault(k => k.guid == keyword.guid) == null) { var copy = (ShaderKeyword)keyword.Copy(); graph.SanitizeGraphInputName(copy); graph.SanitizeGraphInputReferenceName(copy, keyword.overrideReferenceName); // We do want to copy the overrideReferenceName keyword = copy; graph.AddGraphInput(keyword); } var node = new KeywordNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; graph.AddNode(node); // Setting the guid requires the graph to be set first. node.keywordGuid = keyword.guid; break; } default: throw new ArgumentOutOfRangeException(); } } }
public void GenerateNodeEntries() { Profiler.BeginSample("SearchWindowProvider.GenerateNodeEntries"); // First build up temporary data structure containing group & title as an array of strings (the last one is the actual title) and associated node type. List <NodeEntry> nodeEntries = new List <NodeEntry>(); if (target is ContextView contextView) { // Iterate all BlockFieldDescriptors currently cached on GraphData foreach (var field in m_Graph.blockFieldDescriptors) { if (field.isHidden) { continue; } // Test stage if (field.shaderStage != contextView.contextData.shaderStage) { continue; } // Create title List <string> title = ListPool <string> .Get(); if (!string.IsNullOrEmpty(field.path)) { var path = field.path.Split('/').ToList(); title.AddRange(path); } title.Add(field.displayName); // Create and initialize BlockNode instance then add entry var node = (BlockNode)Activator.CreateInstance(typeof(BlockNode)); node.Init(field); AddEntries(node, title.ToArray(), nodeEntries); } SortEntries(nodeEntries); currentNodeEntries = nodeEntries; return; } foreach (var type in NodeClassCache.knownNodeTypes) { if ((!type.IsClass || type.IsAbstract) || type == typeof(PropertyNode) || type == typeof(KeywordNode) || type == typeof(SubGraphNode)) { continue; } TitleAttribute titleAttribute = NodeClassCache.GetAttributeOnNodeType <TitleAttribute>(type); if (titleAttribute != null) { var node = (AbstractMaterialNode)Activator.CreateInstance(type); if (ShaderGraphPreferences.allowDeprecatedBehaviors && node.latestVersion > 0) { var versions = node.allowedNodeVersions ?? Enumerable.Range(0, node.latestVersion + 1); bool multiple = (versions.Count() > 1); foreach (int i in versions) { var depNode = (AbstractMaterialNode)Activator.CreateInstance(type); depNode.ChangeVersion(i); if (multiple) { AddEntries(depNode, titleAttribute.title.Append($"V{i}").ToArray(), nodeEntries); } else { AddEntries(depNode, titleAttribute.title, nodeEntries); } } } else { AddEntries(node, titleAttribute.title, nodeEntries); } } } foreach (var guid in AssetDatabase.FindAssets(string.Format("t:{0}", typeof(SubGraphAsset)))) { var asset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(guid)); var node = new SubGraphNode { asset = asset }; var title = asset.path.Split('/').ToList(); if (asset.descendents.Contains(m_Graph.assetGuid) || asset.assetGuid == m_Graph.assetGuid) { continue; } if (string.IsNullOrEmpty(asset.path)) { AddEntries(node, new string[1] { asset.name }, nodeEntries); } else if (title[0] != k_HiddenFolderName) { title.Add(asset.name); AddEntries(node, title.ToArray(), nodeEntries); } } foreach (var property in m_Graph.properties) { if (property is Serialization.MultiJsonInternal.UnknownShaderPropertyType) { continue; } var node = new PropertyNode(); node.property = property; AddEntries(node, new[] { "Properties", "Property: " + property.displayName }, nodeEntries); } foreach (var keyword in m_Graph.keywords) { var node = new KeywordNode(); node.keyword = keyword; AddEntries(node, new[] { "Keywords", "Keyword: " + keyword.displayName }, nodeEntries); } SortEntries(nodeEntries); currentNodeEntries = nodeEntries; Profiler.EndSample(); }
void CreateNode(Object obj, Vector2 nodePosition) { var texture2D = obj as Texture2D; if (texture2D != null) { m_Graph.owner.RegisterCompleteObjectUndo("Drag Texture"); bool isNormalMap = false; if (EditorUtility.IsPersistent(texture2D) && !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(texture2D))) { var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture2D)) as TextureImporter; if (importer != null) { isNormalMap = importer.textureType == TextureImporterType.NormalMap; } } var node = new SampleTexture2DNode(); if (isNormalMap) { node.textureType = TextureType.Normal; } var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; m_Graph.AddNode(node); var inputslot = node.FindSlot <Texture2DInputMaterialSlot>(SampleTexture2DNode.TextureInputId); if (inputslot != null) { inputslot.texture = texture2D; } } var cubemap = obj as Cubemap; if (cubemap != null) { m_Graph.owner.RegisterCompleteObjectUndo("Drag Cubemap"); var property = new CubemapShaderProperty { displayName = cubemap.name, value = { cubemap = cubemap } }; m_Graph.AddShaderProperty(property); var node = new SampleCubemapNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; m_Graph.AddNode(node); var inputslot = node.FindSlot <CubemapInputMaterialSlot>(SampleCubemapNode.CubemapInputId); if (inputslot != null) { inputslot.cubemap = cubemap; } } var subGraphAsset = obj as MaterialSubGraphAsset; if (subGraphAsset != null) { m_Graph.owner.RegisterCompleteObjectUndo("Drag Sub-Graph"); var node = new SubGraphNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; node.subGraphAsset = subGraphAsset; m_Graph.AddNode(node); } }