diff options
-rw-r--r-- | intern/cycles/kernel/shaders/node_math.osl | 62 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_math.h | 7 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_math_util.h | 34 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_types.h | 16 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 30 | ||||
-rw-r--r-- | intern/cycles/render/nodes.h | 1 | ||||
-rw-r--r-- | intern/cycles/util/util_math.h | 39 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_base_inline.c | 36 | ||||
-rw-r--r-- | source/blender/compositor/nodes/COM_MathNode.cpp | 49 | ||||
-rw-r--r-- | source/blender/compositor/operations/COM_MathBaseOperation.cpp | 271 | ||||
-rw-r--r-- | source/blender/compositor/operations/COM_MathBaseOperation.h | 126 | ||||
-rw-r--r-- | source/blender/gpu/shaders/material/gpu_shader_material_math.glsl | 138 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 16 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 39 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_math.c | 39 | ||||
-rw-r--r-- | source/blender/nodes/shader/nodes/node_shader_math.c | 37 | ||||
-rw-r--r-- | source/blender/nodes/texture/nodes/node_texture_math.c | 141 |
17 files changed, 1044 insertions, 37 deletions
diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl index 13e4c91ba10..1eccb56405b 100644 --- a/intern/cycles/kernel/shaders/node_math.osl +++ b/intern/cycles/kernel/shaders/node_math.osl @@ -26,6 +26,35 @@ float safe_modulo(float a, float b) return (b != 0.0) ? fmod(a, b) : 0.0; } +float fract(float a) +{ + return a - floor(a); +} + +/* Adapted from godotengine math_funcs.h. */ +float wrap(float value, float max, float min) +{ + float range = max - min; + return (range != 0.0) ? value - (range * floor((value - min) / range)) : min; +} + +/* See: https://www.iquilezles.org/www/articles/smin/smin.htm. */ +float smoothmin(float a, float b, float c) +{ + if (c != 0.0) { + float h = max(c - abs(a - b), 0.0) / c; + return min(a, b) - h * h * h * c * (1.0 / 6.0); + } + else { + return min(a, b); + } +} + +float pingpong(float a, float b) +{ + return (b != 0.0) ? abs(fract((a - b) / (b * 2.0)) * b * 2.0 - b) : 0.0; +} + float safe_sqrt(float a) { return (a > 0.0) ? sqrt(a) : 0.0; @@ -40,6 +69,7 @@ float safe_log(float a, float b) shader node_math(string type = "add", float Value1 = 0.5, float Value2 = 0.5, + float Value3 = 0.5, output float Value = 0.0) { if (type == "add") @@ -56,8 +86,14 @@ shader node_math(string type = "add", Value = safe_log(Value1, Value2); else if (type == "sqrt") Value = safe_sqrt(Value1); + else if (type == "inversesqrt") + Value = inversesqrt(Value1); else if (type == "absolute") Value = fabs(Value1); + else if (type == "radians") + Value = radians(Value1); + else if (type == "degrees") + Value = degrees(Value1); else if (type == "minimum") Value = min(Value1, Value2); else if (type == "maximum") @@ -76,12 +112,26 @@ shader node_math(string type = "add", Value = Value1 - floor(Value1); else if (type == "modulo") Value = safe_modulo(Value1, Value2); + else if (type == "trunc") + Value = trunc(Value1); + else if (type == "snap") + Value = floor(safe_divide(Value1, Value2)) * Value2; + else if (type == "wrap") + Value = wrap(Value1, Value2, Value3); + else if (type == "pingpong") + Value = pingpong(Value1, Value2); else if (type == "sine") Value = sin(Value1); else if (type == "cosine") Value = cos(Value1); else if (type == "tangent") Value = tan(Value1); + else if (type == "sinh") + Value = sinh(Value1); + else if (type == "cosh") + Value = cosh(Value1); + else if (type == "tanh") + Value = tanh(Value1); else if (type == "arcsine") Value = asin(Value1); else if (type == "arccosine") @@ -90,6 +140,18 @@ shader node_math(string type = "add", Value = atan(Value1); else if (type == "arctan2") Value = atan2(Value1, Value2); + else if (type == "sign") + Value = sign(Value1); + else if (type == "exponent") + Value = exp(Value1); + else if (type == "compare") + Value = ((Value1 == Value2) || (abs(Value1 - Value2) <= max(Value3, 1e-5))) ? 1.0 : 0.0; + else if (type == "multiply_add") + Value = Value1 * Value2 + Value3; + else if (type == "smoothmin") + Value = smoothmin(Value1, Value2, Value3); + else if (type == "smoothmax") + Value = -(smoothmin(-Value1, -Value2, Value3)); else warning("%s", "Unknown math operator!"); } diff --git a/intern/cycles/kernel/svm/svm_math.h b/intern/cycles/kernel/svm/svm_math.h index d156dec497c..82cae7bbacf 100644 --- a/intern/cycles/kernel/svm/svm_math.h +++ b/intern/cycles/kernel/svm/svm_math.h @@ -24,12 +24,13 @@ ccl_device void svm_node_math(KernelGlobals *kg, uint result_stack_offset, int *offset) { - uint a_stack_offset, b_stack_offset; - svm_unpack_node_uchar2(inputs_stack_offsets, &a_stack_offset, &b_stack_offset); + uint a_stack_offset, b_stack_offset, c_stack_offset; + svm_unpack_node_uchar3(inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &c_stack_offset); float a = stack_load_float(stack, a_stack_offset); float b = stack_load_float(stack, b_stack_offset); - float result = svm_math((NodeMathType)type, a, b); + float c = stack_load_float(stack, c_stack_offset); + float result = svm_math((NodeMathType)type, a, b, c); stack_store_float(stack, result_stack_offset, result); } diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h index c07a1e4ed98..7b9eaaeb710 100644 --- a/intern/cycles/kernel/svm/svm_math_util.h +++ b/intern/cycles/kernel/svm/svm_math_util.h @@ -86,7 +86,7 @@ ccl_device void svm_vector_math( } } -ccl_device float svm_math(NodeMathType type, float a, float b) +ccl_device float svm_math(NodeMathType type, float a, float b, float c) { switch (type) { case NODE_MATH_ADD: @@ -103,8 +103,14 @@ ccl_device float svm_math(NodeMathType type, float a, float b) return safe_logf(a, b); case NODE_MATH_SQRT: return safe_sqrtf(a); + case NODE_MATH_INV_SQRT: + return inversesqrtf(a); case NODE_MATH_ABSOLUTE: return fabsf(a); + case NODE_MATH_RADIANS: + return a * (M_PI_F / 180.0f); + case NODE_MATH_DEGREES: + return a * (180.0f / M_PI_F); case NODE_MATH_MINIMUM: return fminf(a, b); case NODE_MATH_MAXIMUM: @@ -123,12 +129,26 @@ ccl_device float svm_math(NodeMathType type, float a, float b) return a - floorf(a); case NODE_MATH_MODULO: return safe_modulo(a, b); + case NODE_MATH_TRUNC: + return a >= 0.0f ? floorf(a) : ceilf(a); + case NODE_MATH_SNAP: + return floorf(safe_divide(a, b)) * b; + case NODE_MATH_WRAP: + return wrapf(a, b, c); + case NODE_MATH_PINGPONG: + return pingpongf(a, b); case NODE_MATH_SINE: return sinf(a); case NODE_MATH_COSINE: return cosf(a); case NODE_MATH_TANGENT: return tanf(a); + case NODE_MATH_SINH: + return sinhf(a); + case NODE_MATH_COSH: + return coshf(a); + case NODE_MATH_TANH: + return tanhf(a); case NODE_MATH_ARCSINE: return safe_asinf(a); case NODE_MATH_ARCCOSINE: @@ -137,6 +157,18 @@ ccl_device float svm_math(NodeMathType type, float a, float b) return atanf(a); case NODE_MATH_ARCTAN2: return atan2f(a, b); + case NODE_MATH_SIGN: + return compatible_signf(a); + case NODE_MATH_EXPONENT: + return expf(a); + case NODE_MATH_COMPARE: + return ((a == b) || (fabsf(a - b) <= fmaxf(c, FLT_EPSILON))) ? 1.0f : 0.0f; + case NODE_MATH_MULTIPLY_ADD: + return a * b + c; + case NODE_MATH_SMOOTH_MIN: + return smoothminf(a, b, c); + case NODE_MATH_SMOOTH_MAX: + return -smoothminf(-a, -b, c); default: return 0.0f; } diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index aa4dfdca2d1..8e312a515d6 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -281,6 +281,22 @@ typedef enum NodeMathType { NODE_MATH_CEIL, NODE_MATH_FRACTION, NODE_MATH_SQRT, + NODE_MATH_INV_SQRT, + NODE_MATH_SIGN, + NODE_MATH_EXPONENT, + NODE_MATH_RADIANS, + NODE_MATH_DEGREES, + NODE_MATH_SINH, + NODE_MATH_COSH, + NODE_MATH_TANH, + NODE_MATH_TRUNC, + NODE_MATH_SNAP, + NODE_MATH_WRAP, + NODE_MATH_COMPARE, + NODE_MATH_MULTIPLY_ADD, + NODE_MATH_PINGPONG, + NODE_MATH_SMOOTH_MIN, + NODE_MATH_SMOOTH_MAX, } NodeMathType; typedef enum NodeVectorMathType { diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index f637fbf3b37..c6f1e8409eb 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -5710,9 +5710,13 @@ NODE_DEFINE(MathNode) type_enum.insert("subtract", NODE_MATH_SUBTRACT); type_enum.insert("multiply", NODE_MATH_MULTIPLY); type_enum.insert("divide", NODE_MATH_DIVIDE); + type_enum.insert("multiply_add", NODE_MATH_MULTIPLY_ADD); type_enum.insert("sine", NODE_MATH_SINE); type_enum.insert("cosine", NODE_MATH_COSINE); type_enum.insert("tangent", NODE_MATH_TANGENT); + type_enum.insert("sinh", NODE_MATH_SINH); + type_enum.insert("cosh", NODE_MATH_COSH); + type_enum.insert("tanh", NODE_MATH_TANH); type_enum.insert("arcsine", NODE_MATH_ARCSINE); type_enum.insert("arccosine", NODE_MATH_ARCCOSINE); type_enum.insert("arctangent", NODE_MATH_ARCTANGENT); @@ -5729,13 +5733,26 @@ NODE_DEFINE(MathNode) type_enum.insert("floor", NODE_MATH_FLOOR); type_enum.insert("ceil", NODE_MATH_CEIL); type_enum.insert("fraction", NODE_MATH_FRACTION); + type_enum.insert("trunc", NODE_MATH_TRUNC); + type_enum.insert("snap", NODE_MATH_SNAP); + type_enum.insert("wrap", NODE_MATH_WRAP); + type_enum.insert("pingpong", NODE_MATH_PINGPONG); type_enum.insert("sqrt", NODE_MATH_SQRT); + type_enum.insert("inversesqrt", NODE_MATH_INV_SQRT); + type_enum.insert("sign", NODE_MATH_SIGN); + type_enum.insert("exponent", NODE_MATH_EXPONENT); + type_enum.insert("radians", NODE_MATH_RADIANS); + type_enum.insert("degrees", NODE_MATH_DEGREES); + type_enum.insert("smoothmin", NODE_MATH_SMOOTH_MIN); + type_enum.insert("smoothmax", NODE_MATH_SMOOTH_MAX); + type_enum.insert("compare", NODE_MATH_COMPARE); SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD); SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); SOCKET_IN_FLOAT(value1, "Value1", 0.5f); SOCKET_IN_FLOAT(value2, "Value2", 0.5f); + SOCKET_IN_FLOAT(value3, "Value3", 0.0f); SOCKET_OUT_FLOAT(value, "Value"); @@ -5764,7 +5781,7 @@ void MathNode::expand(ShaderGraph *graph) void MathNode::constant_fold(const ConstantFolder &folder) { if (folder.all_inputs_constant()) { - folder.make_constant(svm_math(type, value1, value2)); + folder.make_constant(svm_math(type, value1, value2, value3)); } else { folder.fold_math(type); @@ -5775,16 +5792,19 @@ void MathNode::compile(SVMCompiler &compiler) { ShaderInput *value1_in = input("Value1"); ShaderInput *value2_in = input("Value2"); + ShaderInput *value3_in = input("Value3"); ShaderOutput *value_out = output("Value"); int value1_stack_offset = compiler.stack_assign(value1_in); int value2_stack_offset = compiler.stack_assign(value2_in); + int value3_stack_offset = compiler.stack_assign(value3_in); int value_stack_offset = compiler.stack_assign(value_out); - compiler.add_node(NODE_MATH, - type, - compiler.encode_uchar4(value1_stack_offset, value2_stack_offset), - value_stack_offset); + compiler.add_node( + NODE_MATH, + type, + compiler.encode_uchar4(value1_stack_offset, value2_stack_offset, value3_stack_offset), + value_stack_offset); } void MathNode::compile(OSLCompiler &compiler) diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 62037b0d381..b8f1328f4b9 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -1324,6 +1324,7 @@ class MathNode : public ShaderNode { float value1; float value2; + float value3; NodeMathType type; bool use_clamp; }; diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 53e528de66e..dc211d2ed4e 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -344,6 +344,29 @@ ccl_device_inline int ceil_to_int(float f) return float_to_int(ceilf(f)); } +ccl_device_inline float fractf(float x) +{ + return x - floorf(x); +} + +/* Adapted from godotengine math_funcs.h. */ +ccl_device_inline float wrapf(float value, float max, float min) +{ + float range = max - min; + return (range != 0.0f) ? value - (range * floorf((value - min) / range)) : min; +} + +ccl_device_inline float pingpongf(float a, float b) +{ + return (b != 0.0f) ? fabsf(fractf((a - b) / (b * 2.0f)) * b * 2.0f - b) : 0.0f; +} + +ccl_device_inline float smoothminf(float a, float b, float k) +{ + float h = fmaxf(k - fabsf(a - b), 0.0f) / k; + return fminf(a, b) - h * h * h * k * (1.0f / 6.0f); +} + ccl_device_inline float signf(float f) { return (f < 0.0f) ? -1.0f : 1.0f; @@ -357,6 +380,17 @@ ccl_device_inline float nonzerof(float f, float eps) return f; } +/* Signum function testing for zero. Matches GLSL and OSL functions. */ +ccl_device_inline float compatible_signf(float f) +{ + if (f == 0.0f) { + return 0.0f; + } + else { + return signf(f); + } +} + ccl_device_inline float smoothstepf(float f) { float ff = f * f; @@ -549,6 +583,11 @@ ccl_device_inline float safe_sqrtf(float f) return sqrtf(max(f, 0.0f)); } +ccl_device_inline float inversesqrtf(float f) +{ + return (f > 0.0f) ? 1.0f / sqrtf(f) : 0.0f; +} + ccl_device float safe_asinf(float a) { return asinf(clamp(a, -1.0f, 1.0f)); diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 85c6425bb2f..a1c88edca6f 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -363,6 +363,18 @@ MINLINE int mod_i(int i, int n) return (i % n + n) % n; } +MINLINE float fractf(float a) +{ + return a - floorf(a); +} + +/* Adapted from godotengine math_funcs.h. */ +MINLINE float wrapf(float value, float max, float min) +{ + float range = max - min; + return (range != 0.0f) ? value - (range * floorf((value - min) / range)) : min; +} + MINLINE float min_ff(float a, float b) { return (a < b) ? a : b; @@ -371,6 +383,17 @@ MINLINE float max_ff(float a, float b) { return (a > b) ? a : b; } +/* See: https://www.iquilezles.org/www/articles/smin/smin.htm. */ +MINLINE float smoothminf(float a, float b, float c) +{ + if (c != 0.0f) { + float h = max_ff(c - fabsf(a - b), 0.0f) / c; + return min_ff(a, b) - h * h * h * c * (1.0f / 6.0f); + } + else { + return min_ff(a, b); + } +} MINLINE double min_dd(double a, double b) { @@ -504,6 +527,19 @@ MINLINE float signf(float f) return (f < 0.f) ? -1.f : 1.f; } +MINLINE float compatible_signf(float f) +{ + if (f > 0.0f) { + return 1.0f; + } + if (f < 0.0f) { + return -1.0f; + } + else { + return 0.0f; + } +} + MINLINE int signum_i_ex(float a, float eps) { if (a > eps) { diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp index d13b34bb6b5..5497d4a4755 100644 --- a/source/blender/compositor/nodes/COM_MathNode.cpp +++ b/source/blender/compositor/nodes/COM_MathNode.cpp @@ -56,6 +56,15 @@ void MathNode::convertToOperations(NodeConverter &converter, case NODE_MATH_ARCTANGENT: operation = new MathArcTangentOperation(); break; + case NODE_MATH_SINH: + operation = new MathHyperbolicSineOperation(); + break; + case NODE_MATH_COSH: + operation = new MathHyperbolicCosineOperation(); + break; + case NODE_MATH_TANH: + operation = new MathHyperbolicTangentOperation(); + break; case NODE_MATH_POWER: operation = new MathPowerOperation(); break; @@ -83,6 +92,12 @@ void MathNode::convertToOperations(NodeConverter &converter, case NODE_MATH_ABSOLUTE: operation = new MathAbsoluteOperation(); break; + case NODE_MATH_RADIANS: + operation = new MathRadiansOperation(); + break; + case NODE_MATH_DEGREES: + operation = new MathDegreesOperation(); + break; case NODE_MATH_ARCTAN2: operation = new MathArcTan2Operation(); break; @@ -98,6 +113,39 @@ void MathNode::convertToOperations(NodeConverter &converter, case NODE_MATH_SQRT: operation = new MathSqrtOperation(); break; + case NODE_MATH_INV_SQRT: + operation = new MathInverseSqrtOperation(); + break; + case NODE_MATH_SIGN: + operation = new MathSignOperation(); + break; + case NODE_MATH_EXPONENT: + operation = new MathExponentOperation(); + break; + case NODE_MATH_TRUNC: + operation = new MathTruncOperation(); + break; + case NODE_MATH_SNAP: + operation = new MathSnapOperation(); + break; + case NODE_MATH_WRAP: + operation = new MathWrapOperation(); + break; + case NODE_MATH_PINGPONG: + operation = new MathPingpongOperation(); + break; + case NODE_MATH_COMPARE: + operation = new MathCompareOperation(); + break; + case NODE_MATH_MULTIPLY_ADD: + operation = new MathMultiplyAddOperation(); + break; + case NODE_MATH_SMOOTH_MIN: + operation = new MathSmoothMinOperation(); + break; + case NODE_MATH_SMOOTH_MAX: + operation = new MathSmoothMaxOperation(); + break; } if (operation) { @@ -107,6 +155,7 @@ void MathNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } } diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp index 15dbd4e2ac9..d103cc3cf0d 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp @@ -25,9 +25,11 @@ MathBaseOperation::MathBaseOperation() : NodeOperation() { this->addInputSocket(COM_DT_VALUE); this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); this->addOutputSocket(COM_DT_VALUE); this->m_inputValue1Operation = NULL; this->m_inputValue2Operation = NULL; + this->m_inputValue3Operation = NULL; this->m_useClamp = false; } @@ -35,12 +37,14 @@ void MathBaseOperation::initExecution() { this->m_inputValue1Operation = this->getInputSocketReader(0); this->m_inputValue2Operation = this->getInputSocketReader(1); + this->m_inputValue3Operation = this->getInputSocketReader(2); } void MathBaseOperation::deinitExecution() { this->m_inputValue1Operation = NULL; this->m_inputValue2Operation = NULL; + this->m_inputValue3Operation = NULL; } void MathBaseOperation::determineResolution(unsigned int resolution[2], @@ -182,6 +186,54 @@ void MathTangentOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathHyperbolicSineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = sinh(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathHyperbolicCosineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = cosh(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathHyperbolicTangentOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = tanh(inputValue1[0]); + + clampIfNeeded(output); +} + void MathArcSineOperation::executePixelSampled(float output[4], float x, float y, @@ -404,6 +456,34 @@ void MathAbsoluteOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathRadiansOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = DEG2RADF(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathDegreesOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = RAD2DEGF(inputValue1[0]); + + clampIfNeeded(output); +} + void MathArcTan2Operation::executePixelSampled(float output[4], float x, float y, @@ -480,3 +560,194 @@ void MathSqrtOperation::executePixelSampled(float output[4], clampIfNeeded(output); } + +void MathInverseSqrtOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + if (inputValue1[0] > 0) { + output[0] = 1.0f / sqrt(inputValue1[0]); + } + else { + output[0] = 0.0f; + } + + clampIfNeeded(output); +} + +void MathSignOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = compatible_signf(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathExponentOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = expf(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathTruncOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = (inputValue1[0] >= 0.0f) ? floor(inputValue1[0]) : ceil(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathSnapOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + if (inputValue1[0] == 0 || inputValue2[0] == 0) { /* We don't want to divide by zero. */ + output[0] = 0.0f; + } + else { + output[0] = floorf(inputValue1[0] / inputValue2[0]) * inputValue2[0]; + } + + clampIfNeeded(output); +} + +void MathWrapOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = wrapf(inputValue1[0], inputValue2[0], inputValue3[0]); + + clampIfNeeded(output); +} + +void MathPingpongOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = output[0] = fabsf( + fractf((inputValue1[0] - inputValue2[0]) / (inputValue2[0] * 2.0f)) * inputValue2[0] * 2.0f - + inputValue2[0]); + + clampIfNeeded(output); +} + +void MathCompareOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = (fabsf(inputValue1[0] - inputValue2[0]) <= MAX2(inputValue3[0], 1e-5f)) ? 1.0f : + 0.0f; + + clampIfNeeded(output); +} + +void MathMultiplyAddOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = inputValue1[0] * inputValue2[0] + inputValue3[0]; + + clampIfNeeded(output); +} + +void MathSmoothMinOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = smoothminf(inputValue1[0], inputValue2[0], inputValue3[0]); + + clampIfNeeded(output); +} + +void MathSmoothMaxOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = -smoothminf(-inputValue1[0], -inputValue2[0], inputValue3[0]); + + clampIfNeeded(output); +} diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h index 7c11ea8f45b..199b59d8649 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.h +++ b/source/blender/compositor/operations/COM_MathBaseOperation.h @@ -31,6 +31,7 @@ class MathBaseOperation : public NodeOperation { */ SocketReader *m_inputValue1Operation; SocketReader *m_inputValue2Operation; + SocketReader *m_inputValue3Operation; bool m_useClamp; @@ -119,6 +120,28 @@ class MathTangentOperation : public MathBaseOperation { void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); }; +class MathHyperbolicSineOperation : public MathBaseOperation { + public: + MathHyperbolicSineOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; +class MathHyperbolicCosineOperation : public MathBaseOperation { + public: + MathHyperbolicCosineOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; +class MathHyperbolicTangentOperation : public MathBaseOperation { + public: + MathHyperbolicTangentOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + class MathArcSineOperation : public MathBaseOperation { public: MathArcSineOperation() : MathBaseOperation() @@ -206,6 +229,22 @@ class MathAbsoluteOperation : public MathBaseOperation { void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); }; +class MathRadiansOperation : public MathBaseOperation { + public: + MathRadiansOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathDegreesOperation : public MathBaseOperation { + public: + MathDegreesOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + class MathArcTan2Operation : public MathBaseOperation { public: MathArcTan2Operation() : MathBaseOperation() @@ -246,4 +285,91 @@ class MathSqrtOperation : public MathBaseOperation { void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); }; +class MathInverseSqrtOperation : public MathBaseOperation { + public: + MathInverseSqrtOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathSignOperation : public MathBaseOperation { + public: + MathSignOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathExponentOperation : public MathBaseOperation { + public: + MathExponentOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathTruncOperation : public MathBaseOperation { + public: + MathTruncOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathSnapOperation : public MathBaseOperation { + public: + MathSnapOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathWrapOperation : public MathBaseOperation { + public: + MathWrapOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathPingpongOperation : public MathBaseOperation { + public: + MathPingpongOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathCompareOperation : public MathBaseOperation { + public: + MathCompareOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathMultiplyAddOperation : public MathBaseOperation { + public: + MathMultiplyAddOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathSmoothMinOperation : public MathBaseOperation { + public: + MathSmoothMinOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathSmoothMaxOperation : public MathBaseOperation { + public: + MathSmoothMaxOperation() : MathBaseOperation() + { + } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl index 4fac770e8fe..de3be98b715 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl @@ -1,24 +1,24 @@ -void math_add(float a, float b, out float result) +void math_add(float a, float b, float c, out float result) { result = a + b; } -void math_subtract(float a, float b, out float result) +void math_subtract(float a, float b, float c, out float result) { result = a - b; } -void math_multiply(float a, float b, out float result) +void math_multiply(float a, float b, float c, out float result) { result = a * b; } -void math_divide(float a, float b, out float result) +void math_divide(float a, float b, float c, out float result) { result = safe_divide(a, b); } -void math_power(float a, float b, out float result) +void math_power(float a, float b, float c, out float result) { if (a >= 0.0) { result = compatible_pow(a, b); @@ -34,97 +34,187 @@ void math_power(float a, float b, out float result) } } -void math_logarithm(float a, float b, out float result) +void math_logarithm(float a, float b, float c, out float result) { result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0; } -void math_sqrt(float a, float b, out float result) +void math_sqrt(float a, float b, float c, out float result) { result = (a > 0.0) ? sqrt(a) : 0.0; } -void math_absolute(float a, float b, out float result) +void math_inversesqrt(float a, float b, float c, out float result) +{ + result = inversesqrt(a); +} + +void math_absolute(float a, float b, float c, out float result) { result = abs(a); } -void math_minimum(float a, float b, out float result) +void math_radians(float a, float b, float c, out float result) +{ + result = radians(a); +} + +void math_degrees(float a, float b, float c, out float result) +{ + result = degrees(a); +} + +void math_minimum(float a, float b, float c, out float result) { result = min(a, b); } -void math_maximum(float a, float b, out float result) +void math_maximum(float a, float b, float c, out float result) { result = max(a, b); } -void math_less_than(float a, float b, out float result) +void math_less_than(float a, float b, float c, out float result) { result = (a < b) ? 1.0 : 0.0; } -void math_greater_than(float a, float b, out float result) +void math_greater_than(float a, float b, float c, out float result) { result = (a > b) ? 1.0 : 0.0; } -void math_round(float a, float b, out float result) +void math_round(float a, float b, float c, out float result) { result = floor(a + 0.5); } -void math_floor(float a, float b, out float result) +void math_floor(float a, float b, float c, out float result) { result = floor(a); } -void math_ceil(float a, float b, out float result) +void math_ceil(float a, float b, float c, out float result) { result = ceil(a); } -void math_fraction(float a, float b, out float result) +void math_fraction(float a, float b, float c, out float result) { result = a - floor(a); } -void math_modulo(float a, float b, out float result) +void math_modulo(float a, float b, float c, out float result) { result = c_mod(a, b); } -void math_sine(float a, float b, out float result) +void math_trunc(float a, float b, float c, out float result) +{ + result = trunc(a); +} + +void math_snap(float a, float b, float c, out float result) +{ + result = floor(safe_divide(a, b)) * b; +} + +void math_pingpong(float a, float b, float c, out float result) +{ + result = (b != 0.0) ? abs(fract((a - b) / (b * 2.0)) * b * 2.0 - b) : 0.0; +} + +/* Adapted from godotengine math_funcs.h. */ +void math_wrap(float a, float b, float c, out float result) +{ + float range = b - c; + result = (range != 0.0) ? a - (range * floor((a - c) / range)) : c; +} + +void math_sine(float a, float b, float c, out float result) { result = sin(a); } -void math_cosine(float a, float b, out float result) +void math_cosine(float a, float b, float c, out float result) { result = cos(a); } -void math_tangent(float a, float b, out float result) +void math_tangent(float a, float b, float c, out float result) { result = tan(a); } -void math_arcsine(float a, float b, out float result) +void math_sinh(float a, float b, float c, out float result) +{ + result = sinh(a); +} + +void math_cosh(float a, float b, float c, out float result) +{ + result = cosh(a); +} + +void math_tanh(float a, float b, float c, out float result) +{ + result = tanh(a); +} + +void math_arcsine(float a, float b, float c, out float result) { result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0; } -void math_arccosine(float a, float b, out float result) +void math_arccosine(float a, float b, float c, out float result) { result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0; } -void math_arctangent(float a, float b, out float result) +void math_arctangent(float a, float b, float c, out float result) { result = atan(a); } -void math_arctan2(float a, float b, out float result) +void math_arctan2(float a, float b, float c, out float result) { result = atan(a, b); } + +void math_sign(float a, float b, float c, out float result) +{ + result = sign(a); +} + +void math_exponent(float a, float b, float c, out float result) +{ + result = exp(a); +} + +void math_compare(float a, float b, float c, out float result) +{ + result = (abs(a - b) <= max(c, 1e-5)) ? 1.0 : 0.0; +} + +void math_multiply_add(float a, float b, float c, out float result) +{ + result = a * b + c; +} + +/* See: https://www.iquilezles.org/www/articles/smin/smin.htm. */ +void math_smoothmin(float a, float b, float c, out float result) +{ + if (c != 0.0) { + float h = max(c - abs(a - b), 0.0) / c; + result = min(a, b) - h * h * h * c * (1.0 / 6.0); + } + else { + result = min(a, b); + } +} + +void math_smoothmax(float a, float b, float c, out float result) +{ + math_smoothmin(-a, -b, c, result); + result = -result; +} diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 7eecf23195a..06ddf08b2ce 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1215,6 +1215,22 @@ enum { NODE_MATH_CEIL = 21, NODE_MATH_FRACTION = 22, NODE_MATH_SQRT = 23, + NODE_MATH_INV_SQRT = 24, + NODE_MATH_SIGN = 25, + NODE_MATH_EXPONENT = 26, + NODE_MATH_RADIANS = 27, + NODE_MATH_DEGREES = 28, + NODE_MATH_SINH = 29, + NODE_MATH_COSH = 30, + NODE_MATH_TANH = 31, + NODE_MATH_TRUNC = 32, + NODE_MATH_SNAP = 33, + NODE_MATH_WRAP = 34, + NODE_MATH_COMPARE = 35, + NODE_MATH_MULTIPLY_ADD = 36, + NODE_MATH_PINGPONG = 37, + NODE_MATH_SMOOTH_MIN = 38, + NODE_MATH_SMOOTH_MAX = 39, }; /* Vector Math node operations. */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 287c7502c41..272a4522152 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -123,21 +123,37 @@ const EnumPropertyItem rna_enum_mapping_type_items[] = { }; const EnumPropertyItem rna_enum_node_math_items[] = { + {0, "", 0, N_("Functions"), ""}, {NODE_MATH_ADD, "ADD", 0, "Add", "A + B"}, {NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"}, {NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"}, {NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", "A / B"}, + {NODE_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"}, {0, "", ICON_NONE, NULL, NULL}, {NODE_MATH_POWER, "POWER", 0, "Power", "A power B"}, {NODE_MATH_LOGARITHM, "LOGARITHM", 0, "Logarithm", "Logarithm A base B"}, {NODE_MATH_SQRT, "SQRT", 0, "Square Root", "Square root of A"}, + {NODE_MATH_INV_SQRT, "INVERSE_SQRT", 0, "Inverse Square Root", "1 / Square root of A"}, {NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Magnitude of A"}, - {0, "", ICON_NONE, NULL, NULL}, + {NODE_MATH_EXPONENT, "EXPONENT", 0, "Exponent", "exp(A)"}, + {0, "", 0, N_("Comparison"), ""}, {NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "The minimum from A and B"}, {NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "The maximum from A and B"}, {NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"}, {NODE_MATH_GREATER_THAN, "GREATER_THAN", 0, "Greater Than", "1 if A > B else 0"}, - {0, "", ICON_NONE, NULL, NULL}, + {NODE_MATH_SIGN, "SIGN", 0, "Sign", "Returns the sign of A"}, + {NODE_MATH_COMPARE, "COMPARE", 0, "Compare", "1 if (A == B) within tolerance C else 0"}, + {NODE_MATH_SMOOTH_MIN, + "SMOOTH_MIN", + 0, + "Smooth Minimum", + "The minimum from A and B with smoothing C"}, + {NODE_MATH_SMOOTH_MAX, + "SMOOTH_MAX", + 0, + "Smooth Maximum", + "The maximum from A and B with smoothing C"}, + {0, "", 0, N_("Rounding"), ""}, {NODE_MATH_ROUND, "ROUND", 0, @@ -145,16 +161,33 @@ const EnumPropertyItem rna_enum_node_math_items[] = { "Round A to the nearest integer. Round upward if the fraction part is 0.5"}, {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"}, {NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"}, + {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "trunc(A)"}, + {0, "", ICON_NONE, NULL, NULL}, {NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"}, {NODE_MATH_MODULO, "MODULO", 0, "Modulo", "A mod B"}, - {0, "", ICON_NONE, NULL, NULL}, + {NODE_MATH_SNAP, "SNAP", 0, "Snap", "Snap to increment, snap(A,B)"}, + {NODE_MATH_WRAP, "WRAP", 0, "Wrap", "Wrap value to range, wrap(A,B)"}, + {NODE_MATH_PINGPONG, + "PINGPONG", + 0, + "Pingpong", + "Wraps a value and reverses every other cycle (A,B)"}, + {0, "", 0, N_("Trigonometric"), ""}, {NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"}, {NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"}, {NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"}, + {0, "", ICON_NONE, NULL, NULL}, {NODE_MATH_ARCSINE, "ARCSINE", 0, "Arcsine", "arcsin(A)"}, {NODE_MATH_ARCCOSINE, "ARCCOSINE", 0, "Arccosine", "arccos(A)"}, {NODE_MATH_ARCTANGENT, "ARCTANGENT", 0, "Arctangent", "arctan(A)"}, {NODE_MATH_ARCTAN2, "ARCTAN2", 0, "Arctan2", "The signed angle arctan(A / B)"}, + {0, "", ICON_NONE, NULL, NULL}, + {NODE_MATH_SINH, "SINH", 0, "Hyperbolic Sine", "sinh(A)"}, + {NODE_MATH_COSH, "COSH", 0, "Hyperbolic Cosine", "cosh(A)"}, + {NODE_MATH_TANH, "TANH", 0, "Hyperbolic Tangent", "tanh(A)"}, + {0, "", 0, N_("Conversion"), ""}, + {NODE_MATH_RADIANS, "RADIANS", 0, "To Radians", "Convert from degrees to radians"}, + {NODE_MATH_DEGREES, "DEGREES", 0, "To Degrees", "Convert from radians to degrees"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/nodes/composite/nodes/node_composite_math.c b/source/blender/nodes/composite/nodes/node_composite_math.c index 21a85b2168f..741c0e48806 100644 --- a/source/blender/nodes/composite/nodes/node_composite_math.c +++ b/source/blender/nodes/composite/nodes/node_composite_math.c @@ -27,10 +27,48 @@ static bNodeSocketTemplate cmp_node_math_in[] = { {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, + {SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, {-1, 0, ""}}; static bNodeSocketTemplate cmp_node_math_out[] = {{SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}}; +static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock = BLI_findlink(&node->inputs, 1); + nodeSetSocketAvailability(sock, + !ELEM(node->custom1, + NODE_MATH_SQRT, + NODE_MATH_SIGN, + NODE_MATH_CEIL, + NODE_MATH_SINE, + NODE_MATH_ROUND, + NODE_MATH_FLOOR, + NODE_MATH_COSINE, + NODE_MATH_ARCSINE, + NODE_MATH_TANGENT, + NODE_MATH_ABSOLUTE, + NODE_MATH_RADIANS, + NODE_MATH_DEGREES, + NODE_MATH_FRACTION, + NODE_MATH_ARCCOSINE, + NODE_MATH_ARCTANGENT) && + !ELEM(node->custom1, + NODE_MATH_INV_SQRT, + NODE_MATH_TRUNC, + NODE_MATH_EXPONENT, + NODE_MATH_COSH, + NODE_MATH_SINH, + NODE_MATH_TANH)); + bNodeSocket *sock2 = BLI_findlink(&node->inputs, 2); + nodeSetSocketAvailability(sock2, + ELEM(node->custom1, + NODE_MATH_COMPARE, + NODE_MATH_MULTIPLY_ADD, + NODE_MATH_WRAP, + NODE_MATH_SMOOTH_MIN, + NODE_MATH_SMOOTH_MAX)); +} + void register_node_type_cmp_math(void) { static bNodeType ntype; @@ -38,6 +76,7 @@ void register_node_type_cmp_math(void) cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, cmp_node_math_in, cmp_node_math_out); node_type_label(&ntype, node_math_label); + node_type_update(&ntype, node_shader_update_math); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c index 0f1113920c9..5d9da7788ee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.c +++ b/source/blender/nodes/shader/nodes/node_shader_math.c @@ -27,6 +27,7 @@ static bNodeSocketTemplate sh_node_math_in[] = { {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, + {SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, {-1, 0, ""}}; static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}}; @@ -42,26 +43,42 @@ static int gpu_shader_math(GPUMaterial *mat, [NODE_MATH_SUBTRACT] = "math_subtract", [NODE_MATH_MULTIPLY] = "math_multiply", [NODE_MATH_DIVIDE] = "math_divide", + [NODE_MATH_MULTIPLY_ADD] = "math_multiply_add", [NODE_MATH_POWER] = "math_power", [NODE_MATH_LOGARITHM] = "math_logarithm", + [NODE_MATH_EXPONENT] = "math_exponent", [NODE_MATH_SQRT] = "math_sqrt", + [NODE_MATH_INV_SQRT] = "math_inversesqrt", [NODE_MATH_ABSOLUTE] = "math_absolute", + [NODE_MATH_RADIANS] = "math_radians", + [NODE_MATH_DEGREES] = "math_degrees", [NODE_MATH_MINIMUM] = "math_minimum", [NODE_MATH_MAXIMUM] = "math_maximum", [NODE_MATH_LESS_THAN] = "math_less_than", [NODE_MATH_GREATER_THAN] = "math_greater_than", + [NODE_MATH_SIGN] = "math_sign", + [NODE_MATH_COMPARE] = "math_compare", + [NODE_MATH_SMOOTH_MIN] = "math_smoothmin", + [NODE_MATH_SMOOTH_MAX] = "math_smoothmax", [NODE_MATH_ROUND] = "math_round", [NODE_MATH_FLOOR] = "math_floor", [NODE_MATH_CEIL] = "math_ceil", [NODE_MATH_FRACTION] = "math_fraction", [NODE_MATH_MODULO] = "math_modulo", + [NODE_MATH_TRUNC] = "math_trunc", + [NODE_MATH_SNAP] = "math_snap", + [NODE_MATH_WRAP] = "math_wrap", + [NODE_MATH_PINGPONG] = "math_pingpong", [NODE_MATH_SINE] = "math_sine", [NODE_MATH_COSINE] = "math_cosine", [NODE_MATH_TANGENT] = "math_tangent", + [NODE_MATH_SINH] = "math_sinh", + [NODE_MATH_COSH] = "math_cosh", + [NODE_MATH_TANH] = "math_tanh", [NODE_MATH_ARCSINE] = "math_arcsine", [NODE_MATH_ARCCOSINE] = "math_arccosine", [NODE_MATH_ARCTANGENT] = "math_arctangent", @@ -90,6 +107,7 @@ static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node) nodeSetSocketAvailability(sock, !ELEM(node->custom1, NODE_MATH_SQRT, + NODE_MATH_SIGN, NODE_MATH_CEIL, NODE_MATH_SINE, NODE_MATH_ROUND, @@ -98,9 +116,26 @@ static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node) NODE_MATH_ARCSINE, NODE_MATH_TANGENT, NODE_MATH_ABSOLUTE, + NODE_MATH_RADIANS, + NODE_MATH_DEGREES, NODE_MATH_FRACTION, NODE_MATH_ARCCOSINE, - NODE_MATH_ARCTANGENT)); + NODE_MATH_ARCTANGENT) && + !ELEM(node->custom1, + NODE_MATH_INV_SQRT, + NODE_MATH_TRUNC, + NODE_MATH_EXPONENT, + NODE_MATH_COSH, + NODE_MATH_SINH, + NODE_MATH_TANH)); + bNodeSocket *sock2 = BLI_findlink(&node->inputs, 2); + nodeSetSocketAvailability(sock2, + ELEM(node->custom1, + NODE_MATH_COMPARE, + NODE_MATH_MULTIPLY_ADD, + NODE_MATH_WRAP, + NODE_MATH_SMOOTH_MIN, + NODE_MATH_SMOOTH_MAX)); } void register_node_type_sh_math(void) diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c index b1d67a5a953..310300df204 100644 --- a/source/blender/nodes/texture/nodes/node_texture_math.c +++ b/source/blender/nodes/texture/nodes/node_texture_math.c @@ -28,6 +28,7 @@ static bNodeSocketTemplate inputs[] = { {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f, PROP_NONE}, {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f, PROP_NONE}, + {SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f, PROP_NONE}, {-1, 0, ""}, }; @@ -74,6 +75,18 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor *out = tanf(in0); break; } + case NODE_MATH_SINH: { + *out = sinhf(in0); + break; + } + case NODE_MATH_COSH: { + *out = coshf(in0); + break; + } + case NODE_MATH_TANH: { + *out = tanhf(in0); + break; + } case NODE_MATH_ARCSINE: { /* Can't do the impossible... */ if (in0 <= 1 && in0 >= -1) { @@ -182,11 +195,31 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor break; } + case NODE_MATH_RADIANS: { + *out = DEG2RADF(in0); + break; + } + + case NODE_MATH_DEGREES: { + *out = RAD2DEGF(in0); + break; + } + case NODE_MATH_ARCTAN2: { *out = atan2(in0, in1); break; } + case NODE_MATH_SIGN: { + *out = compatible_signf(in0); + break; + } + + case NODE_MATH_EXPONENT: { + *out = expf(in0); + break; + } + case NODE_MATH_FLOOR: { *out = floorf(in0); break; @@ -212,6 +245,76 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor break; } + case NODE_MATH_INV_SQRT: { + if (in0 > 0.0f) { + *out = 1.0f / sqrtf(in0); + } + else { + *out = 0.0f; + } + break; + } + + case NODE_MATH_TRUNC: { + if (in0 > 0.0f) { + *out = floorf(in0); + } + else { + *out = ceilf(in0); + } + break; + } + + case NODE_MATH_SNAP: { + if (in1 == 0) { + *out = 0.0; + } + else { + *out = floorf(in0 / in1) * in1; + } + break; + } + + case NODE_MATH_WRAP: { + float in2 = tex_input_value(in[2], p, thread); + *out = wrapf(in0, in1, in2); + break; + } + + case NODE_MATH_PINGPONG: { + if (in1 == 0.0f) { + *out = 0.0f; + } + else { + *out = fabsf(fractf((in0 - in1) / (in1 * 2.0f)) * in1 * 2.0f - in1); + } + break; + } + + case NODE_MATH_COMPARE: { + float in2 = tex_input_value(in[2], p, thread); + *out = (fabsf(in0 - in1) <= MAX2(in2, 1e-5f)) ? 1.0f : 0.0f; + break; + } + + case NODE_MATH_MULTIPLY_ADD: { + float in2 = tex_input_value(in[2], p, thread); + *out = in0 * in1 + in2; + break; + } + + case NODE_MATH_SMOOTH_MIN: { + float in2 = tex_input_value(in[2], p, thread); + *out = smoothminf(in0, in1, in2); + break; + } + + case NODE_MATH_SMOOTH_MAX: { + float in2 = tex_input_value(in[2], p, thread); + *out = -smoothminf(-in0, -in1, in2); + break; + } + default: { BLI_assert(0); break; @@ -233,6 +336,43 @@ static void exec(void *data, tex_output(node, execdata, in, out[0], &valuefn, data); } +static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock = BLI_findlink(&node->inputs, 1); + nodeSetSocketAvailability(sock, + !ELEM(node->custom1, + NODE_MATH_SQRT, + NODE_MATH_SIGN, + NODE_MATH_CEIL, + NODE_MATH_SINE, + NODE_MATH_ROUND, + NODE_MATH_FLOOR, + NODE_MATH_COSINE, + NODE_MATH_ARCSINE, + NODE_MATH_TANGENT, + NODE_MATH_ABSOLUTE, + NODE_MATH_RADIANS, + NODE_MATH_DEGREES, + NODE_MATH_FRACTION, + NODE_MATH_ARCCOSINE, + NODE_MATH_ARCTANGENT) && + !ELEM(node->custom1, + NODE_MATH_INV_SQRT, + NODE_MATH_TRUNC, + NODE_MATH_EXPONENT, + NODE_MATH_COSH, + NODE_MATH_SINH, + NODE_MATH_TANH)); + bNodeSocket *sock2 = BLI_findlink(&node->inputs, 2); + nodeSetSocketAvailability(sock2, + ELEM(node->custom1, + NODE_MATH_COMPARE, + NODE_MATH_MULTIPLY_ADD, + NODE_MATH_WRAP, + NODE_MATH_SMOOTH_MIN, + NODE_MATH_SMOOTH_MAX)); +} + void register_node_type_tex_math(void) { static bNodeType ntype; @@ -242,6 +382,7 @@ void register_node_type_tex_math(void) node_type_label(&ntype, node_math_label); node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, exec); + node_type_update(&ntype, node_shader_update_math); nodeRegisterType(&ntype); } |