Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/kernel/shaders/node_math.osl62
-rw-r--r--intern/cycles/kernel/svm/svm_math.h7
-rw-r--r--intern/cycles/kernel/svm/svm_math_util.h34
-rw-r--r--intern/cycles/kernel/svm/svm_types.h16
-rw-r--r--intern/cycles/render/nodes.cpp30
-rw-r--r--intern/cycles/render/nodes.h1
-rw-r--r--intern/cycles/util/util_math.h39
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c36
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cpp49
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cpp271
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.h126
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math.glsl138
-rw-r--r--source/blender/makesdna/DNA_node_types.h16
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c39
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.c39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c37
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c141
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);
}