diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl index 2ec1a5f0a32..214ef931660 100644 --- a/intern/cycles/kernel/shaders/node_math.osl +++ b/intern/cycles/kernel/shaders/node_math.osl @@ -30,6 +30,18 @@ float safe_divide(float a, float b) return result; } +float safe_modulo(float a, float b) +{ + float result; + + if (b == 0.0) + result = 0.0; + else + result = fmod(a, b); + + return result; +} + float safe_log(float a, float b) { if (a < 0.0 || b < 0.0) @@ -81,6 +93,8 @@ shader node_math( Value = Value1 < Value2; else if (type == "Greater Than") Value = Value1 > Value2; + else if (type == "Modulo") + Value = safe_modulo(Value1, Value2); if (Clamp) Value = clamp(Value1, 0.0, 1.0); diff --git a/intern/cycles/kernel/svm/svm_math.h b/intern/cycles/kernel/svm/svm_math.h index c7cd5200cd0..dbf477a0a96 100644 --- a/intern/cycles/kernel/svm/svm_math.h +++ b/intern/cycles/kernel/svm/svm_math.h @@ -56,6 +56,8 @@ __device float svm_math(NodeMath type, float Fac1, float Fac2) Fac = Fac1 < Fac2; else if(type == NODE_MATH_GREATER_THAN) Fac = Fac1 > Fac2; + else if(type == NODE_MATH_MODULO) + Fac = safe_modulo(Fac1, Fac2); else if(type == NODE_MATH_CLAMP) Fac = clamp(Fac1, 0.0f, 1.0f); else diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index d89fde898dc..2cf3ccbe575 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -210,6 +210,7 @@ typedef enum NodeMath { NODE_MATH_ROUND, NODE_MATH_LESS_THAN, NODE_MATH_GREATER_THAN, + NODE_MATH_MODULO, NODE_MATH_CLAMP /* used for the clamp UI option */ } NodeMath; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 7435616ffc0..06322fec820 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2959,6 +2959,7 @@ static ShaderEnum math_type_init() enm.insert("Round", NODE_MATH_ROUND); enm.insert("Less Than", NODE_MATH_LESS_THAN); enm.insert("Greater Than", NODE_MATH_GREATER_THAN); + enm.insert("Modulo", NODE_MATH_MODULO); return enm; } diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 6edf7fa3544..6fe1b2bcf54 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -1166,6 +1166,11 @@ __device float safe_divide(float a, float b) return (b != 0.0f)? a/b: 0.0f; } +__device float safe_modulo(float a, float b) +{ + return (b != 0.0f)? fmodf(a, b): 0.0f; +} + /* Ray Intersection */ __device bool ray_sphere_intersect( diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp index 307590b977b..23e9a9d623d 100644 --- a/source/blender/compositor/nodes/COM_MathNode.cpp +++ b/source/blender/compositor/nodes/COM_MathNode.cpp @@ -80,6 +80,9 @@ void MathNode::convertToOperations(ExecutionSystem *graph, CompositorContext *co case 16: /* Greater Than */ operation = new MathGreaterThanOperation(); break; + case 17: /* Modulo */ + operation = new MathModuloOperation(); + break; } if (operation != NULL) { diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp index 7039689aa5f..3749bcf42d8 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp @@ -317,4 +317,19 @@ void MathGreaterThanOperation::executePixel(float output[4], float x, float y, P clampIfNeeded(output); } +void MathModuloOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->read(&inputValue1[0], x, y, sampler); + this->m_inputValue2Operation->read(&inputValue2[0], x, y, sampler); + + if (inputValue2[0] == 0) + output[0] = 0.0; + else + output[0] = fmod(inputValue1[0], inputValue2[0]); + + clampIfNeeded(output); +} diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h index febfa9662c6..649a9688037 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.h +++ b/source/blender/compositor/operations/COM_MathBaseOperation.h @@ -157,4 +157,10 @@ public: void executePixel(float output[4], float x, float y, PixelSampler sampler); }; +class MathModuloOperation : public MathBaseOperation { +public: + MathModuloOperation() : MathBaseOperation() {} + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + #endif diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index fd519a86fc9..3a68b79d154 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -279,6 +279,14 @@ void math_greater_than(float val1, float val2, out float outval) outval = 0.0; } +void math_modulo(float val1, float val2, out float outval) +{ + if (val2 == 0.0) + outval = 0.0; + else + outval = mod(val1, val2); +} + void squeeze(float val, float width, float center, out float outval) { outval = 1.0/(1.0 + pow(2.71828183, -((val-center)*width))); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 6238e3f7d3d..a40d85ae954 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -127,6 +127,7 @@ EnumPropertyItem node_math_items[] = { {14, "ROUND", 0, "Round", ""}, {15, "LESS_THAN", 0, "Less Than", ""}, {16, "GREATER_THAN", 0, "Greater Than", ""}, + {17, "MODULO", 0, "Modulo", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c index c3e2fc54c78..bef777e5d59 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.c +++ b/source/blender/nodes/shader/nodes/node_shader_math.c @@ -203,6 +203,14 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode out[0]->vec[0] = 0.0f; } break; + case 17: /* Modulo */ + { + if (in[1]->vec[0] == 0.0f) + out[0]->vec[0] = 0.0f; + else + out[0]->vec[0] = fmod(in[0]->vec[0], in[1]->vec[0]); + } + break; } } @@ -211,7 +219,7 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( static const char *names[] = {"math_add", "math_subtract", "math_multiply", "math_divide", "math_sine", "math_cosine", "math_tangent", "math_asin", "math_acos", "math_atan", "math_pow", "math_log", "math_min", "math_max", - "math_round", "math_less_than", "math_greater_than"}; + "math_round", "math_less_than", "math_greater_than", "math_modulo"}; switch (node->custom1) { case 0: diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c index 03349a57832..1e456416159 100644 --- a/source/blender/nodes/texture/nodes/node_texture_math.c +++ b/source/blender/nodes/texture/nodes/node_texture_math.c @@ -174,6 +174,15 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor } break; + case 17: /* Modulo */ + { + if (in1 == 0.0f) + *out = 0.0f; + else + *out= fmod(in0, in1); + } + break; + default: fprintf(stderr, "%s:%d: unhandeld value in switch statement: %d\n",