1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
using GraphProcessor;
using UnityEngine.UIElements;
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
[NodeCustomEditor(typeof(KeyframeNode))]
public class KeyframeNodeView : BaseNodeView
{
Button generateButton;
const string ERROR_TYPE = "GameObject input has wrong type";
const string ERROR_REND = "GameObject must have a MeshRenderer component";
public override void Enable()
{
generateButton = new Button(OnGenerateClick) { text = "Generate Keyframe" };
controlsContainer.Add(generateButton);
onPortConnected += _ => Validate();
onPortDisconnected += _ => Validate();
schedule.Execute(Validate).Every(200);
Validate();
}
void OnGenerateClick()
{
// Process the graph to propagate values through connections
var processor = new ProcessGraphProcessor(nodeTarget.graph);
processor.Run();
var go = GetConnectedGameObject();
if (go == null) return;
var rend = go.GetComponent<MeshRenderer>();
if (rend == null) return;
var foldNode = GetConnectedFoldNode();
// Accumulate nodes. We are going backwards from the output node
// (KeyframeNode) to the root node.
var foldNodes = new Stack<BaseFoldNode>();
var cur = foldNode;
while (cur != null) {
foldNodes.Push(cur);
cur = GetInputFoldNode(cur);
}
var mpb = new MaterialPropertyBlock();
rend.GetPropertyBlock(mpb);
// Set material properties for all 16 slots.
const int kNumSlots = 16;
for (int i = 0; i < kNumSlots; i++) {
string slotPrefix = $"_Vertex_Deformation_Slot_{i}_";
BaseFoldNode node = (foldNodes.Count > 0) ? foldNodes.Pop() : null;
FoldNodeSerialized data = node?.Serialize();
bool active = data != null;
if (active) {
Debug.Log($"Setting opcode {data.opcode}");
}
mpb.SetFloat(slotPrefix + "Enabled", active ? 1.0f : 0.0f);
mpb.SetInt(slotPrefix + "Opcode", active ? data.opcode : 0);
mpb.SetFloat(slotPrefix + "Float_0", active ? data.float0 : 0.0f);
mpb.SetFloat(slotPrefix + "Float_1", active ? data.float1 : 0.0f);
mpb.SetFloat(slotPrefix + "Float_2", active ? data.float2 : 0.0f);
mpb.SetFloat(slotPrefix + "Float_3", active ? data.float3 : 0.0f);
mpb.SetVector(slotPrefix + "Vector_0", active ? data.vec0 : Vector4.zero);
if (active) {
Debug.Log($"Setting vec0 {data.vec0}");
}
mpb.SetVector(slotPrefix + "Vector_1", active ? data.vec1 : Vector4.zero);
mpb.SetVector(slotPrefix + "Vector_2", active ? data.vec2 : Vector4.zero);
mpb.SetVector(slotPrefix + "Vector_3", active ? data.vec3 : Vector4.zero);
}
rend.SetPropertyBlock(mpb);
}
BaseFoldNode GetInputFoldNode(BaseFoldNode node)
{
// Traverse via edges in the graph model, as 'input' field might not be populated in Editor
var port = node.GetPort(nameof(BaseFoldNode.input), null);
if (port == null) return null;
// Find the edge connected to this input port
var edge = node.graph.edges.FirstOrDefault(e => e.inputPort == port);
return edge?.outputNode as BaseFoldNode;
}
T GetConnectedNode<T>(string fieldName) where T : class
{
var edge = GetFirstPortViewFromFieldName(fieldName)?.GetEdges().FirstOrDefault();
return (edge?.output.node as BaseNodeView)?.nodeTarget as T;
}
GameObject GetConnectedGameObject() => GetConnectedNode<GameObjectNode>(nameof(KeyframeNode.targetObject))?.output;
BaseFoldNode GetConnectedFoldNode() => GetConnectedNode<BaseFoldNode>(nameof(KeyframeNode.foldData));
void Validate()
{
var go = GetConnectedGameObject();
bool hasGoConn = GetFirstPortViewFromFieldName(nameof(KeyframeNode.targetObject))?.GetEdges().Any() ?? false;
bool hasFoldConn = GetFirstPortViewFromFieldName(nameof(KeyframeNode.foldData))?.GetEdges().Any() ?? false;
RemoveMessageView(ERROR_TYPE);
RemoveMessageView(ERROR_REND);
if (hasGoConn)
{
if (go == null) AddMessageView(ERROR_TYPE, NodeMessageType.Error);
else if (go.GetComponent<MeshRenderer>() == null) AddMessageView(ERROR_REND, NodeMessageType.Error);
}
generateButton.SetEnabled(hasGoConn && hasFoldConn && go?.GetComponent<MeshRenderer>() != null);
}
}
|