diff options
Diffstat (limited to 'intern')
-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 |
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)); |