Motion transfer setup #1
@ -80,8 +80,7 @@ def _on_frame_changed_post(
|
|||||||
scene: bpy.types.Scene, depsgraph: bpy.types.Depsgraph
|
scene: bpy.types.Scene, depsgraph: bpy.types.Depsgraph
|
||||||
) -> None:
|
) -> None:
|
||||||
global _skip_next_autorun
|
global _skip_next_autorun
|
||||||
if not _skip_next_autorun:
|
_skip_next_autorun = True
|
||||||
_skip_next_autorun = True
|
|
||||||
|
|
||||||
cgtinker marked this conversation as resolved
|
|||||||
run_node_tree(scene, depsgraph)
|
run_node_tree(scene, depsgraph)
|
||||||
|
|
||||||
|
245
nodes.py
245
nodes.py
@ -3,8 +3,8 @@
|
|||||||
import functools
|
import functools
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from math import degrees, radians, sqrt
|
from math import degrees, radians
|
||||||
from typing import TypeVar, Callable, Optional, Iterable, Any
|
from typing import TypeVar, Callable, Optional, Iterable
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import nodeitems_utils
|
import nodeitems_utils
|
||||||
@ -271,7 +271,7 @@ class AbstractPowerShipNode(bpy.types.Node):
|
|||||||
|
|
||||||
def _first_input_to_output(self) -> None:
|
def _first_input_to_output(self) -> None:
|
||||||
"""Copy the first input's default value to the output, if the sockets are compatible."""
|
"""Copy the first input's default value to the output, if the sockets are compatible."""
|
||||||
|
|
||||||
if not self.inputs or not self.outputs:
|
if not self.inputs or not self.outputs:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -580,25 +580,16 @@ class ToVector(AbstractPowerShipNode):
|
|||||||
bl_icon = "EMPTY_ARROWS"
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "X")
|
self.inputs.new("NodeSocketFloat", "X")
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "Y")
|
self.inputs.new("NodeSocketFloat", "Y")
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "Z")
|
self.inputs.new("NodeSocketFloat", "Z")
|
||||||
self.outputs.new("NodeSocketVector", "Vector")
|
self.outputs.new("NodeSocketVector", "Vector")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
x = self._get_optional_input_value("X", float)
|
x = self.inputs["X"].default_value or 0.0
|
||||||
y = self._get_optional_input_value("Y", float)
|
y = self.inputs["Y"].default_value or 0.0
|
||||||
z = self._get_optional_input_value("Z", float)
|
z = self.inputs["Z"].default_value or 0.0
|
||||||
|
self.outputs["Vector"].default_value = Vector((x, y, z))
|
||||||
v = Vector((0.0, 0.0, 0.0))
|
|
||||||
if x is not None:
|
|
||||||
v.x = x
|
|
||||||
if y is not None:
|
|
||||||
v.y = y
|
|
||||||
if z is not None:
|
|
||||||
v.z = z
|
|
||||||
|
|
||||||
self.outputs["Vector"].default_value = v
|
|
||||||
|
|
||||||
|
|
||||||
class SplitVector(AbstractPowerShipNode):
|
class SplitVector(AbstractPowerShipNode):
|
||||||
@ -607,93 +598,88 @@ class SplitVector(AbstractPowerShipNode):
|
|||||||
bl_icon = "EMPTY_ARROWS"
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketVector", "Vector")
|
self.inputs.new("NodeSocketVector", "Vector")
|
||||||
self.outputs.new("NodeSocketFloat", "X")
|
self.outputs.new("NodeSocketFloat", "X")
|
||||||
self.outputs.new("NodeSocketFloat", "Y")
|
self.outputs.new("NodeSocketFloat", "Y")
|
||||||
self.outputs.new("NodeSocketFloat", "Z")
|
self.outputs.new("NodeSocketFloat", "Z")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
v = self._get_optional_input_value("Vector", Vector)
|
v = self.inputs["Vector"].default_value
|
||||||
self.outputs["X"].default_value = v.x
|
self.outputs["X"].default_value = v.x
|
||||||
self.outputs["Y"].default_value = v.y
|
self.outputs["Y"].default_value = v.y
|
||||||
self.outputs["Z"].default_value = v.z
|
self.outputs["Z"].default_value = v.z
|
||||||
|
|
||||||
|
|
||||||
class Distance(AbstractPowerShipNode):
|
class Distance(AbstractPowerShipNode):
|
||||||
""" Calculates distance between two points. """
|
"""Calculates distance between two points."""
|
||||||
|
|
||||||
bl_idname = "Distance"
|
bl_idname = "Distance"
|
||||||
bl_label = "Distance"
|
bl_label = "Distance"
|
||||||
bl_icon = "EMPTY_ARROWS"
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketVector", "U")
|
self.inputs.new("NodeSocketVector", "U")
|
||||||
self.add_optional_input_socket("NodeSocketVector", "V")
|
self.inputs.new("NodeSocketVector", "V")
|
||||||
self.outputs.new("NodeSocketFloat", "Float")
|
self.outputs.new("NodeSocketFloat", "Float")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
u = self._get_optional_input_value("U", Vector)
|
u = self.inputs["U"].default_value
|
||||||
v = self._get_optional_input_value("V", Vector)
|
v = self.inputs["V"].default_value
|
||||||
self.outputs["Float"].default_value = (u-v).length
|
self.outputs["Float"].default_value = (u - v).length
|
||||||
|
|
||||||
|
|
||||||
cgtinker marked this conversation as resolved
Sybren A. Stüvel
commented
Does this calculate a normal vector? Or its length? Does this calculate a normal vector? Or its length?
Denys Hsu
commented
The length. The length.
I went through the comments and updated them (some were unrelated and happened due to closed eyes copy pasting...)
|
|||||||
class NormalFromPoints(AbstractPowerShipNode):
|
class NormalFromPoints(AbstractPowerShipNode):
|
||||||
""" Calculates normal from three points (plane). """
|
"""Calculates normal from three points (plane)."""
|
||||||
|
|
||||||
bl_idname = "NormalFromPoints"
|
bl_idname = "NormalFromPoints"
|
||||||
bl_label = "Normal from Points"
|
bl_label = "Normal from Points"
|
||||||
bl_icon = "EMPTY_ARROWS"
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketVector", "U")
|
self.inputs.new("NodeSocketVector", "U")
|
||||||
self.add_optional_input_socket("NodeSocketVector", "V")
|
self.inputs.new("NodeSocketVector", "V")
|
||||||
self.add_optional_input_socket("NodeSocketVector", "W")
|
self.inputs.new("NodeSocketVector", "W")
|
||||||
self.outputs.new("NodeSocketVector", "Result")
|
self.outputs.new("NodeSocketVector", "Result")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
u = self._get_optional_input_value("U", Vector)
|
u = self.inputs["U"].default_value
|
||||||
v = self._get_optional_input_value("V", Vector)
|
v = self.inputs["V"].default_value
|
||||||
w = self._get_optional_input_value("W", Vector)
|
w = self.inputs["W"].default_value
|
||||||
a = v - u
|
a = v - u
|
||||||
b = w - u
|
b = w - u
|
||||||
normal = a.cross(b)
|
normal = a.cross(b).normalized()
|
||||||
self.outputs["Result"].default_value = normal
|
self.outputs["Result"].default_value = normal
|
||||||
|
|
||||||
|
|
||||||
_enum_up_axis_items = (
|
_enum_up_axis_items = (
|
||||||
('X', "X", ""),
|
("X", "X", ""),
|
||||||
('Y', "Y", ""),
|
("Y", "Y", ""),
|
||||||
('Z', "Z", ""),
|
("Z", "Z", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
_enum_track_axis_items = (
|
_enum_track_axis_items = (
|
||||||
('X', "X", ""),
|
("X", "X", ""),
|
||||||
('Y', "Y", ""),
|
("Y", "Y", ""),
|
||||||
('Z', "Z", ""),
|
("Z", "Z", ""),
|
||||||
('-X', "-X", ""),
|
("-X", "-X", ""),
|
||||||
('-Y', "-Y", ""),
|
("-Y", "-Y", ""),
|
||||||
('-Z', "-Z", ""),
|
("-Z", "-Z", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RotateTowards(AbstractPowerShipNode):
|
class RotateTowards(AbstractPowerShipNode):
|
||||||
""" Calculate the rotation from a vector with a track and up axis
|
"""Calculate the rotation from a vector with a track and up axis."""
|
||||||
based on the given origin, destination. """
|
|
||||||
|
|
||||||
bl_idname = "RotateTowards"
|
bl_idname = "RotateTowards"
|
||||||
bl_label = "Rotate Towards"
|
bl_label = "Rotate Towards"
|
||||||
bl_icon = "EMPTY_ARROWS"
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
track: bpy.props.EnumProperty( # type: ignore
|
track: bpy.props.EnumProperty( # type: ignore
|
||||||
name="Track",
|
name="Track", items=_enum_track_axis_items, default="X"
|
||||||
items=_enum_track_axis_items,
|
|
||||||
default='X'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
up: bpy.props.EnumProperty( # type: ignore
|
up: bpy.props.EnumProperty( # type: ignore
|
||||||
name="Up",
|
name="Up", items=_enum_up_axis_items, default="Y"
|
||||||
items=_enum_up_axis_items,
|
|
||||||
default='Y'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def draw_buttons(
|
def draw_buttons(
|
||||||
@ -704,34 +690,33 @@ class RotateTowards(AbstractPowerShipNode):
|
|||||||
layout.prop(self, "track")
|
layout.prop(self, "track")
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketVector", "Origin")
|
self.inputs.new("NodeSocketVector", "Vector")
|
||||||
self.add_optional_input_socket("NodeSocketVector", "Destination")
|
self.inputs.new("NodeSocketVector", "RotateTo")
|
||||||
self.outputs.new("NodeSocketQuaternion", "Rotation")
|
self.outputs.new("NodeSocketQuaternion", "Rotation")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
origin = self._get_optional_input_value("Origin", Vector)
|
origin = self.inputs["Vector"].default_value
|
||||||
destination = self._get_optional_input_value("Destination", Vector)
|
destination = self.inputs["RotateTo"].default_value
|
||||||
vec = Vector((destination - origin))
|
vec = Vector((destination - origin))
|
||||||
rot = vec.to_track_quat(self.track, self.up)
|
rot = vec.to_track_quat(self.track, self.up)
|
||||||
self.outputs["Rotation"].default_value = rot.normalized()
|
self.outputs["Rotation"].default_value = rot.normalized()
|
||||||
|
|
||||||
|
|
||||||
class OffsetRotation(AbstractPowerShipNode):
|
class OffsetRotation(AbstractPowerShipNode):
|
||||||
""" Offset a rotation. """
|
"""Offset a rotation."""
|
||||||
|
|
||||||
bl_idname = "OffsetRotation"
|
bl_idname = "OffsetRotation"
|
||||||
bl_label = "Offset Rotation"
|
bl_label = "Offset Rotation"
|
||||||
bl_icon = "EMPTY_ARROWS"
|
bl_icon = "EMPTY_ARROWS"
|
||||||
default_value = Quaternion()
|
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketQuaternion", "Base")
|
self.inputs.new("NodeSocketQuaternion", "Base")
|
||||||
self.add_optional_input_socket("NodeSocketQuaternion", "Offset")
|
self.inputs.new("NodeSocketQuaternion", "Offset")
|
||||||
self.outputs.new("NodeSocketQuaternion", "Rotation")
|
self.outputs.new("NodeSocketQuaternion", "Rotation")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
base = self._get_optional_input_value("Base", Quaternion)
|
base = self.inputs["Base"].default_value
|
||||||
offset = self._get_optional_input_value("Offset", Quaternion)
|
offset = self.inputs["Offset"].default_value
|
||||||
self.outputs["Rotation"].default_value = base @ offset
|
self.outputs["Rotation"].default_value = base @ offset
|
||||||
|
|
||||||
|
|
||||||
@ -741,19 +726,19 @@ class MapRange(AbstractPowerShipNode):
|
|||||||
bl_icon = "EMPTY_ARROWS"
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "Value")
|
self.inputs.new("NodeSocketFloat", "Value")
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "From Min")
|
self.inputs.new("NodeSocketFloat", "From Min")
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "From Max")
|
self.inputs.new("NodeSocketFloat", "From Max")
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "To Min")
|
self.inputs.new("NodeSocketFloat", "To Min")
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "To Max")
|
self.inputs.new("NodeSocketFloat", "To Max")
|
||||||
self.outputs.new("NodeSocketFloat", "Result")
|
self.outputs.new("NodeSocketFloat", "Result")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
val = self._get_optional_input_value("Value", float)
|
val = self.inputs["Value"].default_value
|
||||||
fmin = self._get_optional_input_value("From Min", float)
|
fmin = self.inputs["From Min"].default_value
|
||||||
fmax = self._get_optional_input_value("From Max", float)
|
fmax = self.inputs["From Max"].default_value
|
||||||
tmin = self._get_optional_input_value("To Min", float)
|
tmin = self.inputs["To Min"].default_value
|
||||||
tmax = self._get_optional_input_value("To Max", float)
|
tmax = self.inputs["To Max"].default_value
|
||||||
|
|
||||||
factor = (tmax - tmin) / (fmax - fmin)
|
factor = (tmax - tmin) / (fmax - fmin)
|
||||||
offset = tmin - factor * fmin
|
offset = tmin - factor * fmin
|
||||||
@ -761,52 +746,34 @@ class MapRange(AbstractPowerShipNode):
|
|||||||
|
|
||||||
|
|
||||||
class AngleFromVectors(AbstractPowerShipNode):
|
class AngleFromVectors(AbstractPowerShipNode):
|
||||||
""" Calculate the angle between two vectors. Output in degrees. """
|
"""Calculate the angle between two vectors. Output in degrees."""
|
||||||
|
|
||||||
bl_idname = "AngleFromVectors"
|
bl_idname = "AngleFromVectors"
|
||||||
bl_label = "Angle From Vectors"
|
bl_label = "Angle From Vectors"
|
||||||
bl_icon = "EMPTY_ARROWS"
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
angle_type: bpy.props.EnumProperty( # type: ignore
|
|
||||||
name="Type",
|
|
||||||
items=[
|
|
||||||
("DEFAULT", "Unsigned", ""),
|
|
||||||
("SIGNED", "Signed", ""),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
def draw_buttons(
|
|
||||||
self, context: bpy.types.Context, layout: bpy.types.UILayout
|
|
||||||
) -> None:
|
|
||||||
super().draw_buttons(context, layout)
|
|
||||||
layout.prop(self, "angle_type")
|
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketVector", "U")
|
self.inputs.new("NodeSocketVector", "U")
|
||||||
self.add_optional_input_socket("NodeSocketVector", "V")
|
self.inputs.new("NodeSocketVector", "V")
|
||||||
self.outputs.new("NodeSocketFloat", "Angle")
|
self.outputs.new("NodeSocketFloat", "Angle")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
u = self._get_optional_input_value("U", Vector)
|
u = self.inputs["U"].default_value
|
||||||
v = self._get_optional_input_value("V", Vector)
|
v = self.inputs["V"].default_value
|
||||||
signed = self.angle_type == 'SIGNED'
|
|
||||||
|
|
||||||
angle = 0
|
angle = 0
|
||||||
if not (u.length == 0 or v.length == 0):
|
if not (u.length_squared == 0 or v.length_squared == 0):
|
||||||
if signed:
|
angle = u.angle(v)
|
||||||
angle = u.angle_signed(v)
|
|
||||||
else:
|
|
||||||
angle = u.angle(v)
|
|
||||||
|
|
||||||
self.outputs["Angle"].default_value = degrees(angle)
|
self.outputs["Angle"].default_value = degrees(angle)
|
||||||
|
|
||||||
|
|
||||||
_enum_vector_math_operations = [
|
_enum_vector_math_operations = [
|
||||||
('ADD', "Add", ""),
|
("ADD", "Add", ""),
|
||||||
('SUBSTRACT', "Substract", ""),
|
("SUBSTRACT", "Substract", ""),
|
||||||
('MULTIPLY', "Mutliply", ""),
|
("MULTIPLY", "Mutliply", ""),
|
||||||
('DIVIDE', "Divide", ""),
|
("DIVIDE", "Divide", ""),
|
||||||
('CROSS', "Cross", ""),
|
("CROSS", "Cross", ""),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -827,38 +794,36 @@ class VectorMath(AbstractPowerShipNode):
|
|||||||
layout.prop(self, "operation")
|
layout.prop(self, "operation")
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketVector", "U")
|
self.inputs.new("NodeSocketVector", "U")
|
||||||
self.add_optional_input_socket("NodeSocketVector", "V")
|
self.inputs.new("NodeSocketVector", "V")
|
||||||
self.outputs.new("NodeSocketVector", "Result")
|
self.outputs.new("NodeSocketVector", "Result")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
u = self._get_optional_input_value("U", Vector)
|
u = self.inputs["U"].default_value
|
||||||
v = self._get_optional_input_value("V", Vector)
|
v = self.inputs["V"].default_value
|
||||||
|
|
||||||
match self.operation:
|
match self.operation:
|
||||||
case 'ADD':
|
case "ADD":
|
||||||
res = u+v
|
res = u + v
|
||||||
case 'MULTIPLY':
|
case "MULTIPLY":
|
||||||
res = u*v
|
res = u * v
|
||||||
case 'SUBSTRACT':
|
case "SUBSTRACT":
|
||||||
res = u-v
|
res = u - v
|
||||||
case 'DIVIDE':
|
case "DIVIDE":
|
||||||
res = Vector([x/y if y != 0.0 else float("nan")
|
res = Vector((x / y if y != 0.0 else 0.0 for x, y in zip(u, v)))
|
||||||
for x, y in zip(u, v)])
|
case "CROSS":
|
||||||
case 'CROSS':
|
|
||||||
res = u.cross(v)
|
res = u.cross(v)
|
||||||
case _:
|
case _:
|
||||||
print("Vector math operation not found:", self.operation)
|
raise ValueError(f"Vector math operation not found: {self.operation}\n")
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
self.outputs["Result"].default_value = res
|
self.outputs["Result"].default_value = res
|
||||||
|
|
||||||
|
|
||||||
_enum_math_operations = [
|
_enum_math_operations = [
|
||||||
('ADD', "Add", ""),
|
("ADD", "Add", ""),
|
||||||
('SUBSTRACT', "Substract", ""),
|
("SUBSTRACT", "Substract", ""),
|
||||||
('MULTIPLY', "Mutliply", ""),
|
("MULTIPLY", "Mutliply", ""),
|
||||||
('DIVIDE', "Divide", ""),
|
("DIVIDE", "Divide", ""),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -879,26 +844,25 @@ class Math(AbstractPowerShipNode):
|
|||||||
layout.prop(self, "operation")
|
layout.prop(self, "operation")
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "U")
|
self.inputs.new("NodeSocketFloat", "U")
|
||||||
self.add_optional_input_socket("NodeSocketFloat", "V")
|
self.inputs.new("NodeSocketFloat", "V")
|
||||||
self.outputs.new("NodeSocketFloat", "Result")
|
self.outputs.new("NodeSocketFloat", "Result")
|
||||||
|
|
||||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
u = self._get_optional_input_value("U", float)
|
u = self.inputs["U"].default_value
|
||||||
v = self._get_optional_input_value("V", float)
|
v = self.inputs["V"].default_value
|
||||||
|
|
||||||
match self.operation:
|
match self.operation:
|
||||||
case 'ADD':
|
case "ADD":
|
||||||
res = u+v
|
res = u + v
|
||||||
case 'MULTIPLY':
|
case "MULTIPLY":
|
||||||
res = u*v
|
res = u * v
|
||||||
case 'SUBSTRACT':
|
case "SUBSTRACT":
|
||||||
res = u-v
|
res = u - v
|
||||||
case 'DIVIDE':
|
case "DIVIDE":
|
||||||
res = u/v if v != 0 else float("nan")
|
res = u / v if v != 0 else 0
|
||||||
case _:
|
case _:
|
||||||
print("Math operation not found:", self.operation)
|
raise ValueError(f"Math operation not found: {self.operation}\n")
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
self.outputs["Result"].default_value = res
|
self.outputs["Result"].default_value = res
|
||||||
|
|
||||||
@ -994,12 +958,13 @@ class SetBoneNode(AbstractPowerShipNode):
|
|||||||
|
|
||||||
match self.space:
|
match self.space:
|
||||||
case "WORLD":
|
case "WORLD":
|
||||||
bone_mat_world = Matrix.LocRotScale(
|
bone_mat_world = Matrix.LocRotScale(loc, rot, scale)
|
||||||
loc, rot.normalized(), scale)
|
|
||||||
loc, rot, scale = bone_mat_world.decompose()
|
loc, rot, scale = bone_mat_world.decompose()
|
||||||
case "CHANNELS":
|
case "CHANNELS":
|
||||||
bone_rest_rot_scale.translation = v_nil
|
bone_rest_rot_scale.translation = v_nil
|
||||||
mat_rot_scale = Matrix.LocRotScale(v_nil, rot, scale) @ bone_rest_rot_scale
|
mat_rot_scale = (
|
||||||
|
Matrix.LocRotScale(v_nil, rot, scale) @ bone_rest_rot_scale
|
||||||
|
)
|
||||||
mat_loc = Matrix.Translation(loc)
|
mat_loc = Matrix.Translation(loc)
|
||||||
bone_mat_world = mat_loc @ mat_rot_scale
|
bone_mat_world = mat_loc @ mat_rot_scale
|
||||||
|
|
||||||
@ -1318,7 +1283,7 @@ node_categories = [
|
|||||||
nodeitems_utils.NodeItem("ClampNode"),
|
nodeitems_utils.NodeItem("ClampNode"),
|
||||||
nodeitems_utils.NodeItem("ToEulerNode"),
|
nodeitems_utils.NodeItem("ToEulerNode"),
|
||||||
nodeitems_utils.NodeItem("FromEulerNode"),
|
nodeitems_utils.NodeItem("FromEulerNode"),
|
||||||
]
|
],
|
||||||
),
|
),
|
||||||
PowerShipNodeCategory(
|
PowerShipNodeCategory(
|
||||||
"DEBUG",
|
"DEBUG",
|
||||||
|
Loading…
Reference in New Issue
Block a user
Since
_skip_next_autorun
is a boolean, theif
condition can be removed.