Skip to content

Commit 4d843ce

Browse files
elizabeth-legrosChris Tchou
andauthored
Fix "ToSubgraph" with multiple outputs and allow passthrough (#2074)
* first pass, need to talk to Landon about fix * Update CHANGELOG.md * making found properties also look for a matching reference name * code review changes * code review bug fix and made copying properties/keywords form the blackboard consistent with how nodes behave in searching for properties/keywords * small bugfix for duplicating properties on graph/between graphs * more bugfixing * fixing to subgraph workflow * code review notes * more bugfixing and improvements * adding fixup of graph with convert to subgraph for alex to test * bugfixing * Update CHANGELOG.md * adding back in error throw that was commented out for testing * Update CHANGELOG.md * Fixing formatting Co-authored-by: Chris Tchou <ctchou@unity3d.com>
1 parent a31a2b3 commit 4d843ce

File tree

4 files changed

+182
-73
lines changed

4 files changed

+182
-73
lines changed

com.unity.shadergraph/CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
3131
- Shaders using SamplerState types now compile with GLES2 (SamplerStates are ignored, falls back to Texture-associated sampler state) [1292031]
3232
- Fixed Graph Inspector scaling that was allocating too much space to the labels [1268134]
3333

34-
### Fixed
34+
### Fixed
35+
- Fixed some issues with our Convert To Subgraph contextual menu to allow passthrough and fix inputs/outputs getting lost.
3536
- Fixed issue where a NullReferenceException would be thrown on resetting reference name for a Shader Graph property
36-
-
3737

3838
## [10.2.0] - 2020-10-19
3939

@@ -64,6 +64,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6464
- Fixed an issue where unknown type Nodes (i.e. HDRP-only nodes used without HDRP package) could be copied, resulting in an unloadable graph [1288475]
6565
- Fixed an issue where dropping HDRP-only properties from the blackboard field into the graph would soft-lock the graph [1288887]
6666

67+
6768
## [10.1.0] - 2020-10-12
6869

6970
### Added

com.unity.shadergraph/Editor/Data/Graphs/GraphData.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,7 @@ void RemoveEdgeNoValidate(IEdge e, bool reevaluateActivity = true)
10631063
if (m_NodeEdges.TryGetValue(output.objectId, out outputNodeEdges))
10641064
outputNodeEdges.Remove(e);
10651065

1066+
m_AddedEdges.Remove(e);
10661067
m_RemovedEdges.Add(e);
10671068
if (b != null)
10681069
{
@@ -1135,6 +1136,21 @@ public IEnumerable<IEdge> GetEdges(SlotReference s)
11351136
return edges;
11361137
}
11371138

1139+
public void GetEdges(AbstractMaterialNode node, List<IEdge> foundEdges)
1140+
{
1141+
if (m_NodeEdges.TryGetValue(node.objectId, out var edges))
1142+
{
1143+
foundEdges.AddRange(edges);
1144+
}
1145+
}
1146+
1147+
public IEnumerable<IEdge> GetEdges(AbstractMaterialNode node)
1148+
{
1149+
List<IEdge> edges = new List<IEdge>();
1150+
GetEdges(node, edges);
1151+
return edges;
1152+
}
1153+
11381154
public void ForeachHLSLProperty(Action<HLSLProperty> action)
11391155
{
11401156
foreach (var prop in properties)

com.unity.shadergraph/Editor/Drawing/MaterialGraphEditWindow.cs

Lines changed: 155 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -688,13 +688,14 @@ public void ToSubGraph()
688688
var metaKeywords = graphView.graph.keywords.Where(x => keywordNodes.Contains(x));
689689

690690
var copyPasteGraph = new CopyPasteGraph(graphView.selection.OfType<ShaderGroup>().Select(x => x.userData),
691-
graphView.selection.OfType<IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(),
691+
nodes,
692692
graphView.selection.OfType<Edge>().Select(x => x.userData as Graphing.Edge),
693693
graphInputs,
694694
metaProperties,
695695
metaKeywords,
696696
graphView.selection.OfType<StickyNote>().Select(x => x.userData),
697-
true);
697+
true,
698+
false);
698699

699700
// why do we serialize and deserialize only to make copies of everything in the steps below?
700701
// is this just to clear out all non-serialized data?
@@ -763,6 +764,7 @@ public void ToSubGraph()
763764
// figure out what needs remapping
764765
var externalOutputSlots = new List<Graphing.Edge>();
765766
var externalInputSlots = new List<Graphing.Edge>();
767+
var passthroughSlots = new List<Graphing.Edge>();
766768
foreach (var edge in deserialized.edges)
767769
{
768770
var outputSlot = edge.outputSlot;
@@ -785,6 +787,12 @@ public void ToSubGraph()
785787
{
786788
externalOutputSlots.Add(edge);
787789
}
790+
else
791+
{
792+
externalInputSlots.Add(edge);
793+
externalOutputSlots.Add(edge);
794+
passthroughSlots.Add(edge);
795+
}
788796
}
789797

790798
// Find the unique edges coming INTO the graph
@@ -800,6 +808,9 @@ public void ToSubGraph()
800808
const int subtractHeight = 20;
801809
var propPos = new Vector2(0, -((amountOfProps / 2) + height) - subtractHeight);
802810

811+
var passthroughSlotRefLookup = new Dictionary<SlotReference, SlotReference>();
812+
813+
var passedInProperties = new Dictionary<AbstractShaderProperty, AbstractShaderProperty>();
803814
foreach (var group in uniqueIncomingEdges)
804815
{
805816
var sr = group.slotRef;
@@ -812,68 +823,78 @@ public void ToSubGraph()
812823
: null;
813824

814825
AbstractShaderProperty prop;
815-
switch (fromSlot.concreteValueType)
826+
if (fromProperty != null && passedInProperties.TryGetValue(fromProperty, out prop))
816827
{
817-
case ConcreteSlotValueType.Texture2D:
818-
prop = new Texture2DShaderProperty();
819-
break;
820-
case ConcreteSlotValueType.Texture2DArray:
821-
prop = new Texture2DArrayShaderProperty();
822-
break;
823-
case ConcreteSlotValueType.Texture3D:
824-
prop = new Texture3DShaderProperty();
825-
break;
826-
case ConcreteSlotValueType.Cubemap:
827-
prop = new CubemapShaderProperty();
828-
break;
829-
case ConcreteSlotValueType.Vector4:
830-
prop = new Vector4ShaderProperty();
831-
break;
832-
case ConcreteSlotValueType.Vector3:
833-
prop = new Vector3ShaderProperty();
834-
break;
835-
case ConcreteSlotValueType.Vector2:
836-
prop = new Vector2ShaderProperty();
837-
break;
838-
case ConcreteSlotValueType.Vector1:
839-
prop = new Vector1ShaderProperty();
840-
break;
841-
case ConcreteSlotValueType.Boolean:
842-
prop = new BooleanShaderProperty();
843-
break;
844-
case ConcreteSlotValueType.Matrix2:
845-
prop = new Matrix2ShaderProperty();
846-
break;
847-
case ConcreteSlotValueType.Matrix3:
848-
prop = new Matrix3ShaderProperty();
849-
break;
850-
case ConcreteSlotValueType.Matrix4:
851-
prop = new Matrix4ShaderProperty();
852-
break;
853-
case ConcreteSlotValueType.SamplerState:
854-
prop = new SamplerStateShaderProperty();
855-
break;
856-
case ConcreteSlotValueType.Gradient:
857-
prop = new GradientShaderProperty();
858-
break;
859-
case ConcreteSlotValueType.VirtualTexture:
860-
prop = new VirtualTextureShaderProperty()
861-
{
862-
// also copy the VT settings over from the original property (if there is one)
863-
value = (fromProperty as VirtualTextureShaderProperty)?.value ?? new SerializableVirtualTexture()
864-
};
865-
break;
866-
default:
867-
throw new ArgumentOutOfRangeException();
868828
}
829+
else
830+
{
831+
switch (fromSlot.concreteValueType)
832+
{
833+
case ConcreteSlotValueType.Texture2D:
834+
prop = new Texture2DShaderProperty();
835+
break;
836+
case ConcreteSlotValueType.Texture2DArray:
837+
prop = new Texture2DArrayShaderProperty();
838+
break;
839+
case ConcreteSlotValueType.Texture3D:
840+
prop = new Texture3DShaderProperty();
841+
break;
842+
case ConcreteSlotValueType.Cubemap:
843+
prop = new CubemapShaderProperty();
844+
break;
845+
case ConcreteSlotValueType.Vector4:
846+
prop = new Vector4ShaderProperty();
847+
break;
848+
case ConcreteSlotValueType.Vector3:
849+
prop = new Vector3ShaderProperty();
850+
break;
851+
case ConcreteSlotValueType.Vector2:
852+
prop = new Vector2ShaderProperty();
853+
break;
854+
case ConcreteSlotValueType.Vector1:
855+
prop = new Vector1ShaderProperty();
856+
break;
857+
case ConcreteSlotValueType.Boolean:
858+
prop = new BooleanShaderProperty();
859+
break;
860+
case ConcreteSlotValueType.Matrix2:
861+
prop = new Matrix2ShaderProperty();
862+
break;
863+
case ConcreteSlotValueType.Matrix3:
864+
prop = new Matrix3ShaderProperty();
865+
break;
866+
case ConcreteSlotValueType.Matrix4:
867+
prop = new Matrix4ShaderProperty();
868+
break;
869+
case ConcreteSlotValueType.SamplerState:
870+
prop = new SamplerStateShaderProperty();
871+
break;
872+
case ConcreteSlotValueType.Gradient:
873+
prop = new GradientShaderProperty();
874+
break;
875+
case ConcreteSlotValueType.VirtualTexture:
876+
prop = new VirtualTextureShaderProperty()
877+
{
878+
// also copy the VT settings over from the original property (if there is one)
879+
value = (fromProperty as VirtualTextureShaderProperty)?.value ?? new SerializableVirtualTexture()
880+
};
881+
break;
882+
default:
883+
throw new ArgumentOutOfRangeException();
884+
}
869885

870-
prop.displayName = fromProperty != null
871-
? fromProperty.displayName
872-
: fromSlot.concreteValueType.ToString();
873-
prop.displayName = GraphUtil.SanitizeName(subGraph.addedInputs.Select(p => p.displayName), "{0} ({1})",
874-
prop.displayName);
886+
prop.displayName = fromProperty != null
887+
? fromProperty.displayName
888+
: fromSlot.concreteValueType.ToString();
889+
prop.displayName = GraphUtil.SanitizeName(subGraph.addedInputs.Select(p => p.displayName), "{0} ({1})",
890+
prop.displayName);
891+
subGraph.AddGraphInput(prop);
892+
if (fromProperty != null)
893+
{
894+
passedInProperties.Add(fromProperty, prop);
895+
}
896+
}
875897

876-
subGraph.AddGraphInput(prop);
877898
var propNode = new PropertyNode();
878899
{
879900
var drawState = propNode.drawState;
@@ -885,13 +906,45 @@ public void ToSubGraph()
885906
subGraph.AddNode(propNode);
886907
propNode.property = prop;
887908

909+
910+
Vector2 avg = Vector2.zero;
888911
foreach (var edge in group.edges)
889912
{
890-
subGraph.Connect(
891-
new SlotReference(propNode, PropertyNode.OutputSlotId),
892-
edge.inputSlot);
893-
externalInputNeedingConnection.Add(new KeyValuePair<IEdge, AbstractShaderProperty>(edge, prop));
913+
if (passthroughSlots.Contains(edge) && !passthroughSlotRefLookup.ContainsKey(sr))
914+
{
915+
passthroughSlotRefLookup.Add(sr, new SlotReference(propNode, PropertyNode.OutputSlotId));
916+
}
917+
else
918+
{
919+
subGraph.Connect(
920+
new SlotReference(propNode, PropertyNode.OutputSlotId),
921+
edge.inputSlot);
922+
923+
int i;
924+
var inputs = edge.inputSlot.node.GetInputSlots<MaterialSlot>().ToList();
925+
926+
for (i = 0; i < inputs.Count; ++i)
927+
{
928+
if (inputs[i].slotReference.slotId == edge.inputSlot.slotId)
929+
{
930+
break;
931+
}
932+
}
933+
avg += new Vector2(edge.inputSlot.node.drawState.position.xMin, edge.inputSlot.node.drawState.position.center.y + 30f * i);
934+
}
935+
//we collapse input properties so dont add edges that are already being added
936+
if (!externalInputNeedingConnection.Any(x => x.Key.outputSlot.slot == edge.outputSlot.slot && x.Value == prop))
937+
{
938+
externalInputNeedingConnection.Add(new KeyValuePair<IEdge, AbstractShaderProperty>(edge, prop));
939+
}
894940
}
941+
avg /= group.edges.Count;
942+
var pos = avg - new Vector2(150f, 0f);
943+
propNode.drawState = new DrawState()
944+
{
945+
position = new Rect(pos, propNode.drawState.position.size),
946+
expanded = propNode.drawState.expanded
947+
};
895948
}
896949

897950
var uniqueOutgoingEdges = externalInputSlots.GroupBy(
@@ -912,7 +965,7 @@ public void ToSubGraph()
912965

913966
foreach (var edge in group.edges)
914967
{
915-
var newEdge = subGraph.Connect(edge.outputSlot, inputSlotRef);
968+
var newEdge = subGraph.Connect(passthroughSlotRefLookup.TryGetValue(edge.outputSlot, out SlotReference remap) ? remap : edge.outputSlot, inputSlotRef);
916969
externalOutputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge));
917970
}
918971
}
@@ -961,10 +1014,46 @@ public void ToSubGraph()
9611014
}
9621015

