mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Shader Nodes: support Integer Math node in EEVEE and Cycles
This adds the Integer Math node to shader nodes. It's the same node that can already be used in Geometry Nodes and the Compositor. While creating the regression test, I noticed that the integer math implementation was a bit broken: * The integer modulo (`%`) operator on the GPU is undefined for negative divisors (the added regression test showed that the behavior is not consistent across platforms). * Use integer power function instead of using float implementation with casts. The MaterialX implementation is omitted for now. I didn't look into it in detail yet but for the Boolean Math node (#162798) it seemed like some more work is needed there to support this type. Pull Request: https://projects.blender.org/blender/blender/pulls/163805
This commit is contained in:
parent
fe998a1cd9
commit
ba82476ade
19 changed files with 389 additions and 7 deletions
|
|
@ -549,6 +549,11 @@ static ShaderNode *add_node(Scene *scene,
|
|||
boolean_math_node->set_math_type((NodeBooleanMathType)b_node.custom1);
|
||||
node = boolean_math_node;
|
||||
}
|
||||
else if (b_node.is_type("FunctionNodeIntegerMath"_ustr)) {
|
||||
IntegerMathNode *integer_math_node = graph->create_node<IntegerMathNode>();
|
||||
integer_math_node->set_math_type((NodeIntegerMathType)b_node.custom1);
|
||||
node = integer_math_node;
|
||||
}
|
||||
else if (b_node.is_type("ShaderNodeVectorMath"_ustr)) {
|
||||
VectorMathNode *vector_math_node = graph->create_node<VectorMathNode>();
|
||||
vector_math_node->set_math_type((NodeVectorMathType)b_node.custom1);
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ set(SRC_KERNEL_SVM_HEADERS
|
|||
svm/mapping_util.h
|
||||
svm/math.h
|
||||
svm/math_util.h
|
||||
svm/integer_math.h
|
||||
svm/mix.h
|
||||
svm/node_types.h
|
||||
svm/node_types_template.h
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ set(SRC_OSL
|
|||
node_map_range.osl
|
||||
node_mapping.osl
|
||||
node_math.osl
|
||||
node_integer_math.osl
|
||||
node_metallic_bsdf.osl
|
||||
node_mix.osl
|
||||
node_mix_closure.osl
|
||||
|
|
|
|||
96
intern/cycles/kernel/osl/shaders/node_integer_math.osl
Normal file
96
intern/cycles/kernel/osl/shaders/node_integer_math.osl
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/* SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "stdcycles.h"
|
||||
|
||||
int integer_math_divide_floor(int a, int b)
|
||||
{
|
||||
int d = a / b;
|
||||
int r = a % b;
|
||||
return (r != 0) ? (d - int((a < 0) != (b < 0))) : d;
|
||||
}
|
||||
|
||||
int integer_math_gcd(int a_in, int b_in)
|
||||
{
|
||||
int a = abs(a_in);
|
||||
int b = abs(b_in);
|
||||
while (b != 0) {
|
||||
int t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
int integer_math_power(int base_in, int exponent_in)
|
||||
{
|
||||
int base = base_in;
|
||||
int exponent = exponent_in;
|
||||
if (exponent < 0) {
|
||||
if (base == 1 || base == -1) {
|
||||
return (base < 0 && (exponent & 1) != 0) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int result = 1;
|
||||
while (exponent != 0) {
|
||||
if ((exponent & 1) != 0) {
|
||||
result *= base;
|
||||
}
|
||||
exponent = exponent >> 1;
|
||||
base = base * base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
shader node_integer_math(
|
||||
string math_type = "add", int Value1 = 0, int Value2 = 0, int Value3 = 0, output int Value = 0)
|
||||
{
|
||||
if (math_type == "add")
|
||||
Value = Value1 + Value2;
|
||||
else if (math_type == "subtract")
|
||||
Value = Value1 - Value2;
|
||||
else if (math_type == "multiply")
|
||||
Value = Value1 * Value2;
|
||||
else if (math_type == "divide")
|
||||
Value = (Value2 != 0) ? (Value1 / Value2) : 0;
|
||||
else if (math_type == "multiply_add")
|
||||
Value = Value1 * Value2 + Value3;
|
||||
else if (math_type == "power")
|
||||
Value = integer_math_power(Value1, Value2);
|
||||
else if (math_type == "floored_modulo")
|
||||
Value = (Value2 != 0) ? (((Value1 % Value2) + Value2) % Value2) : 0;
|
||||
else if (math_type == "absolute")
|
||||
Value = abs(Value1);
|
||||
else if (math_type == "minimum")
|
||||
Value = min(Value1, Value2);
|
||||
else if (math_type == "maximum")
|
||||
Value = max(Value1, Value2);
|
||||
else if (math_type == "gcd")
|
||||
Value = integer_math_gcd(Value1, Value2);
|
||||
else if (math_type == "lcm") {
|
||||
int gcd = integer_math_gcd(Value1, Value2);
|
||||
Value = (gcd != 0) ? abs(Value1 / gcd * Value2) : 0;
|
||||
}
|
||||
else if (math_type == "negate")
|
||||
Value = -Value1;
|
||||
else if (math_type == "sign")
|
||||
Value = int(0 < Value1) - int(Value1 < 0);
|
||||
else if (math_type == "divide_floor")
|
||||
Value = (Value2 != 0) ? integer_math_divide_floor(Value1, Value2) : 0;
|
||||
else if (math_type == "divide_ceil")
|
||||
Value = (Value2 != 0) ? -integer_math_divide_floor(Value1, -Value2) : 0;
|
||||
else if (math_type == "divide_round") {
|
||||
int abs_b = abs(Value2);
|
||||
int sign_b = int(0 < Value2) - int(Value2 < 0);
|
||||
if (Value1 >= 0)
|
||||
Value = ((abs_b != 0) ? ((2 * Value1 + abs_b) / (2 * abs_b)) : 0) * sign_b;
|
||||
else
|
||||
Value = -((abs_b != 0) ? ((2 * -Value1 + abs_b) / (2 * abs_b)) : 0) * sign_b;
|
||||
}
|
||||
else if (math_type == "modulo")
|
||||
Value = (Value2 != 0) ? (Value1 % Value2) : 0;
|
||||
else
|
||||
Value = 0;
|
||||
}
|
||||
118
intern/cycles/kernel/svm/integer_math.h
Normal file
118
intern/cycles/kernel/svm/integer_math.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/* SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device int svm_integer_math_divide_floor(const int a, const int b)
|
||||
{
|
||||
const int d = a / b;
|
||||
const int r = a % b;
|
||||
return (r != 0) ? (d - int((a < 0) != (b < 0))) : d;
|
||||
}
|
||||
|
||||
ccl_device int svm_integer_math_gcd(int a, int b)
|
||||
{
|
||||
a = abs(a);
|
||||
b = abs(b);
|
||||
while (b != 0) {
|
||||
const int t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
ccl_device int svm_integer_math_power(int base, int exponent)
|
||||
{
|
||||
if (exponent < 0) {
|
||||
if (base == 1 || base == -1) {
|
||||
return (base < 0 && (exponent & 1) != 0) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int result = 1;
|
||||
while (exponent != 0) {
|
||||
if ((exponent & 1) != 0) {
|
||||
result *= base;
|
||||
}
|
||||
exponent >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ccl_device int svm_integer_math(const NodeIntegerMathType type,
|
||||
const int a,
|
||||
const int b,
|
||||
const int c)
|
||||
{
|
||||
switch (type) {
|
||||
case NODE_INTEGER_MATH_ADD:
|
||||
return a + b;
|
||||
case NODE_INTEGER_MATH_SUBTRACT:
|
||||
return a - b;
|
||||
case NODE_INTEGER_MATH_MULTIPLY:
|
||||
return a * b;
|
||||
case NODE_INTEGER_MATH_DIVIDE:
|
||||
return (b != 0) ? (a / b) : 0;
|
||||
case NODE_INTEGER_MATH_MULTIPLY_ADD:
|
||||
return a * b + c;
|
||||
case NODE_INTEGER_MATH_POWER:
|
||||
return svm_integer_math_power(a, b);
|
||||
case NODE_INTEGER_MATH_FLOORED_MODULO:
|
||||
return (b != 0) ? (((a % b) + b) % b) : 0;
|
||||
case NODE_INTEGER_MATH_ABSOLUTE:
|
||||
return abs(a);
|
||||
case NODE_INTEGER_MATH_MINIMUM:
|
||||
return min(a, b);
|
||||
case NODE_INTEGER_MATH_MAXIMUM:
|
||||
return max(a, b);
|
||||
case NODE_INTEGER_MATH_GCD:
|
||||
return svm_integer_math_gcd(a, b);
|
||||
case NODE_INTEGER_MATH_LCM: {
|
||||
const int gcd = svm_integer_math_gcd(a, b);
|
||||
return (gcd != 0) ? abs(a / gcd * b) : 0;
|
||||
}
|
||||
case NODE_INTEGER_MATH_NEGATE:
|
||||
return -a;
|
||||
case NODE_INTEGER_MATH_SIGN:
|
||||
return int(0 < a) - int(a < 0);
|
||||
case NODE_INTEGER_MATH_DIVIDE_FLOOR:
|
||||
return (b != 0) ? svm_integer_math_divide_floor(a, b) : 0;
|
||||
case NODE_INTEGER_MATH_DIVIDE_CEIL:
|
||||
return (b != 0) ? -svm_integer_math_divide_floor(a, -b) : 0;
|
||||
case NODE_INTEGER_MATH_DIVIDE_ROUND: {
|
||||
const int abs_b = abs(b);
|
||||
const int sign_b = int(0 < b) - int(b < 0);
|
||||
if (a >= 0) {
|
||||
return ((abs_b != 0) ? ((2 * a + abs_b) / (2 * abs_b)) : 0) * sign_b;
|
||||
}
|
||||
return -((abs_b != 0) ? ((2 * -a + abs_b) / (2 * abs_b)) : 0) * sign_b;
|
||||
}
|
||||
case NODE_INTEGER_MATH_MODULO:
|
||||
return (b != 0) ? (a % b) : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_integer_math(
|
||||
ccl_private float *ccl_restrict stack, const ccl_global SVMNodeIntegerMath &ccl_restrict node)
|
||||
{
|
||||
const int a = stack_load(stack, node.value1);
|
||||
const int b = stack_load(stack, node.value2);
|
||||
const int c = stack_load(stack, node.value3);
|
||||
const int result = svm_integer_math(node.math_type, a, b, c);
|
||||
|
||||
if (stack_valid(node.result_offset)) {
|
||||
stack_store_int(stack, node.result_offset, result);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
@ -71,6 +71,18 @@ struct SVMNodeBooleanMath {
|
|||
static_assert(alignof(SVMNodeBooleanMath) <= alignof(uint));
|
||||
static_assert(sizeof(SVMNodeBooleanMath) % sizeof(uint) == 0);
|
||||
|
||||
/* NODE_INTEGER_MATH */
|
||||
struct SVMNodeIntegerMath {
|
||||
NodeIntegerMathType math_type;
|
||||
SVMInputInt value1;
|
||||
SVMInputInt value2;
|
||||
SVMInputInt value3;
|
||||
SVMStackOffset result_offset;
|
||||
uint8_t _pad[3];
|
||||
};
|
||||
static_assert(alignof(SVMNodeIntegerMath) <= alignof(uint));
|
||||
static_assert(sizeof(SVMNodeIntegerMath) % sizeof(uint) == 0);
|
||||
|
||||
/* NODE_CLAMP */
|
||||
struct SVMNodeClamp {
|
||||
NodeClampType clamp_type;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ SHADER_NODE_TYPE(NODE_VOLUME_COEFFICIENTS)
|
|||
SHADER_NODE_TYPE(NODE_PRINCIPLED_VOLUME)
|
||||
SHADER_NODE_TYPE(NODE_MATH)
|
||||
SHADER_NODE_TYPE(NODE_BOOLEAN_MATH)
|
||||
SHADER_NODE_TYPE(NODE_INTEGER_MATH)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_VECTOR_MATH)
|
||||
SHADER_NODE_TYPE(NODE_RGB_RAMP)
|
||||
SHADER_NODE_TYPE(NODE_GAMMA)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
#include "kernel/svm/hsv.h"
|
||||
#include "kernel/svm/ies.h"
|
||||
#include "kernel/svm/image.h"
|
||||
#include "kernel/svm/integer_math.h"
|
||||
#include "kernel/svm/invert.h"
|
||||
#include "kernel/svm/light_path.h"
|
||||
#include "kernel/svm/magic.h"
|
||||
|
|
@ -369,6 +370,9 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
|
|||
SVM_CASE(NODE_BOOLEAN_MATH)
|
||||
svm_node_boolean_math(stack, svm_node_get<SVMNodeBooleanMath>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_INTEGER_MATH)
|
||||
svm_node_integer_math(stack, svm_node_get<SVMNodeIntegerMath>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VECTOR_MATH)
|
||||
svm_node_vector_math<float3>(stack, svm_node_get<SVMNodeVectorMath>(kg, &offset));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -233,6 +233,27 @@ enum NodeBooleanMathType : uint {
|
|||
NODE_BOOLEAN_MATH_NIMPLY,
|
||||
};
|
||||
|
||||
enum NodeIntegerMathType : uint {
|
||||
NODE_INTEGER_MATH_ADD,
|
||||
NODE_INTEGER_MATH_SUBTRACT,
|
||||
NODE_INTEGER_MATH_MULTIPLY,
|
||||
NODE_INTEGER_MATH_DIVIDE,
|
||||
NODE_INTEGER_MATH_MULTIPLY_ADD,
|
||||
NODE_INTEGER_MATH_POWER,
|
||||
NODE_INTEGER_MATH_FLOORED_MODULO,
|
||||
NODE_INTEGER_MATH_ABSOLUTE,
|
||||
NODE_INTEGER_MATH_MINIMUM,
|
||||
NODE_INTEGER_MATH_MAXIMUM,
|
||||
NODE_INTEGER_MATH_GCD,
|
||||
NODE_INTEGER_MATH_LCM,
|
||||
NODE_INTEGER_MATH_NEGATE,
|
||||
NODE_INTEGER_MATH_SIGN,
|
||||
NODE_INTEGER_MATH_DIVIDE_FLOOR,
|
||||
NODE_INTEGER_MATH_DIVIDE_CEIL,
|
||||
NODE_INTEGER_MATH_DIVIDE_ROUND,
|
||||
NODE_INTEGER_MATH_MODULO,
|
||||
};
|
||||
|
||||
enum NodeVectorMathType : uint {
|
||||
NODE_VECTOR_MATH_ADD,
|
||||
NODE_VECTOR_MATH_SUBTRACT,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "kernel/closure/bsdf_microfacet.h"
|
||||
#include "kernel/svm/boolean_math.h"
|
||||
#include "kernel/svm/color_util.h"
|
||||
#include "kernel/svm/integer_math.h"
|
||||
#include "kernel/svm/mapping_util.h"
|
||||
#include "kernel/svm/math_util.h"
|
||||
#include "kernel/svm/ramp_util.h"
|
||||
|
|
@ -7092,6 +7093,70 @@ void BooleanMathNode::compile(OSLCompiler &compiler)
|
|||
compiler.add(this, "node_boolean_math");
|
||||
}
|
||||
|
||||
/* Integer Math */
|
||||
|
||||
NODE_DEFINE(IntegerMathNode)
|
||||
{
|
||||
NodeType *type = NodeType::add("integer_math", create, NodeType::SHADER);
|
||||
|
||||
static NodeEnum type_enum;
|
||||
type_enum.insert("add", NODE_INTEGER_MATH_ADD);
|
||||
type_enum.insert("subtract", NODE_INTEGER_MATH_SUBTRACT);
|
||||
type_enum.insert("multiply", NODE_INTEGER_MATH_MULTIPLY);
|
||||
type_enum.insert("divide", NODE_INTEGER_MATH_DIVIDE);
|
||||
type_enum.insert("multiply_add", NODE_INTEGER_MATH_MULTIPLY_ADD);
|
||||
type_enum.insert("power", NODE_INTEGER_MATH_POWER);
|
||||
type_enum.insert("floored_modulo", NODE_INTEGER_MATH_FLOORED_MODULO);
|
||||
type_enum.insert("absolute", NODE_INTEGER_MATH_ABSOLUTE);
|
||||
type_enum.insert("minimum", NODE_INTEGER_MATH_MINIMUM);
|
||||
type_enum.insert("maximum", NODE_INTEGER_MATH_MAXIMUM);
|
||||
type_enum.insert("gcd", NODE_INTEGER_MATH_GCD);
|
||||
type_enum.insert("lcm", NODE_INTEGER_MATH_LCM);
|
||||
type_enum.insert("negate", NODE_INTEGER_MATH_NEGATE);
|
||||
type_enum.insert("sign", NODE_INTEGER_MATH_SIGN);
|
||||
type_enum.insert("divide_floor", NODE_INTEGER_MATH_DIVIDE_FLOOR);
|
||||
type_enum.insert("divide_ceil", NODE_INTEGER_MATH_DIVIDE_CEIL);
|
||||
type_enum.insert("divide_round", NODE_INTEGER_MATH_DIVIDE_ROUND);
|
||||
type_enum.insert("modulo", NODE_INTEGER_MATH_MODULO);
|
||||
SOCKET_ENUM(math_type, "Type", type_enum, NODE_INTEGER_MATH_ADD);
|
||||
|
||||
SOCKET_IN_INT(value1, "Value1", 0);
|
||||
SOCKET_IN_INT(value2, "Value2", 0);
|
||||
SOCKET_IN_INT(value3, "Value3", 0);
|
||||
|
||||
SOCKET_OUT_INT(value, "Value");
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
IntegerMathNode::IntegerMathNode() : ShaderNode(get_node_type()) {}
|
||||
|
||||
void IntegerMathNode::constant_fold(const ConstantFolder &folder)
|
||||
{
|
||||
if (folder.all_inputs_constant()) {
|
||||
folder.make_constant(svm_integer_math(math_type, value1, value2, value3));
|
||||
}
|
||||
}
|
||||
|
||||
void IntegerMathNode::compile(SVMCompiler &compiler)
|
||||
{
|
||||
compiler.add_node(this,
|
||||
NODE_INTEGER_MATH,
|
||||
SVMNodeIntegerMath{
|
||||
.math_type = math_type,
|
||||
.value1 = compiler.input_int("Value1"),
|
||||
.value2 = compiler.input_int("Value2"),
|
||||
.value3 = compiler.input_int("Value3"),
|
||||
.result_offset = compiler.output("Value"),
|
||||
});
|
||||
}
|
||||
|
||||
void IntegerMathNode::compile(OSLCompiler &compiler)
|
||||
{
|
||||
compiler.parameter(this, "math_type");
|
||||
compiler.add(this, "node_integer_math");
|
||||
}
|
||||
|
||||
/* VectorMath */
|
||||
|
||||
NODE_DEFINE(VectorMathNode)
|
||||
|
|
|
|||
|
|
@ -1559,6 +1559,17 @@ class BooleanMathNode : public ShaderNode {
|
|||
NODE_SOCKET_API(NodeBooleanMathType, math_type)
|
||||
};
|
||||
|
||||
class IntegerMathNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(IntegerMathNode)
|
||||
void constant_fold(const ConstantFolder &folder) override;
|
||||
|
||||
NODE_SOCKET_API(int, value1)
|
||||
NODE_SOCKET_API(int, value2)
|
||||
NODE_SOCKET_API(int, value3)
|
||||
NODE_SOCKET_API(NodeIntegerMathType, math_type)
|
||||
};
|
||||
|
||||
class NormalNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(NormalNode)
|
||||
|
|
|
|||
|
|
@ -452,6 +452,12 @@ class NODE_MT_shader_node_math_base(node_add_menu.NodeMenu):
|
|||
self.node_operator(layout, "ShaderNodeClamp")
|
||||
self.node_operator(layout, "ShaderNodeFloatCurve")
|
||||
self.node_operator(layout, "ShaderNodeMapRange")
|
||||
self.node_operator_with_searchable_enum(
|
||||
context,
|
||||
layout,
|
||||
"FunctionNodeIntegerMath",
|
||||
"operation",
|
||||
defaults_callback=node_add_menu.set_int_math_node_default_props)
|
||||
self.node_operator_with_searchable_enum(
|
||||
context,
|
||||
layout,
|
||||
|
|
|
|||
|
|
@ -555,7 +555,17 @@ static void register_common_functions_impl()
|
|||
});
|
||||
registry::add_new_cb([] {
|
||||
return mf::build::SI2_SO<int, int, int>(
|
||||
"int ** int", [](int a, int b) { return math::pow(a, b); }, exec_fast);
|
||||
"int ** int",
|
||||
[](int base, int exponent) {
|
||||
if (exponent < 0) {
|
||||
if (base == 1 || base == -1) {
|
||||
return (base < 0 && (exponent & 1) != 0) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return pow_i(base, exponent);
|
||||
},
|
||||
exec_fast);
|
||||
});
|
||||
registry::add_new_cb([] {
|
||||
return mf::build::SI3_SO<int, int, int, int>(
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@
|
|||
int divide_floor(int a, int b)
|
||||
{
|
||||
int d = a / b;
|
||||
int r = a % b;
|
||||
return (r != 0) ? (d - int((a < 0) != (b < 0))) : d;
|
||||
return (a != d * b) ? (d - int((a < 0) != (b < 0))) : d;
|
||||
}
|
||||
|
||||
int euclid_gcd(int a, int b)
|
||||
|
|
@ -55,16 +54,35 @@ void integer_math_multiply_add(int a, int b, int c, int &result)
|
|||
result = a * b + c;
|
||||
}
|
||||
|
||||
int integer_power(int base, int exponent)
|
||||
{
|
||||
if (exponent < 0) {
|
||||
if (base == 1 || base == -1) {
|
||||
return (base < 0 && (exponent & 1) != 0) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int result = 1;
|
||||
while (exponent != 0) {
|
||||
if ((exponent & 1) != 0) {
|
||||
result *= base;
|
||||
}
|
||||
exponent >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[node]]
|
||||
void integer_math_power(int base, int exponent, int /*c*/, int &result)
|
||||
{
|
||||
result = int(pow(float(base), float(exponent)));
|
||||
result = integer_power(base, exponent);
|
||||
}
|
||||
|
||||
[[node]]
|
||||
void integer_math_floored_modulo(int a, int b, int /*c*/, int &result)
|
||||
{
|
||||
result = (b != 0) ? (((a % b) + b) % b) : 0;
|
||||
result = (b != 0) ? (a - divide_floor(a, b) * b) : 0;
|
||||
}
|
||||
|
||||
[[node]]
|
||||
|
|
@ -138,5 +156,6 @@ void integer_math_divide_round(int a, int b, int /*c*/, int &result)
|
|||
[[node]]
|
||||
void integer_math_modulo(int a, int b, int /*c*/, int &result)
|
||||
{
|
||||
result = (b != 0) ? (a % b) : 0;
|
||||
/* Can't use `%` as it is undefined for negative b on the GPU.*/
|
||||
result = (b != 0) ? a - (a / b) * b : 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ static void node_register()
|
|||
{
|
||||
static bke::bNodeType ntype;
|
||||
|
||||
fn_cmp_node_type_base(&ntype, "FunctionNodeIntegerMath"_ustr, FN_NODE_INTEGER_MATH);
|
||||
common_node_type_base(&ntype, "FunctionNodeIntegerMath"_ustr, FN_NODE_INTEGER_MATH);
|
||||
ntype.ui_name = "Integer Math";
|
||||
ntype.ui_description = "Perform various math operations on the given integer inputs";
|
||||
ntype.enum_name_legacy = "INTEGER_MATH";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0cfc2bb10378e7ca9907e504d5f72d606a0740cbd134b36f6ba943c4aa09f33e
|
||||
size 13588
|
||||
3
tests/files/render/shader/eevee_renders/integer_math.png
Normal file
3
tests/files/render/shader/eevee_renders/integer_math.png
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1018a56d697b1eff3ec26e56f7fcfcb74478cda9bb0e35ff21622c925dc005f7
|
||||
size 4724
|
||||
3
tests/files/render/shader/integer_math.blend
Normal file
3
tests/files/render/shader/integer_math.blend
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0611d15d780dc6f429d534de5c02d53222108cf80f28e8f32878c6f0bca79174
|
||||
size 1274148
|
||||
3
tests/files/render/shader/storm_renders/integer_math.png
Normal file
3
tests/files/render/shader/storm_renders/integer_math.png
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:71cdc833ad0d243e05666bb3b50d81a2165a674690907e3494ab75d7eb4b4cff
|
||||
size 1589
|
||||
Loading…
Add table
Add a link
Reference in a new issue