Upgrading the Vector Math Node

Dynamically change the number of input and output parameters for the selected operation
This commit is contained in:
E1e5en 2020-11-07 11:14:46 +03:00
parent 085146b245
commit 7dae9e38d0
2 changed files with 249 additions and 45 deletions

View file

@ -4,49 +4,136 @@ import iron.math.Vec4;
class VectorMathNode extends LogicNode {
public var property0: String;
var v = new Vec4();
public var property0: String; // Operation
public var property1: Bool; // Separator Out
var res_v = new Vec4();
var res_f = 0.0;
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var v1: Vec4 = inputs[0].get();
var v2: Vec4 = inputs[1].get();
if (v1 == null || v2 == null) return null;
v.setFrom(v1);
var f = 0.0;
var p1: Vec4 = inputs[0].get();
if (p1 == null) return null;
res_v.setFrom(p1);
switch (property0) {
case "Add":
v.add(v2);
case "Subtract":
v.sub(v2);
case "Average":
v.add(v2);
v.x *= 0.5;
v.y *= 0.5;
v.z *= 0.5;
case "Dot Product":
f = v.dot(v2);
v.set(f, f, f);
case "Cross Product":
v.cross(v2);
case "Normalize":
v.normalize();
case "Multiply":
v.x *= v2.x;
v.y *= v2.y;
v.z *= v2.z;
case "Length":
f = v.length();
case "Distance":
f = v.distanceTo(v2);
case "Reflect":
v.reflect(v2);
// 1 arguments: Normalize, Length
case "Normalize":
res_v.normalize();
case "Length":
res_f = res_v.length();
// 2 arguments: Distance, Reflect
case "Distance": {
var p2: Vec4 = inputs[1].get();
if (p2 == null) return null;
res_f = res_v.distanceTo(p2);
}
case "Reflect": {
var p2: Vec4 = inputs[1].get();
if (p2 == null) return null;
res_v.reflect(p2);
}
// Many arguments: Add, Subtract, Average, Dot Product, Cross Product, Multiply
case "Add": {
var p2 = new Vec4();
var i = 1;
while (i < inputs.length) {
p2 = inputs[i].get();
if (p2 == null) return null;
res_v.add(p2);
i++;
}
}
case "Subtract": {
var p2 = new Vec4();
var i = 1;
while (i < inputs.length) {
p2 = inputs[i].get();
if (p2 == null) return null;
res_v.sub(p2);
i++;
}
}
case "Average": {
var p2 = new Vec4();
var i = 1;
while (i < inputs.length) {
p2 = inputs[i].get();
if (p2 == null) return null;
res_v.add(p2);
res_v.mult(0.5);
i++;
}
}
case "Dot Product": {
var p2 = new Vec4();
var i = 1;
while (i < inputs.length) {
p2 = inputs[i].get();
if (p2 == null) return null;
res_f = res_v.dot(p2);
res_v.set(res_f, res_f, res_f);
i++;
}
}
case "Cross Product": {
var p2 = new Vec4();
var i = 1;
while (i < inputs.length) {
p2 = inputs[i].get();
if (p2 == null) return null;
res_v.cross(p2);
i++;
}
}
case "Multiply": {
var p2 = new Vec4();
var i = 1;
while (i < inputs.length) {
p2 = inputs[i].get();
if (p2 == null) return null;
res_v.x *= p2.x;
res_v.y *= p2.y;
res_v.z *= p2.z;
i++;
}
}
case "MultiplyFloats": {
var p2_f = 1.0;
var i = 1;
while (i < inputs.length) {
p2_f = inputs[i].get();
if (p2_f == null) return null;
res_v.mult(p2_f);
i++;
}
}
}
if (from == 0) return v;
else return f;
// Return and check separator
switch (from) {
case 0: return res_v;
case 1:
if (property1) {
return res_v.x;
} else {
return res_f;
}
case 2:
if (property1) {
return res_v.y;
} else {
return res_f;
}
case 3:
if (property1) {
return res_v.z;
} else {
return res_f;
}
case 4:
if (property1) return res_f;
}
return null;
}
}
}

View file