9631016
graphObject.graph.RemoveElements(
964-
graphView.selection.OfType<IShaderNodeView>().Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(),
1017+
graphView.selection.OfType<IShaderNodeView>().Select(x => x.node).Where(x => !(x is PropertyNode || x is SubGraphOutputNode) && x.allowedInSubGraph).ToArray(),
9651018
new IEdge[] {},
9661019
new GroupData[] {},
9671020
graphView.selection.OfType<StickyNote>().Select(x => x.userData).ToArray());
1021+
1022+
List<GraphElement> moved = new List<GraphElement>();
1023+
foreach (var nodeView in graphView.selection.OfType<IShaderNodeView>())
1024+
{
1025+
var node = nodeView.node;
1026+
if (graphView.graph.removedNodes.Contains(node) || node is SubGraphOutputNode)
1027+
{
1028+
continue;
1029+
}
1030+
1031+
var edges = graphView.graph.GetEdges(node);
1032+
int numEdges = edges.Count();
1033+
if (numEdges == 0)
1034+
{
1035+
graphView.graph.RemoveNode(node);
1036+
}
1037+
else if (numEdges == 1 && edges.First().inputSlot.node != node) //its an output edge
1038+
{
1039+
var edge = edges.First();
1040+
int i;
1041+
var inputs = edge.inputSlot.node.GetInputSlots<MaterialSlot>().ToList();
1042+
for (i = 0; i < inputs.Count; ++i)
1043+
{
1044+
if (inputs[i].slotReference.slotId == edge.inputSlot.slotId)
1045+
{
1046+
break;
1047+
}
1048+
}
1049+
node.drawState = new DrawState()
1050+
{
1051+
position = new Rect(new Vector2(edge.inputSlot.node.drawState.position.xMin, edge.inputSlot.node.drawState.position.center.y) - new Vector2(150f, -30f * i), node.drawState.position.size),
1052+
expanded = node.drawState.expanded
1053+
};
1054+
(nodeView as GraphElement).SetPosition(node.drawState.position);
1055+
}
1056+
}
9681057
graphObject.graph.ValidateGraph();
9691058
}
9701059

