Source code for procfunc.nodes.math

"""
Math and Vector Math Node bindings for Blender
"""

from typing import Literal

from procfunc import types as pt
from procfunc.nodes import types as nt


[docs] def clamp( value: nt.SocketOrVal[float] = 1.0, min: nt.SocketOrVal[float] = 0.0, max: nt.SocketOrVal[float] = 1.0, clamp_type: Literal["MINMAX", "RANGE"] = "MINMAX", ) -> nt.ProcNode[float]: """ Uses a Clamp Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/clamp.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeClamp", inputs={"Value": value, "Min": min, "Max": max}, attrs={"clamp_type": clamp_type}, )
# Math Nodes def _math( a: nt.SocketOrVal[float] = None, b: nt.SocketOrVal[float] = None, value_2: nt.SocketOrVal[float] = None, operation: str = "ADD", ) -> nt.ProcNode[float]: """ Uses a Math Shader Node. Procfunc does NOT support the inline clamp option - use pf.nodes.math.clamp() on the output instead. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/math.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeMath", inputs={("Value", 0): a, ("Value", 1): b, ("Value", 2): value_2}, attrs={ "operation": operation, "use_clamp": False, # not supported by procfunc }, ) # Basic Math Operations
[docs] def add( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="ADD")
[docs] def subtract( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="SUBTRACT")
[docs] def multiply( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="MULTIPLY")
[docs] def multiply_add( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5, addend: nt.SocketOrVal[float] = 0.0, ) -> nt.ProcNode[float]: return _math(a, b, addend, operation="MULTIPLY_ADD")
[docs] def divide( numerator: nt.SocketOrVal[float] = 0.5, denominator: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(numerator, denominator, operation="DIVIDE")
[docs] def power( base: nt.SocketOrVal[float] = 0.5, exponent: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(base, exponent, operation="POWER")
[docs] def logarithm( value: nt.SocketOrVal[float] = 0.5, base: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(value, base, operation="LOGARITHM")
[docs] def sqrt(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="SQRT")
[docs] def inverse_sqrt(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="INVERSE_SQRT")
[docs] def absolute(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="ABSOLUTE")
[docs] def exponent(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="EXPONENT")
# Comparison Operations
[docs] def minimum( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="MINIMUM")
[docs] def maximum( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="MAXIMUM")
[docs] def less_than( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="LESS_THAN")
[docs] def greater_than( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="GREATER_THAN")
[docs] def sign(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="SIGN")
[docs] def compare( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5, epsilon: nt.SocketOrVal[float] = 0.001, ) -> nt.ProcNode[float]: return _math(a, b, epsilon, operation="COMPARE")
[docs] def smooth_minimum( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5, distance: nt.SocketOrVal[float] = 0.0, ) -> nt.ProcNode[float]: return _math(a, b, distance, operation="SMOOTH_MIN")
[docs] def smooth_maximum( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5, distance: nt.SocketOrVal[float] = 0.0, ) -> nt.ProcNode[float]: return _math(a, b, distance, operation="SMOOTH_MAX")
[docs] def round(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="ROUND")
[docs] def floor(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="FLOOR")
[docs] def ceil(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="CEIL")
[docs] def truncate(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="TRUNC")
[docs] def fraction(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="FRACT")
[docs] def modulo( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="MODULO")
[docs] def floor_mod( a: nt.SocketOrVal[float] = 0.5, b: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(a, b, operation="FLOORED_MODULO")
[docs] def wrap( value: nt.SocketOrVal[float] = 0.5, max_val: nt.SocketOrVal[float] = 1.0, min_val: nt.SocketOrVal[float] = 0.0, ) -> nt.ProcNode[float]: return _math(value, max_val, min_val, operation="WRAP")
[docs] def snap( value: nt.SocketOrVal[float] = 0.5, increment: nt.SocketOrVal[float] = 1.0 ) -> nt.ProcNode[float]: return _math(value, increment, operation="SNAP")
[docs] def pingpong( value: nt.SocketOrVal[float] = 0.5, scale: nt.SocketOrVal[float] = 1.0 ) -> nt.ProcNode[float]: return _math(value, scale, operation="PINGPONG")
# Trigonometric Operations
[docs] def sin(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="SINE")
[docs] def cos(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="COSINE")
[docs] def tan(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="TANGENT")
[docs] def asin(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="ARCSINE")
[docs] def acos(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="ARCCOSINE")
[docs] def atan(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="ARCTANGENT")
[docs] def atan2( y: nt.SocketOrVal[float] = 0.5, x: nt.SocketOrVal[float] = 0.5 ) -> nt.ProcNode[float]: return _math(y, x, operation="ARCTAN2")
[docs] def sinh(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="SINH")
[docs] def cosh(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="COSH")
[docs] def tanh(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="TANH")
# Conversion Operations
[docs] def deg_to_rad(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="RADIANS")
[docs] def rad_to_deg(value: nt.SocketOrVal[float] = 0.5) -> nt.ProcNode[float]: return _math(value, operation="DEGREES")
# Vector Math Operations
[docs] def vector_add( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: """Add two vectors.""" return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "ADD"}, )
[docs] def vector_subtract( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "SUBTRACT"}, )
[docs] def vector_multiply( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "MULTIPLY"}, )
[docs] def vector_multiply_add( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), addend: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", attrs={"operation": "MULTIPLY_ADD"}, inputs={("Vector", 0): a, ("Vector", 1): b, ("Vector", 2): addend}, )
[docs] def vector_divide( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "DIVIDE"}, )
[docs] def vector_cross_product( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "CROSS_PRODUCT"}, )
[docs] def vector_project( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), onto: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[float]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector, ("Vector", 1): onto}, attrs={"operation": "PROJECT"}, )
[docs] def vector_reflect( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), normal: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): normal}, attrs={"operation": "REFLECT"}, )
[docs] def vector_refract( incident: nt.SocketOrVal[pt.Vector] = (0, 0, 0), normal: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ior: nt.SocketOrVal[float] = 1.0, ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): incident, ("Vector", 1): normal, ("Scale", 2): ior}, attrs={"operation": "REFRACT"}, )
[docs] def vector_faceforward( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), surface: nt.SocketOrVal[pt.Vector] = (0, 0, 0), normal: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={ ("Vector", 0): vector, ("Vector", 1): surface, ("Vector", 2): normal, }, attrs={"operation": "FACEFORWARD"}, )
[docs] def vector_dot_product( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "DOT_PRODUCT"}, )
[docs] def vector_distance( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "DISTANCE"}, )
[docs] def vector_length(vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0)) -> nt.ProcNode[float]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "LENGTH"}, )
[docs] def vector_scale( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), scale: nt.SocketOrVal[float] = 1.0 ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector, ("Scale", 0): scale}, attrs={"operation": "SCALE"}, )
[docs] def vector_normalize( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "NORMALIZE"}, )
[docs] def vector_wrap( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), max_val: nt.SocketOrVal[pt.Vector] = (1, 1, 1), min_val: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector, ("Vector", 1): max_val, ("Vector", 2): min_val}, attrs={"operation": "WRAP"}, )
[docs] def vector_snap( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (1, 1, 1), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "SNAP"}, )
[docs] def vector_floor( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "FLOOR"}, )
[docs] def vector_ceil( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "CEIL"}, )
[docs] def vector_modulo( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (1, 1, 1), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "MODULO"}, )
[docs] def vector_fraction( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "FRACTION"}, )
[docs] def vector_round( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "ROUND"}, )
[docs] def vector_truncate( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "TRUNC"}, )
[docs] def vector_absolute( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "ABSOLUTE"}, )
[docs] def vector_minimum( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "MINIMUM"}, )
[docs] def vector_maximum( a: nt.SocketOrVal[pt.Vector] = (0, 0, 0), b: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): a, ("Vector", 1): b}, attrs={"operation": "MAXIMUM"}, )
[docs] def vector_sine( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "SINE"}, )
[docs] def vector_cosine( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "COSINE"}, )
[docs] def vector_tangent( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorMath", inputs={("Vector", 0): vector}, attrs={"operation": "TANGENT"}, )
[docs] def vector_rotate_axis_angle( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), center: nt.SocketOrVal[pt.Vector] = (0, 0, 0), axis: nt.SocketOrVal[pt.Vector] = (0, 0, 1), angle: nt.SocketOrVal[float] = 0.0, invert: bool = False, ) -> nt.ProcNode[pt.Vector]: """ Uses a VectorRotate Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/vector/vector_rotate.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorRotate", inputs={"Vector": vector, "Center": center, "Axis": axis, "Angle": angle}, attrs={"invert": invert, "rotation_type": "AXIS_ANGLE"}, )
[docs] def vector_rotate_euler( vector: nt.SocketOrVal[pt.Vector] = (0, 0, 0), center: nt.SocketOrVal[pt.Vector] = (0, 0, 0), rotation: nt.SocketOrVal[pt.Vector] = (0, 0, 0), invert: bool = False, ) -> nt.ProcNode[pt.Vector]: return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorRotate", inputs={"Vector": vector, "Center": center, "Rotation": rotation}, attrs={"invert": invert, "rotation_type": "EULER_XYZ"}, )
# NOTE: mode XYZ have been dropped. transpiler specialcases will map these back to vector_rotate_euler calls.
[docs] def vector_transform( vector: nt.SocketOrVal[pt.Vector] = (0.5, 0.5, 0.5), convert_from: Literal["WORLD", "OBJECT", "CAMERA"] = "WORLD", convert_to: Literal["WORLD", "OBJECT", "CAMERA"] = "OBJECT", vector_type: Literal["POINT", "VECTOR", "NORMAL"] = "VECTOR", ) -> nt.ProcNode[pt.Vector]: """ Uses a VectorTransform Shader Node. See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/vector/transform.html """ return nt.ProcNode.from_nodetype( node_type="ShaderNodeVectorTransform", inputs={"Vector": vector}, attrs={ "convert_from": convert_from, "convert_to": convert_to, "vector_type": vector_type, }, )