@ -1,32 +1,149 @@
from arm.logicnode.arm_nodes import *
class VectorMathNode(ArmLogicTreeNode):
"""Operates vectors. Some operations uses only the first input."""
"""Mathematical operations on vectors."""
bl_idname = 'LNVectorMathNode'
bl_label = 'Vector Math'
arm_section = 'vector'
arm_version = 1
min_outputs = 2
max_outputs = 5
def get_bool(self):
return self['property1']
def set_bool(self, value):
self['property1'] = value
if value:
if (self.property0 == 'Length') or (self.property0 == 'Distance') or (self.property0 == 'Dot Product'):
self.outputs.remove(self.outputs.values()[-1]) # Distance/Length/Scalar
self.add_output('NodeSocketFloat', 'X') # Result X
self.add_output('NodeSocketFloat', 'Y') # Result Y
self.add_output('NodeSocketFloat', 'Z') # Result Z
if (self.property0 == 'Length'):
self.add_output('NodeSocketFloat', 'Length') # Length
if (self.property0 == 'Distance'):
self.add_output('NodeSocketFloat', 'Distance') # Distance
if (self.property0 == 'Dot Product'):
self.add_output('NodeSocketFloat', 'Scalar') # Scalar
else:
if (self.property0 == 'Length') or (self.property0 == 'Distance') or (self.property0 == 'Dot Product'):
self.outputs.remove(self.outputs.values()[-1]) # Distance/Length/Scalar
self.outputs.remove(self.outputs.values()[-1]) # Result X
self.outputs.remove(self.outputs.values()[-1]) # Result Y
self.outputs.remove(self.outputs.values()[-1]) # Result Z
if (self.property0 == 'Length'):
self.add_output('NodeSocketFloat', 'Length') # Length
if (self.property0 == 'Distance'):
self.add_output('NodeSocketFloat', 'Distance') # Distance
if (self.property0 == 'Dot Product'):
self.add_output('NodeSocketFloat', 'Scalar') # Scalar
property1: BoolProperty(name='Separator Out', default=False, set=set_bool, get=get_bool)
@staticmethod
def get_enum_id_value(obj, prop_name, value):
return obj.bl_rna.properties[prop_name].enum_items[value].identifier
@staticmethod
def get_count_in(operation_name):
return {
'Add': 0,
'Subtract': 0,
'Average': 0,
'Dot Product': 0,
'Cross Product': 0,
'Multiply': 0,
'MultiplyFloats': 0,
'Distance': 2,
'Reflect': 2,
'Normalize': 1,
'Length': 1
}.get(operation_name, 0)
def get_enum(self):
return self['property0']
def set_enum(self, value):
# Checking the selection of another operation
select_current = self.get_enum_id_value(self, 'property0', value)
select_prev = self.property0
if select_prev != select_current:
if (select_prev == 'Distance') or (select_prev == 'Length') or (self.property0 == 'Dot Product'):
self.outputs.remove(self.outputs.values()[-1])
# Many arguments: Add, Subtract, Average, Dot Product, Cross Product, Multiply, MultiplyFloats
if (self.get_count_in(select_current) == 0):
if (select_current == "MultiplyFloats") or (select_prev == "MultiplyFloats"):
while (len(self.inputs) > 1):
self.inputs.remove(self.inputs.values()[-1])
if (select_current == "MultiplyFloats"):
self.add_input('NodeSocketFloat', 'Value ' + str(len(self.inputs)))
else:
while (len(self.inputs) < 2):
self.add_input('NodeSocketVector', 'Value ' + str(len(self.inputs)))
if (select_current == 'Dot Product'):
self.add_output('NodeSocketFloat', 'Scalar')
# 2 arguments: Distance, Reflect
if (self.get_count_in(select_current) == 2):
count = 2
if (select_prev == "MultiplyFloats"):
count = 1
while (len(self.inputs) > count):
self.inputs.remove(self.inputs.values()[-1])
while (len(self.inputs) < 2):
self.add_input('NodeSocketVector', 'Value ' + str(len(self.inputs)))
if (select_current == 'Distance'):
self.add_output('NodeSocketFloat', 'Distance')
# 1 argument: Normalize, Length
if (self.get_count_in(select_current) == 1):
while (len(self.inputs) > 1):
self.inputs.remove(self.inputs.values()[-1])
if (select_current == 'Length'):
self.add_output('NodeSocketFloat', 'Length')
self['property0'] = value
property0: EnumProperty(
items = [('Add', 'Add', 'Add'),
('Dot Product', 'Dot Product', 'Dot Product'),
('Multiply', 'Multiply', 'Multiply'),
('MultiplyFloats', 'Multiply (Floats)', 'Multiply (Floats)'),
('Normalize', 'Normalize', 'Normalize'),
('Subtract', 'Subtract', 'Subtract'),
('Average', 'Average', 'Average'),
('Cross Product', 'Cross Product', 'Cross Product'),
('Length', 'Length', 'Length'),
('Distance', 'Distance', 'Distance'),
('Reflect', 'Reflect', 'Reflect'),
],
name='', default='Add')
('Reflect', 'Reflect', 'Reflect')],
name='', default='Add', set=set_enum, get=get_enum)
def __init__(self):
array_nodes[str(id(self))] = self
def init(self, context):
super(VectorMathNode, self).init(context)
self.add_input('NodeSocketVector', 'Vector 1', default_value=[0.0, 0.0, 0.0])
self.add_input('NodeSocketVector', 'Vector 2', default_value=[0.0, 0.0, 0.0])
self['property0'] = 0
self['property1'] = False
self.add_input('NodeSocketVector', 'Value 0', default_value=[0.0, 0.0, 0.0])
self.add_input('NodeSocketVector', 'Value 1', default_value=[0.0, 0.0, 0.0])
self.add_output('NodeSocketVector', 'Result')
self.add_output('NodeSocketFloat', 'Distance')
def draw_buttons(self, context, layout):
layout.prop(self, 'property0')
layout.prop(self, 'property1') # Separator Out
layout.prop(self, 'property0') # Operation
# Buttons
if (self.get_count_in(self.property0) == 0):
row = layout.row(align=True)
column = row.column(align=True)
op = column.operator('arm.node_add_input', text='Add Value', icon='PLUS', emboss=True)
op.node_index = str(id(self))
op.name_format = 'Value {0}'
if (self.property0 == "MultiplyFloats"):
op.socket_type = 'NodeSocketFloat'
else:
op.socket_type = 'NodeSocketVector'
column = row.column(align=True)
op = column.operator('arm.node_remove_input', text='', icon='X', emboss=True)
op.node_index = str(id(self))
if len(self.inputs) == 2:
column.enabled = False