com.unity.shadergraph/Editor/Util/CopyPasteGraph.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ sealed class CopyPasteGraph : JsonObject
4747
public CopyPasteGraph() {}
4848

4949
public CopyPasteGraph(IEnumerable<GroupData> groups, IEnumerable<AbstractMaterialNode> nodes, IEnumerable<Edge> edges,
50-
IEnumerable<ShaderInput> inputs, IEnumerable<AbstractShaderProperty> metaProperties, IEnumerable<ShaderKeyword> metaKeywords, IEnumerable<StickyNoteData> notes, bool keepOutputEdges = false)
50+
IEnumerable<ShaderInput> inputs, IEnumerable<AbstractShaderProperty> metaProperties, IEnumerable<ShaderKeyword> metaKeywords, IEnumerable<StickyNoteData> notes,
51+
bool keepOutputEdges = false, bool removeOrphanEdges = true)
5152
{
5253
if (groups != null)
5354
{
@@ -103,10 +104,12 @@ public CopyPasteGraph(IEnumerable<GroupData> groups, IEnumerable<AbstractMateria
103104
AddMetaKeyword(metaKeyword);
104105
}
105106

106-
m_Edges = m_Edges
107-
.Distinct()
108-
.Where(edge => nodeSet.Contains(edge.inputSlot.node) || (keepOutputEdges && nodeSet.Contains(edge.outputSlot.node)))
109-
.ToList();
107+
var distinct = m_Edges.Distinct();
108+
if (removeOrphanEdges)
109+
{
110+
distinct = distinct.Where(edge => nodeSet.Contains(edge.inputSlot.node) || (keepOutputEdges && nodeSet.Contains(edge.outputSlot.node)));
111+
}
112+
m_Edges = distinct.ToList();
110113
}
111114

112115
void AddGroup(GroupData group)

0 commit comments

Comments
 (0)