mirror of
https://github.com/blender/blender
synced 2026-10-25 03:07:01 +03:00
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
96 lines
2.7 KiB
Text
96 lines
2.7 KiB
Text
/* 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;
|
|
}
|