Skip to content

Commit

Permalink
Merge pull request #102 from mischakolbe/add_native_maya_trip_ops
Browse files Browse the repository at this point in the history
Add native maya trip ops
  • Loading branch information
mischakolbe authored Aug 3, 2020
2 parents f9ad77e + f5b85bc commit a328ad5
Show file tree
Hide file tree
Showing 4 changed files with 427 additions and 28 deletions.
250 changes: 237 additions & 13 deletions node_calculator/base_functions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Basic NodeCalculator functions."""
# This is an extension that is loaded by default.
"""Basic NodeCalculator functions.
# The main difference to the base_operators is that functions rely on operators!
# They combine existing operators to create more complex setups.
This is an extension that is loaded by default.
The main difference to the base_operators is that functions rely on operators!
They combine existing operators to create more complex setups.
"""
from node_calculator.core import noca_op
from node_calculator.core import Op

Expand All @@ -16,18 +17,18 @@


@noca_op
def soft_approach(in_value, fade_in_range=0.5, target_value=1):
"""Follow in_value, but approach the target_value slowly.
def soft_approach(attr_a, fade_in_range=0.5, target_value=1):
"""Follow attr_a, but approach the target_value slowly.
Note:
Only works for 1D inputs!
Args:
in_value (NcNode or NcAttrs or str or int or float): Value or attr
attr_a (NcNode or NcAttrs or str or int or float): Value or attr
fade_in_range (NcNode or NcAttrs or str or int or float): Value or
attr. This defines a range over which the target_value will be
approached. Before the in_value is within this range the output
of this and the in_value will be equal. Defaults to 0.5.
approached. Before the attr_a is within this range the output
of this and the attr_a will be equal. Defaults to 0.5.
target_value (NcNode or NcAttrs or str or int or float): Value or
attr. This is the value that will be approached slowly.
Defaults to 1.
Expand All @@ -45,19 +46,242 @@ def soft_approach(in_value, fade_in_range=0.5, target_value=1):
"""
start_val = target_value - fade_in_range

exponent = ((start_val) - in_value) / fade_in_range
exponent = ((start_val) - attr_a) / fade_in_range
soft_approach_value = target_value - fade_in_range * Op.exp(exponent)

is_range_valid_condition = Op.condition(
fade_in_range > 0,
soft_approach_value,
target_value
target_value,
)

is_in_range_condition = Op.condition(
in_value > start_val,
attr_a > start_val,
is_range_valid_condition,
in_value
attr_a,
)

return is_in_range_condition


@noca_op
def sin(attr_a):
"""Sine of attr_a.
Note:
Only works for 1D inputs!
The idea how to set this up with native Maya nodes is from Chad Vernon:
https://www.chadvernon.com/blog/trig-maya/
Args:
attr_a (NcNode or NcAttrs or str or int or float): Value or attr
Returns:
NcNode: Instance with node and output-attr.
Example:
::
in_attr = Node("pCube.tx")
Op.sin(in_attr)
"""
sin = Op.euler_to_quat(attr_a * 2).outputQuatX
return sin


@noca_op
def cos(attr_a):
"""Cosine of attr_a.
Note:
Only works for 1D inputs!
The idea how to set this up with native Maya nodes is from Chad Vernon:
https://www.chadvernon.com/blog/trig-maya/
Args:
attr_a (NcNode or NcAttrs or str or int or float): Value or attr
Returns:
NcNode: Instance with node and output-attr.
Example:
::
in_attr = Node("pCube.tx")
Op.cos(in_attr)
"""
cos = Op.euler_to_quat(attr_a * 2).outputQuatW
return cos


@noca_op
def tan(attr_a):
"""Tangent of attr_a.
Note:
Only works for 1D inputs!
The idea how to set this up with native Maya nodes is from Chad Vernon:
https://www.chadvernon.com/blog/trig-maya/
Args:
attr_a (NcNode or NcAttrs or str or int or float): Value or attr
Returns:
NcNode: Instance with node and output-attr.
Example:
::
in_attr = Node("pCube.tx")
Op.tan(in_attr)
"""
sin = Op.sin(attr_a)
cos = Op.cos(attr_a)
tan = sin / cos
divide_by_zero_safety = Op.condition(cos == 0, 0, tan)
return divide_by_zero_safety


