Motion transfer setup #1
|
@ -101,7 +101,6 @@ def run_node_tree(
|
|||
return
|
||||
|
||||
powership_mode = scene.powership_mode
|
||||
|
||||
if powership_mode == "AUTO":
|
||||
cgtinker marked this conversation as resolved
Outdated
|
||||
# TODO: don't use the global context here.
|
||||
powership_mode = _choose_auto_mode(bpy.context)
|
||||
|
|
46
nodes.py
46
nodes.py
|
@ -251,7 +251,14 @@ class AbstractPowerShipNode(bpy.types.Node):
|
|||
return link.from_socket.default_value
|
||||
return input_socket.default_value
|
||||
|
||||
def _get_input_value(self, input_socket_name: str, expectType: T) -> T | None:
|
||||
def _get_input_value(self, input_socket_name: str, expectType: type[T]) -> T | None:
|
||||
"""Return the socket value, or None in some cases.
|
||||
|
||||
None is returned only when the socket value is None, for example with
|
||||
empty ID pointer sockets. Even though this may not be applicable to many
|
||||
node types, the code is generic and thus can technically always return a
|
||||
None value.
|
||||
"""
|
||||
input_socket = self.inputs[input_socket_name]
|
||||
value = self._get_input_socket_value(input_socket)
|
||||
if value is None:
|
||||
|
@ -262,7 +269,15 @@ class AbstractPowerShipNode(bpy.types.Node):
|
|||
def _get_optional_input_value(
|
||||
self, input_socket_name: str, expectType: type[T]
|
||||
) -> T | None:
|
||||
"""Return the connected socket value, or None if not connected."""
|
||||
"""Return the connected socket value, or None if not connected.
|
||||
|
||||
Note that the 'optional' in the name indicates optional functionality.
|
||||
cgtinker marked this conversation as resolved
Outdated
Sybren A. Stüvel
commented
Keep formatting changes out of the patch. You can use Keep formatting changes out of the patch. You can use `git gui` or some other tool to cherry-pick which lines you do (not) want to include in a commit. That way you can exclude such changes, commit the rest, then revert the unwanted formatting changes to get rid of them.
|
||||
It does *not* refer to optionally being connected; that's always
|
||||
optional for any input socket.
|
||||
|
||||
An example of optional functionality would be to only set a bone's
|
||||
rotation when the 'Rotation' socket is connected.
|
||||
"""
|
||||
input_socket = self.inputs[input_socket_name]
|
||||
for link in input_socket.links:
|
||||
convertedValue = expectType(link.from_socket.default_value) # type: ignore
|
||||
|
@ -898,17 +913,6 @@ class SetBoneNode(AbstractPowerShipNode):
|
|||
bl_label = "Set Bone"
|
||||
bl_icon = "BONE_DATA"
|
||||
|
||||
space: bpy.props.EnumProperty( # type: ignore
|
||||
name="Space",
|
||||
items=_enum_control_space,
|
||||
)
|
||||
|
||||
def draw_buttons(
|
||||
self, context: bpy.types.Context, layout: bpy.types.UILayout
|
||||
) -> None:
|
||||
super().draw_buttons(context, layout)
|
||||
layout.prop(self, "space")
|
||||
|
||||
def init(self, context):
|
||||
self.add_execution_sockets()
|
||||
|
||||
|
@ -940,8 +944,8 @@ class SetBoneNode(AbstractPowerShipNode):
|
|||
arm_eval: bpy.types.Object = arm_ob.evaluated_get(depsgraph)
|
||||
arm_matrix = arm_eval.matrix_world
|
||||
bone_mat_world: Matrix = arm_matrix @ bone.matrix
|
||||
loc, rot, scale = bone_mat_world.decompose()
|
||||
|
||||
loc, rot, scale = bone_mat_world.decompose()
|
||||
if control_location is not None:
|
||||
loc = control_location
|
||||
if control_rotation is not None:
|
||||
|
@ -1111,6 +1115,8 @@ class ToEulerNode(AbstractPowerShipNode):
|
|||
|
||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||
rotation = self._get_input_value("Rotation", Quaternion)
|
||||
if rotation is None:
|
||||
return
|
||||
euler = rotation.to_euler(self.order)
|
||||
self.outputs["X"].default_value = degrees(euler.x)
|
||||
self.outputs["Y"].default_value = degrees(euler.y)
|
||||
|
@ -1142,9 +1148,9 @@ class FromEulerNode(AbstractPowerShipNode):
|
|||
self.inputs.new("NodeSocketFloat", "Z")
|
||||
|
||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||
x = self._get_input_value("X", float)
|
||||
y = self._get_input_value("Y", float)
|
||||
z = self._get_input_value("Z", float)
|
||||
x: float = self._get_input_value("X", float) or 0.0
|
||||
y: float = self._get_input_value("Y", float) or 0.0
|
||||
z: float = self._get_input_value("Z", float) or 0.0
|
||||
|
||||
euler = Euler((radians(x), radians(y), radians(z)), self.order)
|
||||
self.outputs["Rotation"].default_value = euler.to_quaternion()
|
||||
|
@ -1164,9 +1170,9 @@ class ClampNode(AbstractPowerShipNode):
|
|||
self.outputs.new("NodeSocketFloat", "Result")
|
||||
|
||||
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||
value = self._get_input_value("Value", float)
|
||||
minimum = self._get_input_value("Minimum", float)
|
||||
maximum = self._get_input_value("Maximum", float)
|
||||
value = self._get_input_value("Value", float) or 0.0
|
||||
minimum = self._get_input_value("Minimum", float) or 0.0
|
||||
maximum = self._get_input_value("Maximum", float) or 0.0
|
||||
|
||||
clamped = max(minimum, min(value, maximum))
|
||||
self.outputs["Result"].default_value = clamped
|
||||
|
|
Loading…
Reference in New Issue
This seems like the same logic as the depsgraph update callback. Maybe move it into a separate function and call that from both places?