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
path: root/intern
diff options
context:
space:
mode:
authorCharlie Jolly <charlie>2019-12-06 02:02:05 +0300
committerCharlie Jolly <mistajolly@gmail.com>2019-12-07 15:33:07 +0300
commit0406eb110332a863811d7fb6228f9a7ca514e022 (patch)
tree9809062966699e31c785ae0dc97ccb6e9f6c60f7 /intern
parent6a78ace569ec7c0e076e5af34d9496ce3363b81e (diff)
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL. This patch adds missing functions to the Blender maths node. Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch. This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt. Sign function is based on GLSL and OSL functions and returns zero when x == 0. Differential Revision: https://developer.blender.org/D5957
Diffstat (limited to 'intern')
-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
7 files changed, 180 insertions, 9 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));