@noca_op
def asin(attr_a):
"""Arcsine of attr_a.
Note:
Only works for 1D inputs!
Args:
attr_a (NcNode or NcAttrs or str or int or float): Value or attr
Returns:
NcNode: Instance with node and output-attr.
Example:
::
in_attr = Node("pCube.tx")
Op.asin(in_attr)
"""
x_vector_component = Op.sqrt(1 - attr_a ** 2)
angle_between = Op.angle_between(
(x_vector_component, 0, 0),
(x_vector_component, attr_a, 0),
)
right_angle_cond = Op.condition(x_vector_component == 0, 90, angle_between)
sign_cond = Op.condition(attr_a >= 0, right_angle_cond, -right_angle_cond)
return sign_cond


@noca_op
def acos(attr_a):
"""Arccosine of attr_a.
Note:
Only works for 1D inputs!
Args:
attr_a (NcNode or NcAttrs or str or int or float): Value or attr
Returns:
NcNode: Instance with node and output-attr.
Example:
::
in_attr = Node("pCube.tx")
Op.acos(in_attr)
"""
y_vector_component = Op.sqrt(1 - attr_a ** 2)
angle_between = Op.angle_between(
(attr_a, 0, 0),
(attr_a, y_vector_component, 0),
)
right_angle_cond = Op.condition(attr_a == 0, 90, angle_between)
flip_cond = Op.condition(
attr_a < 0, 180 - right_angle_cond, right_angle_cond
)
return flip_cond


@noca_op
def atan(attr_a):
"""Arctangent of attr_a, which calculates only quadrant 1 and 4.
Note:
Only works for 1D inputs!
Args:
attr_a (NcNode or NcAttrs or str or int or float): Value or attr
Returns:
NcNode: Instance with node and output-attr.
Example:
::
in_attr = Node("pCube.tx")
Op.atan(in_attr)
"""
angle_between = Op.angle_between(
(1, 0, 0),
(1, attr_a, 0),
)
sign_cond = Op.condition(attr_a < 0, -angle_between, angle_between)
return sign_cond


@noca_op
def atan2(attr_a, attr_b):
"""Arctangent2 of attr_b/attr_a, which calculates all four quadrants.
Note:
The arguments mimic the behaviour of math.atan2(y, x)! Make sure you
pass them in the right order.
Args:
attr_a (NcNode or NcAttrs or str or int or float): Value or attr
attr_b (NcNode or NcAttrs or str or int or float): Value or attr
Returns:
NcNode: Instance with node and output-attr.
Example:
::
x = Node("pCube.tx")
y = Node("pCube.ty")
Op.atan2(y, x)
"""
# Measure the angle between a vector constructed out of given values.
angle_between = Op.angle_between(
(attr_b, 0, 0),
(attr_b, attr_a, 0),
)

# Change the angle, depending on the quadrant it lies in.
quadrant_1_and_4_cond = Op.condition(
attr_a > 0,
angle_between,
-angle_between,
)
quadrant_2_and_3_cond = Op.condition(
attr_a > 0,
180 - angle_between,
-180 + angle_between,
)
quadrant_cond = Op.condition(
attr_b > 0,
quadrant_1_and_4_cond,
quadrant_2_and_3_cond,
)

# Take care of special case where attr_b is zero & would result in angle=0.
right_angle_cond = Op.condition(
attr_b == 0,
Op.condition(attr_a < 0, -90, 90),
quadrant_cond,
)

return right_angle_cond
9 changes: 5 additions & 4 deletions node_calculator/base_operators.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Basic NodeCalculator operators."""
# This is an extension that is loaded by default.
"""Basic NodeCalculator operators.
# The main difference to the base_functions is that operators are stand-alone
# functions that create a Maya node.
This is an extension that is loaded by default.
The main difference to the base_functions is that operators are stand-alone
functions that create a Maya node.
"""
import math

from maya import cmds
Expand Down
Loading

0 comments on commit a328ad5

Please sign in to comment.