diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl index c5fcbc311d3..aa9f6e671c3 100644 --- a/intern/cycles/kernel/shaders/node_math.osl +++ b/intern/cycles/kernel/shaders/node_math.osl @@ -40,6 +40,18 @@ float safe_modulo(float a, float b) return result; } +float safe_sqrt(float a) +{ + float result; + + if (a > 0.0) + result = sqrt(a); + else + result = 0.0; + + return result; +} + float safe_log(float a, float b) { if (a < 0.0 || b < 0.0) @@ -97,6 +109,14 @@ shader node_math( Value = fabs(Value1); else if (type == "arctan2") Value = atan2(Value1, Value2); + else if (type == "floor") + Value = floor(Value1); + else if (type == "ceil") + Value = ceil(Value1); + else if (type == "fract") + Value = Value1 - floor(Value1); + else if (type == "sqrt") + Value = safe_sqrt(Value1); if (use_clamp) Value = clamp(Value, 0.0, 1.0); diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h index 04864bd610a..d3490ab284f 100644 --- a/intern/cycles/kernel/svm/svm_math_util.h +++ b/intern/cycles/kernel/svm/svm_math_util.h @@ -94,6 +94,14 @@ ccl_device float svm_math(NodeMath type, float Fac1, float Fac2) Fac = fabsf(Fac1); else if(type == NODE_MATH_ARCTAN2) Fac = atan2f(Fac1, Fac2); + else if (type == NODE_MATH_FLOOR) + Fac = floorf(Fac1); + else if (type == NODE_MATH_CEIL) + Fac = ceilf(Fac1); + else if (type == NODE_MATH_FRACT) + Fac = Fac1 - floorf(Fac1); + else if (type == NODE_MATH_SQRT) + Fac = safe_sqrtf(Fac1); else if(type == NODE_MATH_CLAMP) Fac = saturate(Fac1); else diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index b94a83b6712..0fde5126434 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -261,6 +261,10 @@ typedef enum NodeMath { NODE_MATH_MODULO, NODE_MATH_ABSOLUTE, NODE_MATH_ARCTAN2, + NODE_MATH_FLOOR, + NODE_MATH_CEIL, + NODE_MATH_FRACT, + NODE_MATH_SQRT, 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 7e40b99abdd..868217f595b 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -5068,6 +5068,10 @@ NODE_DEFINE(MathNode) type_enum.insert("modulo", NODE_MATH_MODULO); type_enum.insert("absolute", NODE_MATH_ABSOLUTE); type_enum.insert("arctan2", NODE_MATH_ARCTAN2); + type_enum.insert("floor", NODE_MATH_FLOOR); + type_enum.insert("ceil", NODE_MATH_CEIL); + type_enum.insert("fract", NODE_MATH_FRACT); + type_enum.insert("sqrt", NODE_MATH_SQRT); SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD); SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp index d16300ebff4..25c617a3487 100644 --- a/source/blender/compositor/nodes/COM_MathNode.cpp +++ b/source/blender/compositor/nodes/COM_MathNode.cpp @@ -89,6 +89,18 @@ void MathNode::convertToOperations(NodeConverter &converter, const CompositorCon case NODE_MATH_ATAN2: operation = new MathArcTan2Operation(); break; + case NODE_MATH_FLOOR: + operation = new MathFloorOperation(); + break; + case NODE_MATH_CEIL: + operation = new MathCeilOperation(); + break; + case NODE_MATH_FRACT: + operation = new MathFractOperation(); + break; + case NODE_MATH_SQRT: + operation = new MathSqrtOperation(); + break; } if (operation) { diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp index 0a515da1877..99385a5073a 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp @@ -356,3 +356,50 @@ void MathArcTan2Operation::executePixelSampled(float output[4], float x, float y clampIfNeeded(output); } + +void MathFloorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = floor(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathCeilOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = ceil(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathFractOperation::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] - floor(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathSqrtOperation::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] = sqrt(inputValue1[0]); + else + output[0] = 0.0f; + + clampIfNeeded(output); +} diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h index c636117451f..5435cc82ba7 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.h +++ b/source/blender/compositor/operations/COM_MathBaseOperation.h @@ -175,4 +175,28 @@ public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); }; +class MathFloorOperation : public MathBaseOperation { +public: + MathFloorOperation() : MathBaseOperation() {} + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathCeilOperation : public MathBaseOperation { +public: + MathCeilOperation() : MathBaseOperation() {} + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathFractOperation : public MathBaseOperation { +public: + MathFractOperation() : MathBaseOperation() {} + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); +}; + +class MathSqrtOperation : public MathBaseOperation { +public: + MathSqrtOperation() : MathBaseOperation() {} + void executePixelSampled(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 2496170db3f..3890d7b52cf 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -389,6 +389,29 @@ void math_atan2(float val1, float val2, out float outval) outval = atan(val1, val2); } +void math_floor(float val, out float outval) +{ + outval = floor(val); +} + +void math_ceil(float val, out float outval) +{ + outval = ceil(val); +} + +void math_fract(float val, out float outval) +{ + outval = val - floor(val); +} + +void math_sqrt(float val, out float outval) +{ + if (val > 0.0) + outval = sqrt(val); + else + outval = 0.0; +} + 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/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 90c9d81e996..d5cb32c90d9 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1071,6 +1071,10 @@ enum { NODE_MATH_MOD = 17, NODE_MATH_ABS = 18, NODE_MATH_ATAN2 = 19, + NODE_MATH_FLOOR = 20, + NODE_MATH_CEIL = 21, + NODE_MATH_FRACT = 22, + NODE_MATH_SQRT = 23, }; /* mix rgb node flags */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 89ca6b52c75..ebae066db1c 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -144,6 +144,10 @@ const EnumPropertyItem rna_enum_node_math_items[] = { {NODE_MATH_MOD, "MODULO", 0, "Modulo", ""}, {NODE_MATH_ABS, "ABSOLUTE", 0, "Absolute", ""}, {NODE_MATH_ATAN2, "ARCTAN2", 0, "Arctan2", ""}, + {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", ""}, + {NODE_MATH_CEIL, "CEIL", 0, "Ceil", ""}, + {NODE_MATH_FRACT, "FRACT", 0, "Fract", ""}, + {NODE_MATH_SQRT, "SQRT", 0, "Square Root", ""}, {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 e3c52a9bc03..1b702a722ba 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.c +++ b/source/blender/nodes/shader/nodes/node_shader_math.c @@ -226,6 +226,46 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode r = atan2(a, b); break; } + case NODE_MATH_FLOOR: + { + if (in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ + r = floorf(a); + else + r = floorf(b); + break; + } + case NODE_MATH_CEIL: + { + if (in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ + r = ceilf(a); + else + r = ceilf(b); + break; + } + case NODE_MATH_FRACT: + { + if (in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */ + r = a - floorf(a); + else + r = b - floorf(b); + break; + } + case NODE_MATH_SQRT: + { + if (in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */ + if (a > 0) + r = sqrt(a); + else + r = 0.0; + } + else { + if (b > 0) + r = sqrt(b); + else + r = 0.0; + } + break; + } } if (node->custom2 & SHD_MATH_CLAMP) { CLAMP(r, 0.0f, 1.0f); @@ -240,7 +280,7 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( "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_modulo", "math_abs", - "math_atan2" + "math_atan2", "math_floor", "math_ceil", "math_fract", "math_sqrt" }; switch (node->custom1) { @@ -266,6 +306,10 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( case NODE_MATH_ATAN: case NODE_MATH_ROUND: case NODE_MATH_ABS: + case NODE_MATH_FLOOR: + case NODE_MATH_FRACT: + case NODE_MATH_CEIL: + case NODE_MATH_SQRT: if (in[0].hasinput || !in[1].hasinput) { /* use only first item and terminator */ GPUNodeStack tmp_in[2]; diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c index d8dc2a62625..f786a293080 100644 --- a/source/blender/nodes/texture/nodes/node_texture_math.c +++ b/source/blender/nodes/texture/nodes/node_texture_math.c @@ -195,6 +195,33 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor break; } + case NODE_MATH_FLOOR: + { + *out = floorf(in0); + break; + } + + case NODE_MATH_CEIL: + { + *out = ceilf(in0); + break; + } + + case NODE_MATH_FRACT: + { + *out = in0 - floorf(in0); + break; + } + + case NODE_MATH_SQRT: + { + if (in0 > 0.0f) + *out = sqrtf(in0); + else + *out = 0.0f; + break; + } + default: { BLI_assert(0);