Shading: Refactor Math node and use dynamic inputs.
- Implement dynamic inputs. The second input is now unavailable in single operand math operators. - Reimplemenet the clamp option using graph expansion for Cycles. - Clean up code and unify naming between Blender and Cycles. - Remove unused code. Reviewers: brecht Differential Revision: https://developer.blender.org/D5481
This commit is contained in:
parent
e12c17b305
commit
e5618725fd
|
@ -326,10 +326,10 @@ static ShaderNode *add_node(Scene *scene,
|
|||
}
|
||||
else if (b_node.is_a(&RNA_ShaderNodeMath)) {
|
||||
BL::ShaderNodeMath b_math_node(b_node);
|
||||
MathNode *math = new MathNode();
|
||||
math->type = (NodeMath)b_math_node.operation();
|
||||
math->use_clamp = b_math_node.use_clamp();
|
||||
node = math;
|
||||
MathNode *math_node = new MathNode();
|
||||
math_node->type = (NodeMathType)b_math_node.operation();
|
||||
math_node->use_clamp = b_math_node.use_clamp();
|
||||
node = math_node;
|
||||
}
|
||||
else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
|
||||
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
|
||||
|
|
|
@ -17,57 +17,31 @@
|
|||
#include "stdosl.h"
|
||||
|
||||
float safe_divide(float a, float b)
|
||||
{
|
||||
float result;
|
||||
|
||||
if (b == 0.0)
|
||||
result = 0.0;
|
||||
else
|
||||
result = a / b;
|
||||
|
||||
return result;
|
||||
{
|
||||
return (b != 0.0) ? a / b : 0.0;
|
||||
}
|
||||
|
||||
float safe_modulo(float a, float b)
|
||||
{
|
||||
float result;
|
||||
|
||||
if (b == 0.0)
|
||||
result = 0.0;
|
||||
else
|
||||
result = fmod(a, b);
|
||||
|
||||
return result;
|
||||
return (b != 0.0) ? fmod(a, b) : 0.0;
|
||||
}
|
||||
|
||||
float safe_sqrt(float a)
|
||||
{
|
||||
float result;
|
||||
|
||||
if (a > 0.0)
|
||||
result = sqrt(a);
|
||||
else
|
||||
result = 0.0;
|
||||
|
||||
return result;
|
||||
return (a > 0.0) ? sqrt(a) : 0.0;
|
||||
}
|
||||
|
||||
float safe_log(float a, float b)
|
||||
{
|
||||
if (a < 0.0 || b < 0.0)
|
||||
return 0.0;
|
||||
|
||||
return log(a) / log(b);
|
||||
return (a > 0.0 && b > 0.0) ? log(a) / log(b) : 0.0;
|
||||
}
|
||||
|
||||
/* OSL asin, acos, and pow functions are safe by default. */
|
||||
shader node_math(string type = "add",
|
||||
int use_clamp = 0,
|
||||
float Value1 = 0.0,
|
||||
float Value2 = 0.0,
|
||||
float Value1 = 0.5,
|
||||
float Value2 = 0.5,
|
||||
output float Value = 0.0)
|
||||
{
|
||||
/* OSL asin, acos, pow check for values that could give rise to nan */
|
||||
|
||||
if (type == "add")
|
||||
Value = Value1 + Value2;
|
||||
else if (type == "subtract")
|
||||
|
@ -76,6 +50,32 @@ shader node_math(string type = "add",
|
|||
Value = Value1 * Value2;
|
||||
else if (type == "divide")
|
||||
Value = safe_divide(Value1, Value2);
|
||||
else if (type == "power")
|
||||
Value = pow(Value1, Value2);
|
||||
else if (type == "logarithm")
|
||||
Value = safe_log(Value1, Value2);
|
||||
else if (type == "sqrt")
|
||||
Value = safe_sqrt(Value1);
|
||||
else if (type == "absolute")
|
||||
Value = fabs(Value1);
|
||||
else if (type == "minimum")
|
||||
Value = min(Value1, Value2);
|
||||
else if (type == "maximum")
|
||||
Value = max(Value1, Value2);
|
||||
else if (type == "less_than")
|
||||
Value = Value1 < Value2;
|
||||
else if (type == "greater_than")
|
||||
Value = Value1 > Value2;
|
||||
else if (type == "round")
|
||||
Value = floor(Value1 + 0.5);
|
||||
else if (type == "floor")
|
||||
Value = floor(Value1);
|
||||
else if (type == "ceil")
|
||||
Value = ceil(Value1);
|
||||
else if (type == "fraction")
|
||||
Value = Value1 - floor(Value1);
|
||||
else if (type == "modulo")
|
||||
Value = safe_modulo(Value1, Value2);
|
||||
else if (type == "sine")
|
||||
Value = sin(Value1);
|
||||
else if (type == "cosine")
|
||||
|
@ -88,35 +88,8 @@ shader node_math(string type = "add",
|
|||
Value = acos(Value1);
|
||||
else if (type == "arctangent")
|
||||
Value = atan(Value1);
|
||||
else if (type == "power")
|
||||
Value = pow(Value1, Value2);
|
||||
else if (type == "logarithm")
|
||||
Value = safe_log(Value1, Value2);
|
||||
else if (type == "minimum")
|
||||
Value = min(Value1, Value2);
|
||||
else if (type == "maximum")
|
||||
Value = max(Value1, Value2);
|
||||
else if (type == "round")
|
||||
Value = floor(Value1 + 0.5);
|
||||
else if (type == "less_than")
|
||||
Value = Value1 < Value2;
|
||||
else if (type == "greater_than")
|
||||
Value = Value1 > Value2;
|
||||
else if (type == "modulo")
|
||||
Value = safe_modulo(Value1, Value2);
|
||||
else if (type == "absolute")
|
||||
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);
|
||||
else
|
||||
warning("%s", "Unknown math operator!");
|
||||
}
|
||||
|
|
|
@ -16,24 +16,22 @@
|
|||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Nodes */
|
||||
|
||||
ccl_device void svm_node_math(KernelGlobals *kg,
|
||||
ShaderData *sd,
|
||||
float *stack,
|
||||
uint itype,
|
||||
uint f1_offset,
|
||||
uint f2_offset,
|
||||
uint type,
|
||||
uint inputs_stack_offsets,
|
||||
uint result_stack_offset,
|
||||
int *offset)
|
||||
{
|
||||
NodeMath type = (NodeMath)itype;
|
||||
float f1 = stack_load_float(stack, f1_offset);
|
||||
float f2 = stack_load_float(stack, f2_offset);
|
||||
float f = svm_math(type, f1, f2);
|
||||
uint a_stack_offset, b_stack_offset;
|
||||
decode_node_uchar4(inputs_stack_offsets, &a_stack_offset, &b_stack_offset, NULL, NULL);
|
||||
|
||||
uint4 node1 = read_node(kg, 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);
|
||||
|
||||
stack_store_float(stack, node1.y, f);
|
||||
stack_store_float(stack, result_stack_offset, result);
|
||||
}
|
||||
|
||||
ccl_device void svm_node_vector_math(KernelGlobals *kg,
|
||||
|
|
|
@ -51,64 +51,60 @@ ccl_device void svm_vector_math(
|
|||
}
|
||||
}
|
||||
|
||||
ccl_device float svm_math(NodeMath type, float Fac1, float Fac2)
|
||||
ccl_device float svm_math(NodeMathType type, float a, float b)
|
||||
{
|
||||
float Fac;
|
||||
|
||||
if (type == NODE_MATH_ADD)
|
||||
Fac = Fac1 + Fac2;
|
||||
else if (type == NODE_MATH_SUBTRACT)
|
||||
Fac = Fac1 - Fac2;
|
||||
else if (type == NODE_MATH_MULTIPLY)
|
||||
Fac = Fac1 * Fac2;
|
||||
else if (type == NODE_MATH_DIVIDE)
|
||||
Fac = safe_divide(Fac1, Fac2);
|
||||
else if (type == NODE_MATH_SINE)
|
||||
Fac = sinf(Fac1);
|
||||
else if (type == NODE_MATH_COSINE)
|
||||
Fac = cosf(Fac1);
|
||||
else if (type == NODE_MATH_TANGENT)
|
||||
Fac = tanf(Fac1);
|
||||
else if (type == NODE_MATH_ARCSINE)
|
||||
Fac = safe_asinf(Fac1);
|
||||
else if (type == NODE_MATH_ARCCOSINE)
|
||||
Fac = safe_acosf(Fac1);
|
||||
else if (type == NODE_MATH_ARCTANGENT)
|
||||
Fac = atanf(Fac1);
|
||||
else if (type == NODE_MATH_POWER)
|
||||
Fac = safe_powf(Fac1, Fac2);
|
||||
else if (type == NODE_MATH_LOGARITHM)
|
||||
Fac = safe_logf(Fac1, Fac2);
|
||||
else if (type == NODE_MATH_MINIMUM)
|
||||
Fac = fminf(Fac1, Fac2);
|
||||
else if (type == NODE_MATH_MAXIMUM)
|
||||
Fac = fmaxf(Fac1, Fac2);
|
||||
else if (type == NODE_MATH_ROUND)
|
||||
Fac = floorf(Fac1 + 0.5f);
|
||||
else if (type == NODE_MATH_LESS_THAN)
|
||||
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_ABSOLUTE)
|
||||
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
|
||||
Fac = 0.0f;
|
||||
|
||||
return Fac;
|
||||
switch (type) {
|
||||
case NODE_MATH_ADD:
|
||||
return a + b;
|
||||
case NODE_MATH_SUBTRACT:
|
||||
return a - b;
|
||||
case NODE_MATH_MULTIPLY:
|
||||
return a * b;
|
||||
case NODE_MATH_DIVIDE:
|
||||
return safe_divide(a, b);
|
||||
case NODE_MATH_POWER:
|
||||
return safe_powf(a, b);
|
||||
case NODE_MATH_LOGARITHM:
|
||||
return safe_logf(a, b);
|
||||
case NODE_MATH_SQRT:
|
||||
return safe_sqrtf(a);
|
||||
case NODE_MATH_ABSOLUTE:
|
||||
return fabsf(a);
|
||||
case NODE_MATH_MINIMUM:
|
||||
return fminf(a, b);
|
||||
case NODE_MATH_MAXIMUM:
|
||||
return fmaxf(a, b);
|
||||
case NODE_MATH_LESS_THAN:
|
||||
return a < b;
|
||||
case NODE_MATH_GREATER_THAN:
|
||||
return a > b;
|
||||
case NODE_MATH_ROUND:
|
||||
return floorf(a + 0.5f);
|
||||
case NODE_MATH_FLOOR:
|
||||
return floorf(a);
|
||||
case NODE_MATH_CEIL:
|
||||
return ceilf(a);
|
||||
case NODE_MATH_FRACTION:
|
||||
return a - floorf(a);
|
||||
case NODE_MATH_MODULO:
|
||||
return safe_modulo(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_ARCSINE:
|
||||
return safe_asinf(a);
|
||||
case NODE_MATH_ARCCOSINE:
|
||||
return safe_acosf(a);
|
||||
case NODE_MATH_ARCTANGENT:
|
||||
return atanf(a);
|
||||
case NODE_MATH_ARCTAN2:
|
||||
return atan2f(a, b);
|
||||
default:
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate color in range 800..12000 using an approximation
|
||||
|
|
|
@ -244,7 +244,7 @@ typedef enum NodeMix {
|
|||
NODE_MIX_CLAMP /* used for the clamp UI option */
|
||||
} NodeMix;
|
||||
|
||||
typedef enum NodeMath {
|
||||
typedef enum NodeMathType {
|
||||
NODE_MATH_ADD,
|
||||
NODE_MATH_SUBTRACT,
|
||||
NODE_MATH_MULTIPLY,
|
||||
|
@ -267,10 +267,9 @@ typedef enum NodeMath {
|
|||
NODE_MATH_ARCTAN2,
|
||||
NODE_MATH_FLOOR,
|
||||
NODE_MATH_CEIL,
|
||||
NODE_MATH_FRACT,
|
||||
NODE_MATH_FRACTION,
|
||||
NODE_MATH_SQRT,
|
||||
NODE_MATH_CLAMP /* used for the clamp UI option */
|
||||
} NodeMath;
|
||||
} NodeMathType;
|
||||
|
||||
typedef enum NodeVectorMath {
|
||||
NODE_VECTOR_MATH_ADD,
|
||||
|
|
|
@ -301,7 +301,7 @@ void ConstantFolder::fold_mix(NodeMix type, bool clamp) const
|
|||
}
|
||||
}
|
||||
|
||||
void ConstantFolder::fold_math(NodeMath type, bool clamp) const
|
||||
void ConstantFolder::fold_math(NodeMathType type) const
|
||||
{
|
||||
ShaderInput *value1_in = node->input("Value1");
|
||||
ShaderInput *value2_in = node->input("Value2");
|
||||
|
@ -310,25 +310,25 @@ void ConstantFolder::fold_math(NodeMath type, bool clamp) const
|
|||
case NODE_MATH_ADD:
|
||||
/* X + 0 == 0 + X == X */
|
||||
if (is_zero(value1_in)) {
|
||||
try_bypass_or_make_constant(value2_in, clamp);
|
||||
try_bypass_or_make_constant(value2_in);
|
||||
}
|
||||
else if (is_zero(value2_in)) {
|
||||
try_bypass_or_make_constant(value1_in, clamp);
|
||||
try_bypass_or_make_constant(value1_in);
|
||||
}
|
||||
break;
|
||||
case NODE_MATH_SUBTRACT:
|
||||
/* X - 0 == X */
|
||||
if (is_zero(value2_in)) {
|
||||
try_bypass_or_make_constant(value1_in, clamp);
|
||||
try_bypass_or_make_constant(value1_in);
|
||||
}
|
||||
break;
|
||||
case NODE_MATH_MULTIPLY:
|
||||
/* X * 1 == 1 * X == X */
|
||||
if (is_one(value1_in)) {
|
||||
try_bypass_or_make_constant(value2_in, clamp);
|
||||
try_bypass_or_make_constant(value2_in);
|
||||
}
|
||||
else if (is_one(value2_in)) {
|
||||
try_bypass_or_make_constant(value1_in, clamp);
|
||||
try_bypass_or_make_constant(value1_in);
|
||||
}
|
||||
/* X * 0 == 0 * X == 0 */
|
||||
else if (is_zero(value1_in) || is_zero(value2_in)) {
|
||||
|
@ -338,7 +338,7 @@ void ConstantFolder::fold_math(NodeMath type, bool clamp) const
|
|||
case NODE_MATH_DIVIDE:
|
||||
/* X / 1 == X */
|
||||
if (is_one(value2_in)) {
|
||||
try_bypass_or_make_constant(value1_in, clamp);
|
||||
try_bypass_or_make_constant(value1_in);
|
||||
}
|
||||
/* 0 / X == 0 */
|
||||
else if (is_zero(value1_in)) {
|
||||
|
@ -352,7 +352,7 @@ void ConstantFolder::fold_math(NodeMath type, bool clamp) const
|
|||
}
|
||||
/* X ^ 1 == X */
|
||||
else if (is_one(value2_in)) {
|
||||
try_bypass_or_make_constant(value1_in, clamp);
|
||||
try_bypass_or_make_constant(value1_in);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -64,7 +64,7 @@ class ConstantFolder {
|
|||
|
||||
/* Specific nodes. */
|
||||
void fold_mix(NodeMix type, bool clamp) const;
|
||||
void fold_math(NodeMath type, bool clamp) const;
|
||||
void fold_math(NodeMathType type) const;
|
||||
void fold_vector_math(NodeVectorMath type) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -5422,14 +5422,12 @@ NODE_DEFINE(MathNode)
|
|||
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("fraction", NODE_MATH_FRACTION);
|
||||
type_enum.insert("sqrt", NODE_MATH_SQRT);
|
||||
SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
|
||||
|
||||
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
|
||||
|
||||
SOCKET_IN_FLOAT(value1, "Value1", 0.0f);
|
||||
SOCKET_IN_FLOAT(value2, "Value2", 0.0f);
|
||||
SOCKET_IN_FLOAT(value1, "Value1", 0.5f);
|
||||
SOCKET_IN_FLOAT(value2, "Value2", 0.5f);
|
||||
|
||||
SOCKET_OUT_FLOAT(value, "Value");
|
||||
|
||||
|
@ -5440,13 +5438,28 @@ MathNode::MathNode() : ShaderNode(node_type)
|
|||
{
|
||||
}
|
||||
|
||||
void MathNode::expand(ShaderGraph *graph)
|
||||
{
|
||||
if (use_clamp) {
|
||||
ShaderOutput *result_out = output("Value");
|
||||
if (!result_out->links.empty()) {
|
||||
ClampNode *clamp_node = new ClampNode();
|
||||
clamp_node->min = 0.0f;
|
||||
clamp_node->max = 1.0f;
|
||||
graph->add(clamp_node);
|
||||
graph->relink(result_out, clamp_node->output("Result"));
|
||||
graph->connect(result_out, clamp_node->input("Value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MathNode::constant_fold(const ConstantFolder &folder)
|
||||
{
|
||||
if (folder.all_inputs_constant()) {
|
||||
folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp);
|
||||
folder.make_constant(svm_math(type, value1, value2));
|
||||
}
|
||||
else {
|
||||
folder.fold_math(type, use_clamp);
|
||||
folder.fold_math(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5456,20 +5469,19 @@ void MathNode::compile(SVMCompiler &compiler)
|
|||
ShaderInput *value2_in = input("Value2");
|
||||
ShaderOutput *value_out = output("Value");
|
||||
|
||||
compiler.add_node(
|
||||
NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in));
|
||||
compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
|
||||
int value1_stack_offset = compiler.stack_assign(value1_in);
|
||||
int value2_stack_offset = compiler.stack_assign(value2_in);
|
||||
int value_stack_offset = compiler.stack_assign(value_out);
|
||||
|
||||
if (use_clamp) {
|
||||
compiler.add_node(NODE_MATH, NODE_MATH_CLAMP, compiler.stack_assign(value_out));
|
||||
compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
|
||||
}
|
||||
compiler.add_node(NODE_MATH,
|
||||
type,
|
||||
compiler.encode_uchar4(value1_stack_offset, value2_stack_offset),
|
||||
value_stack_offset);
|
||||
}
|
||||
|
||||
void MathNode::compile(OSLCompiler &compiler)
|
||||
{
|
||||
compiler.parameter(this, "type");
|
||||
compiler.parameter(this, "use_clamp");
|
||||
compiler.add(this, "node_math");
|
||||
}
|
||||
|
||||
|
|
|
@ -1260,11 +1260,12 @@ class MathNode : public ShaderNode {
|
|||
{
|
||||
return NODE_GROUP_LEVEL_1;
|
||||
}
|
||||
void expand(ShaderGraph *graph);
|
||||
void constant_fold(const ConstantFolder &folder);
|
||||
|
||||
float value1;
|
||||
float value2;
|
||||
NodeMath type;
|
||||
NodeMathType type;
|
||||
bool use_clamp;
|
||||
};
|
||||
|
||||
|
|
|
@ -1003,7 +1003,7 @@ TEST_F(RenderGraph, constant_fold_math_clamp)
|
|||
* Includes 2 tests: constant on each side.
|
||||
*/
|
||||
static void build_math_partial_test_graph(ShaderGraphBuilder &builder,
|
||||
NodeMath type,
|
||||
NodeMathType type,
|
||||
float constval)
|
||||
{
|
||||
builder
|
||||
|
|
|
@ -615,6 +615,7 @@ void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
|
|||
|
||||
int nodeSocketIsHidden(struct bNodeSocket *sock);
|
||||
void ntreeTagUsedSockets(struct bNodeTree *ntree);
|
||||
void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
|
||||
|
||||
/* Node Clipboard */
|
||||
void BKE_node_clipboard_init(struct bNodeTree *ntree);
|
||||
|
|
|
@ -2799,6 +2799,16 @@ int nodeSocketIsHidden(bNodeSocket *sock)
|
|||
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
|
||||
}
|
||||
|
||||
void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available)
|
||||
{
|
||||
if (is_available) {
|
||||
sock->flag &= ~SOCK_UNAVAIL;
|
||||
}
|
||||
else {
|
||||
sock->flag |= SOCK_UNAVAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************** Node Clipboard *********** */
|
||||
|
||||
#define USE_NODE_CB_VALIDATE
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_color_types.h"
|
||||
|
@ -185,7 +186,7 @@ static void square_roughness_node_insert(bNodeTree *ntree)
|
|||
|
||||
/* Add sqrt node. */
|
||||
bNode *node = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
|
||||
node->custom1 = NODE_MATH_POW;
|
||||
node->custom1 = NODE_MATH_POWER;
|
||||
node->locx = 0.5f * (fromnode->locx + tonode->locx);
|
||||
node->locy = 0.5f * (fromnode->locy + tonode->locy);
|
||||
|
||||
|
@ -385,6 +386,46 @@ static void light_emission_unify(Light *light, const char *engine)
|
|||
}
|
||||
}
|
||||
|
||||
/* The B input of the Math node is no longer used for single-operand operators.
|
||||
* Previously, if the B input was linked and the A input was not, the B input
|
||||
* was used as the input of the operator. To correct this, we move the link
|
||||
* from B to A if B is linked and A is not.
|
||||
*/
|
||||
static void update_math_node_single_operand_operators(bNodeTree *ntree)
|
||||
{
|
||||
bool need_update = false;
|
||||
|
||||
for (bNode *node = ntree->nodes.first; node; node = node->next) {
|
||||
if (node->type == SH_NODE_MATH) {
|
||||
if (ELEM(node->custom1,
|
||||
NODE_MATH_SQRT,
|
||||
NODE_MATH_CEIL,
|
||||
NODE_MATH_SINE,
|
||||
NODE_MATH_ROUND,
|
||||
NODE_MATH_FLOOR,
|
||||
NODE_MATH_COSINE,
|
||||
NODE_MATH_ARCSINE,
|
||||
NODE_MATH_TANGENT,
|
||||
NODE_MATH_ABSOLUTE,
|
||||
NODE_MATH_FRACTION,
|
||||
NODE_MATH_ARCCOSINE,
|
||||
NODE_MATH_ARCTANGENT)) {
|
||||
bNodeSocket *sockA = BLI_findlink(&node->inputs, 0);
|
||||
bNodeSocket *sockB = BLI_findlink(&node->inputs, 1);
|
||||
if (!sockA->link && sockB->link) {
|
||||
nodeAddLink(ntree, sockB->link->fromnode, sockB->link->fromsock, node, sockA);
|
||||
nodeRemLink(ntree, sockB->link);
|
||||
need_update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (need_update) {
|
||||
ntreeUpdateTree(NULL, ntree);
|
||||
}
|
||||
}
|
||||
|
||||
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
|
||||
{
|
||||
/* Particle shape shared with Eevee. */
|
||||
|
@ -526,4 +567,13 @@ void do_versions_after_linking_cycles(Main *bmain)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
if (ntree->type == NTREE_SHADER) {
|
||||
update_math_node_single_operand_operators(ntree);
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,61 +29,61 @@ void MathNode::convertToOperations(NodeConverter &converter,
|
|||
case NODE_MATH_ADD:
|
||||
operation = new MathAddOperation();
|
||||
break;
|
||||
case NODE_MATH_SUB:
|
||||
case NODE_MATH_SUBTRACT:
|
||||
operation = new MathSubtractOperation();
|
||||
break;
|
||||
case NODE_MATH_MUL:
|
||||
case NODE_MATH_MULTIPLY:
|
||||
operation = new MathMultiplyOperation();
|
||||
break;
|
||||
case NODE_MATH_DIVIDE:
|
||||
operation = new MathDivideOperation();
|
||||
break;
|
||||
case NODE_MATH_SIN:
|
||||
case NODE_MATH_SINE:
|
||||
operation = new MathSineOperation();
|
||||
break;
|
||||
case NODE_MATH_COS:
|
||||
case NODE_MATH_COSINE:
|
||||
operation = new MathCosineOperation();
|
||||
break;
|
||||
case NODE_MATH_TAN:
|
||||
case NODE_MATH_TANGENT:
|
||||
operation = new MathTangentOperation();
|
||||
break;
|
||||
case NODE_MATH_ASIN:
|
||||
case NODE_MATH_ARCSINE:
|
||||
operation = new MathArcSineOperation();
|
||||
break;
|
||||
case NODE_MATH_ACOS:
|
||||
case NODE_MATH_ARCCOSINE:
|
||||
operation = new MathArcCosineOperation();
|
||||
break;
|
||||
case NODE_MATH_ATAN:
|
||||
case NODE_MATH_ARCTANGENT:
|
||||
operation = new MathArcTangentOperation();
|
||||
break;
|
||||
case NODE_MATH_POW:
|
||||
case NODE_MATH_POWER:
|
||||
operation = new MathPowerOperation();
|
||||
break;
|
||||
case NODE_MATH_LOG:
|
||||
case NODE_MATH_LOGARITHM:
|
||||
operation = new MathLogarithmOperation();
|
||||
break;
|
||||
case NODE_MATH_MIN:
|
||||
case NODE_MATH_MINIMUM:
|
||||
operation = new MathMinimumOperation();
|
||||
break;
|
||||
case NODE_MATH_MAX:
|
||||
case NODE_MATH_MAXIMUM:
|
||||
operation = new MathMaximumOperation();
|
||||
break;
|
||||
case NODE_MATH_ROUND:
|
||||
operation = new MathRoundOperation();
|
||||
break;
|
||||
case NODE_MATH_LESS:
|
||||
case NODE_MATH_LESS_THAN:
|
||||
operation = new MathLessThanOperation();
|
||||
break;
|
||||
case NODE_MATH_GREATER:
|
||||
case NODE_MATH_GREATER_THAN:
|
||||
operation = new MathGreaterThanOperation();
|
||||
break;
|
||||
case NODE_MATH_MOD:
|
||||
case NODE_MATH_MODULO:
|
||||
operation = new MathModuloOperation();
|
||||
break;
|
||||
case NODE_MATH_ABS:
|
||||
case NODE_MATH_ABSOLUTE:
|
||||
operation = new MathAbsoluteOperation();
|
||||
break;
|
||||
case NODE_MATH_ATAN2:
|
||||
case NODE_MATH_ARCTAN2:
|
||||
operation = new MathArcTan2Operation();
|
||||
break;
|
||||
case NODE_MATH_FLOOR:
|
||||
|
@ -92,7 +92,7 @@ void MathNode::convertToOperations(NodeConverter &converter,
|
|||
case NODE_MATH_CEIL:
|
||||
operation = new MathCeilOperation();
|
||||
break;
|
||||
case NODE_MATH_FRACT:
|
||||
case NODE_MATH_FRACTION:
|
||||
operation = new MathFractOperation();
|
||||
break;
|
||||
case NODE_MATH_SQRT:
|
||||
|
|
|
@ -250,178 +250,138 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
|
|||
outview = normalize(co);
|
||||
}
|
||||
|
||||
void math_add(float val1, float val2, out float outval)
|
||||
void math_add(float a, float b, out float result)
|
||||
{
|
||||
outval = val1 + val2;
|
||||
result = a + b;
|
||||
}
|
||||
|
||||
void math_subtract(float val1, float val2, out float outval)
|
||||
void math_subtract(float a, float b, out float result)
|
||||
{
|
||||
outval = val1 - val2;
|
||||
result = a - b;
|
||||
}
|
||||
|
||||
void math_multiply(float val1, float val2, out float outval)
|
||||
void math_multiply(float a, float b, out float result)
|
||||
{
|
||||
outval = val1 * val2;
|
||||
result = a * b;
|
||||
}
|
||||
|
||||
void math_divide(float val1, float val2, out float outval)
|
||||
void math_divide(float a, float b, out float result)
|
||||
{
|
||||
if (val2 == 0.0) {
|
||||
outval = 0.0;
|
||||
result = (b != 0.0) ? a / b : 0.0;
|
||||
}
|
||||
|
||||
void math_power(float a, float b, out float result)
|
||||
{
|
||||
if (a >= 0.0) {
|
||||
result = compatible_pow(a, b);
|
||||
}
|
||||
else {
|
||||
outval = val1 / val2;
|
||||
}
|
||||
}
|
||||
|
||||
void math_sine(float val, out float outval)
|
||||
{
|
||||
outval = sin(val);
|
||||
}
|
||||
|
||||
void math_cosine(float val, out float outval)
|
||||
{
|
||||
outval = cos(val);
|
||||
}
|
||||
|
||||
void math_tangent(float val, out float outval)
|
||||
{
|
||||
outval = tan(val);
|
||||
}
|
||||
|
||||
void math_asin(float val, out float outval)
|
||||
{
|
||||
if (val <= 1.0 && val >= -1.0) {
|
||||
outval = asin(val);
|
||||
}
|
||||
else {
|
||||
outval = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void math_acos(float val, out float outval)
|
||||
{
|
||||
if (val <= 1.0 && val >= -1.0) {
|
||||
outval = acos(val);
|
||||
}
|
||||
else {
|
||||
outval = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void math_atan(float val, out float outval)
|
||||
{
|
||||
outval = atan(val);
|
||||
}
|
||||
|
||||
void math_pow(float val1, float val2, out float outval)
|
||||
{
|
||||
if (val1 >= 0.0) {
|
||||
outval = compatible_pow(val1, val2);
|
||||
}
|
||||
else {
|
||||
float val2_mod_1 = mod(abs(val2), 1.0);
|
||||
|
||||
if (val2_mod_1 > 0.999 || val2_mod_1 < 0.001) {
|
||||
outval = compatible_pow(val1, floor(val2 + 0.5));
|
||||
float fraction = mod(abs(b), 1.0);
|
||||
if (fraction > 0.999 || fraction < 0.001) {
|
||||
result = compatible_pow(a, floor(b + 0.5));
|
||||
}
|
||||
else {
|
||||
outval = 0.0;
|
||||
result = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void math_log(float val1, float val2, out float outval)
|
||||
void math_logarithm(float a, float b, out float result)
|
||||
{
|
||||
if (val1 > 0.0 && val2 > 0.0) {
|
||||
outval = log2(val1) / log2(val2);
|
||||
}
|
||||
else {
|
||||
outval = 0.0;
|
||||
}
|
||||
result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0;
|
||||
}
|
||||
|
||||
void math_max(float val1, float val2, out float outval)
|
||||
void math_sqrt(float a, float b, out float result)
|
||||
{
|
||||
outval = max(val1, val2);
|
||||
result = (a > 0.0) ? sqrt(a) : 0.0;
|
||||
}
|
||||
|
||||
void math_min(float val1, float val2, out float outval)
|
||||
void math_absolute(float a, float b, out float result)
|
||||
{
|
||||
outval = min(val1, val2);
|
||||
result = abs(a);
|
||||
}
|
||||
|
||||
void math_round(float val, out float outval)
|
||||
void math_minimum(float a, float b, out float result)
|
||||
{
|
||||
outval = floor(val + 0.5);
|
||||
result = min(a, b);
|
||||
}
|
||||
|
||||
void math_less_than(float val1, float val2, out float outval)
|
||||
void math_maximum(float a, float b, out float result)
|
||||
{
|
||||
if (val1 < val2) {
|
||||
outval = 1.0;
|
||||
}
|
||||
else {
|
||||
outval = 0.0;
|
||||
}
|
||||
result = max(a, b);
|
||||
}
|
||||
|
||||
void math_greater_than(float val1, float val2, out float outval)
|
||||
void math_less_than(float a, float b, out float result)
|
||||
{
|
||||
if (val1 > val2) {
|
||||
outval = 1.0;
|
||||
}
|
||||
else {
|
||||
outval = 0.0;
|
||||
}
|
||||
result = (a < b) ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
void math_modulo(float val1, float val2, out float outval)
|
||||
void math_greater_than(float a, float b, out float result)
|
||||
{
|
||||
if (val2 == 0.0 || val1 == val2) {
|
||||
outval = 0.0;
|
||||
}
|
||||
else {
|
||||
/* change sign to match C convention, mod in GLSL will take absolute for negative numbers,
|
||||
* see https://www.opengl.org/sdk/docs/man/html/mod.xhtml */
|
||||
outval = sign(val1) * mod(abs(val1), val2);
|
||||
}
|
||||
result = (a > b) ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
void math_abs(float val1, out float outval)
|
||||
void math_round(float a, float b, out float result)
|
||||
{
|
||||
outval = abs(val1);
|
||||
result = floor(a + 0.5);
|
||||
}
|
||||
|
||||
void math_atan2(float val1, float val2, out float outval)
|
||||
void math_floor(float a, float b, out float result)
|
||||
{
|
||||
outval = atan(val1, val2);
|
||||
result = floor(a);
|
||||
}
|
||||
|
||||
void math_floor(float val, out float outval)
|
||||
void math_ceil(float a, float b, out float result)
|
||||
{
|
||||
outval = floor(val);
|
||||
result = ceil(a);
|
||||
}
|
||||
|
||||
void math_ceil(float val, out float outval)
|
||||
void math_fraction(float a, float b, out float result)
|
||||
{
|
||||
outval = ceil(val);
|
||||
result = a - floor(a);
|
||||
}
|
||||
|
||||
void math_fract(float val, out float outval)
|
||||
/* Change sign to match C convention. mod in GLSL will take absolute for negative numbers.
|
||||
* See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/mod.xhtml
|
||||
*/
|
||||
void math_modulo(float a, float b, out float result)
|
||||
{
|
||||
outval = val - floor(val);
|
||||
result = (b != 0.0) ? sign(a) * mod(abs(a), b) : 0.0;
|
||||
}
|
||||
|
||||
void math_sqrt(float val, out float outval)
|
||||
void math_sine(float a, float b, out float result)
|
||||
{
|
||||
if (val > 0.0) {
|
||||
outval = sqrt(val);
|
||||
}
|
||||
else {
|
||||
outval = 0.0;
|
||||
}
|
||||
result = sin(a);
|
||||
}
|
||||
|
||||
void math_cosine(float a, float b, out float result)
|
||||
{
|
||||
result = cos(a);
|
||||
}
|
||||
|
||||
void math_tangent(float a, float b, out float result)
|
||||
{
|
||||
result = tan(a);
|
||||
}
|
||||
|
||||
void math_arcsine(float a, float b, out float result)
|
||||
{
|
||||
result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0;
|
||||
}
|
||||
|
||||
void math_arccosine(float a, float b, out float result)
|
||||
{
|
||||
result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0;
|
||||
}
|
||||
|
||||
void math_arctangent(float a, float b, out float result)
|
||||
{
|
||||
result = atan(a);
|
||||
}
|
||||
|
||||
void math_arctan2(float a, float b, out float result)
|
||||
{
|
||||
result = atan(a, b);
|
||||
}
|
||||
|
||||
void squeeze(float val, float width, float center, out float outval)
|
||||
|
|
|
@ -1167,31 +1167,31 @@ typedef struct NodeDenoise {
|
|||
/* math node clamp */
|
||||
#define SHD_MATH_CLAMP 1
|
||||
|
||||
/* Math node operation/ */
|
||||
/* Math node operations. */
|
||||
enum {
|
||||
NODE_MATH_ADD = 0,
|
||||
NODE_MATH_SUB = 1,
|
||||
NODE_MATH_MUL = 2,
|
||||
NODE_MATH_SUBTRACT = 1,
|
||||
NODE_MATH_MULTIPLY = 2,
|
||||
NODE_MATH_DIVIDE = 3,
|
||||
NODE_MATH_SIN = 4,
|
||||
NODE_MATH_COS = 5,
|
||||
NODE_MATH_TAN = 6,
|
||||
NODE_MATH_ASIN = 7,
|
||||
NODE_MATH_ACOS = 8,
|
||||
NODE_MATH_ATAN = 9,
|
||||
NODE_MATH_POW = 10,
|
||||
NODE_MATH_LOG = 11,
|
||||
NODE_MATH_MIN = 12,
|
||||
NODE_MATH_MAX = 13,
|
||||
NODE_MATH_SINE = 4,
|
||||
NODE_MATH_COSINE = 5,
|
||||
NODE_MATH_TANGENT = 6,
|
||||
NODE_MATH_ARCSINE = 7,
|
||||
NODE_MATH_ARCCOSINE = 8,
|
||||
NODE_MATH_ARCTANGENT = 9,
|
||||
NODE_MATH_POWER = 10,
|
||||
NODE_MATH_LOGARITHM = 11,
|
||||
NODE_MATH_MINIMUM = 12,
|
||||
NODE_MATH_MAXIMUM = 13,
|
||||
NODE_MATH_ROUND = 14,
|
||||
NODE_MATH_LESS = 15,
|
||||
NODE_MATH_GREATER = 16,
|
||||
NODE_MATH_MOD = 17,
|
||||
NODE_MATH_ABS = 18,
|
||||
NODE_MATH_ATAN2 = 19,
|
||||
NODE_MATH_LESS_THAN = 15,
|
||||
NODE_MATH_GREATER_THAN = 16,
|
||||
NODE_MATH_MODULO = 17,
|
||||
NODE_MATH_ABSOLUTE = 18,
|
||||
NODE_MATH_ARCTAN2 = 19,
|
||||
NODE_MATH_FLOOR = 20,
|
||||
NODE_MATH_CEIL = 21,
|
||||
NODE_MATH_FRACT = 22,
|
||||
NODE_MATH_FRACTION = 22,
|
||||
NODE_MATH_SQRT = 23,
|
||||
};
|
||||
|
||||
|
|
|
@ -100,34 +100,38 @@ static const EnumPropertyItem node_chunksize_items[] = {
|
|||
#endif
|
||||
|
||||
const EnumPropertyItem rna_enum_node_math_items[] = {
|
||||
{NODE_MATH_ADD, "ADD", 0, "Add", ""},
|
||||
{NODE_MATH_SUB, "SUBTRACT", 0, "Subtract", ""},
|
||||
{NODE_MATH_MUL, "MULTIPLY", 0, "Multiply", ""},
|
||||
{NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", ""},
|
||||
{NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
|
||||
{NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
|
||||
{NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"},
|
||||
{NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", "A / B"},
|
||||
{0, "", ICON_NONE, NULL, NULL},
|
||||
{NODE_MATH_POW, "POWER", 0, "Power", ""},
|
||||
{NODE_MATH_LOG, "LOGARITHM", 0, "Logarithm", ""},
|
||||
{NODE_MATH_SQRT, "SQRT", 0, "Square Root", ""},
|
||||
{NODE_MATH_ABS, "ABSOLUTE", 0, "Absolute", ""},
|
||||
{NODE_MATH_POWER, "POWER", 0, "Power", "A power B"},
|
||||
{NODE_MATH_LOGARITHM, "LOGARITHM", 0, "Logarithm", "Logarithm A base B"},
|
||||
{NODE_MATH_SQRT, "SQRT", 0, "Square Root", "Square root of A"},
|
||||
{NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Magnitude of A"},
|
||||
{0, "", ICON_NONE, NULL, NULL},
|
||||
{NODE_MATH_MIN, "MINIMUM", 0, "Minimum", ""},
|
||||
{NODE_MATH_MAX, "MAXIMUM", 0, "Maximum", ""},
|
||||
{NODE_MATH_LESS, "LESS_THAN", 0, "Less Than", ""},
|
||||
{NODE_MATH_GREATER, "GREATER_THAN", 0, "Greater Than", ""},
|
||||
{NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "The minimum from A and B"},
|
||||
{NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "The maximum from A and B"},
|
||||
{NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"},
|
||||
{NODE_MATH_GREATER_THAN, "GREATER_THAN", 0, "Greater Than", "1 if A > B else 0"},
|
||||
{0, "", ICON_NONE, NULL, NULL},
|
||||
{NODE_MATH_ROUND, "ROUND", 0, "Round", ""},
|
||||
{NODE_MATH_FLOOR, "FLOOR", 0, "Floor", ""},
|
||||
{NODE_MATH_CEIL, "CEIL", 0, "Ceil", ""},
|
||||
{NODE_MATH_FRACT, "FRACT", 0, "Fract", ""},
|
||||
{NODE_MATH_MOD, "MODULO", 0, "Modulo", ""},
|
||||
{NODE_MATH_ROUND,
|
||||
"ROUND",
|
||||
0,
|
||||
"Round",
|
||||
"Round A to the nearest integer. Round upward if the fraction part is 0.5"},
|
||||
{NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"},
|
||||
{NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"},
|
||||
{NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
|
||||
{NODE_MATH_MODULO, "MODULO", 0, "Modulo", "A mod B"},
|
||||
{0, "", ICON_NONE, NULL, NULL},
|
||||
{NODE_MATH_SIN, "SINE", 0, "Sine", ""},
|
||||
{NODE_MATH_COS, "COSINE", 0, "Cosine", ""},
|
||||
{NODE_MATH_TAN, "TANGENT", 0, "Tangent", ""},
|
||||
{NODE_MATH_ASIN, "ARCSINE", 0, "Arcsine", ""},
|
||||
{NODE_MATH_ACOS, "ARCCOSINE", 0, "Arccosine", ""},
|
||||
{NODE_MATH_ATAN, "ARCTANGENT", 0, "Arctangent", ""},
|
||||
{NODE_MATH_ATAN2, "ARCTAN2", 0, "Arctan2", ""},
|
||||
{NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"},
|
||||
{NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"},
|
||||
{NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"},
|
||||
{NODE_MATH_ARCSINE, "ARCSINE", 0, "Arcsine", "arcsin(A)"},
|
||||
{NODE_MATH_ARCCOSINE, "ARCCOSINE", 0, "Arccosine", "arccos(A)"},
|
||||
{NODE_MATH_ARCTANGENT, "ARCTANGENT", 0, "Arctangent", "arctan(A)"},
|
||||
{NODE_MATH_ARCTAN2, "ARCTAN2", 0, "Arctan2", "The signed angle arctan(A / B)"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
@ -3852,7 +3856,7 @@ static void def_math(StructRNA *srna)
|
|||
RNA_def_property_enum_sdna(prop, NULL, "custom1");
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_math_items);
|
||||
RNA_def_property_ui_text(prop, "Operation", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_MATH_CLAMP);
|
||||
|
|
|
@ -31,272 +31,6 @@ static bNodeSocketTemplate sh_node_math_in[] = {
|
|||
|
||||
static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
|
||||
|
||||
static void node_shader_exec_math(void *UNUSED(data),
|
||||
int UNUSED(thread),
|
||||
bNode *node,
|
||||
bNodeExecData *UNUSED(execdata),
|
||||
bNodeStack **in,
|
||||
bNodeStack **out)
|
||||
{
|
||||
float a, b, r = 0.0f;
|
||||
|
||||
nodestack_get_vec(&a, SOCK_FLOAT, in[0]);
|
||||
nodestack_get_vec(&b, SOCK_FLOAT, in[1]);
|
||||
|
||||
switch (node->custom1) {
|
||||
|
||||
case NODE_MATH_ADD:
|
||||
r = a + b;
|
||||
break;
|
||||
case NODE_MATH_SUB:
|
||||
r = a - b;
|
||||
break;
|
||||
case NODE_MATH_MUL:
|
||||
r = a * b;
|
||||
break;
|
||||
case NODE_MATH_DIVIDE: {
|
||||
if (b == 0) { /* We don't want to divide by zero. */
|
||||
r = 0.0;
|
||||
}
|
||||
else {
|
||||
r = a / b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_SIN: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
r = sinf(a);
|
||||
}
|
||||
else {
|
||||
r = sinf(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_COS: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
r = cosf(a);
|
||||
}
|
||||
else {
|
||||
r = cosf(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_TAN: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
r = tanf(a);
|
||||
}
|
||||
else {
|
||||
r = tanf(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ASIN: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
/* Can't do the impossible... */
|
||||
if (a <= 1 && a >= -1) {
|
||||
r = asinf(a);
|
||||
}
|
||||
else {
|
||||
r = 0.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Can't do the impossible... */
|
||||
if (b <= 1 && b >= -1) {
|
||||
r = asinf(b);
|
||||
}
|
||||
else {
|
||||
r = 0.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ACOS: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
/* Can't do the impossible... */
|
||||
if (a <= 1 && a >= -1) {
|
||||
r = acosf(a);
|
||||
}
|
||||
else {
|
||||
r = 0.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Can't do the impossible... */
|
||||
if (b <= 1 && b >= -1) {
|
||||
r = acosf(b);
|
||||
}
|
||||
else {
|
||||
r = 0.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ATAN: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
r = atan(a);
|
||||
}
|
||||
else {
|
||||
r = atan(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_POW: {
|
||||
/* Only raise negative numbers by full integers */
|
||||
if (a >= 0) {
|
||||
r = pow(a, b);
|
||||
}
|
||||
else {
|
||||
float y_mod_1 = fabsf(fmodf(b, 1.0f));
|
||||
|
||||
/* if input value is not nearly an integer,
|
||||
* fall back to zero, nicer than straight rounding. */
|
||||
if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) {
|
||||
r = powf(a, floorf(b + 0.5f));
|
||||
}
|
||||
else {
|
||||
r = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_LOG: {
|
||||
/* Don't want any imaginary numbers... */
|
||||
if (a > 0 && b > 0) {
|
||||
r = log(a) / log(b);
|
||||
}
|
||||
else {
|
||||
r = 0.0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_MIN: {
|
||||
if (a < b) {
|
||||
r = a;
|
||||
}
|
||||
else {
|
||||
r = b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_MAX: {
|
||||
if (a > b) {
|
||||
r = a;
|
||||
}
|
||||
else {
|
||||
r = b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ROUND: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
r = (a < 0) ? (int)(a - 0.5f) : (int)(a + 0.5f);
|
||||
}
|
||||
else {
|
||||
r = (b < 0) ? (int)(b - 0.5f) : (int)(b + 0.5f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_LESS: {
|
||||
if (a < b) {
|
||||
r = 1.0f;
|
||||
}
|
||||
else {
|
||||
r = 0.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_GREATER: {
|
||||
if (a > b) {
|
||||
r = 1.0f;
|
||||
}
|
||||
else {
|
||||
r = 0.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_MOD: {
|
||||
if (b == 0.0f) {
|
||||
r = 0.0f;
|
||||
}
|
||||
else {
|
||||
r = fmod(a, b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ABS: {
|
||||
r = fabsf(a);
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ATAN2: {
|
||||
r = atan2(a, b);
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_FLOOR: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
r = floorf(a);
|
||||
}
|
||||
else {
|
||||
r = floorf(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_CEIL: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
r = ceilf(a);
|
||||
}
|
||||
else {
|
||||
r = ceilf(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_FRACT: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
r = a - floorf(a);
|
||||
}
|
||||
else {
|
||||
r = b - floorf(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_SQRT: {
|
||||
/* This one only takes one input, so we've got to choose. */
|
||||
if (in[0]->hasinput || !in[1]->hasinput) {
|
||||
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);
|
||||
}
|
||||
out[0]->vec[0] = r;
|
||||
}
|
||||
|
||||
static int gpu_shader_math(GPUMaterial *mat,
|
||||
bNode *node,
|
||||
bNodeExecData *UNUSED(execdata),
|
||||
|
@ -304,68 +38,65 @@ static int gpu_shader_math(GPUMaterial *mat,
|
|||
GPUNodeStack *out)
|
||||
{
|
||||
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_modulo", "math_abs", "math_atan2",
|
||||
"math_floor", "math_ceil", "math_fract", "math_sqrt",
|
||||
[NODE_MATH_ADD] = "math_add",
|
||||
[NODE_MATH_SUBTRACT] = "math_subtract",
|
||||
[NODE_MATH_MULTIPLY] = "math_multiply",
|
||||
[NODE_MATH_DIVIDE] = "math_divide",
|
||||
|
||||
[NODE_MATH_POWER] = "math_power",
|
||||
[NODE_MATH_LOGARITHM] = "math_logarithm",
|
||||
[NODE_MATH_SQRT] = "math_sqrt",
|
||||
[NODE_MATH_ABSOLUTE] = "math_absolute",
|
||||
|
||||
[NODE_MATH_MINIMUM] = "math_minimum",
|
||||
[NODE_MATH_MAXIMUM] = "math_maximum",
|
||||
[NODE_MATH_LESS_THAN] = "math_less_than",
|
||||
[NODE_MATH_GREATER_THAN] = "math_greater_than",
|
||||
|
||||
[NODE_MATH_ROUND] = "math_round",
|
||||
[NODE_MATH_FLOOR] = "math_floor",
|
||||
[NODE_MATH_CEIL] = "math_ceil",
|
||||
[NODE_MATH_FRACTION] = "math_fraction",
|
||||
[NODE_MATH_MODULO] = "math_modulo",
|
||||
|
||||
[NODE_MATH_SINE] = "math_sine",
|
||||
[NODE_MATH_COSINE] = "math_cosine",
|
||||
[NODE_MATH_TANGENT] = "math_tangent",
|
||||
[NODE_MATH_ARCSINE] = "math_arcsine",
|
||||
[NODE_MATH_ARCCOSINE] = "math_arccosine",
|
||||
[NODE_MATH_ARCTANGENT] = "math_arctangent",
|
||||
[NODE_MATH_ARCTAN2] = "math_arctan2",
|
||||
};
|
||||
|
||||
switch (node->custom1) {
|
||||
case NODE_MATH_ADD:
|
||||
case NODE_MATH_SUB:
|
||||
case NODE_MATH_MUL:
|
||||
case NODE_MATH_DIVIDE:
|
||||
case NODE_MATH_POW:
|
||||
case NODE_MATH_LOG:
|
||||
case NODE_MATH_MIN:
|
||||
case NODE_MATH_MAX:
|
||||
case NODE_MATH_LESS:
|
||||
case NODE_MATH_GREATER:
|
||||
case NODE_MATH_MOD:
|
||||
case NODE_MATH_ATAN2:
|
||||
GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
break;
|
||||
case NODE_MATH_SIN:
|
||||
case NODE_MATH_COS:
|
||||
case NODE_MATH_TAN:
|
||||
case NODE_MATH_ASIN:
|
||||
case NODE_MATH_ACOS:
|
||||
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];
|
||||
memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
|
||||
memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
|
||||
GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
|
||||
}
|
||||
else {
|
||||
/* use only second item and terminator */
|
||||
GPUNodeStack tmp_in[2];
|
||||
memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
|
||||
memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
|
||||
GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
|
||||
if (node->custom2 & SHD_MATH_CLAMP) {
|
||||
float min[3] = {0.0f, 0.0f, 0.0f};
|
||||
float max[3] = {1.0f, 1.0f, 1.0f};
|
||||
GPU_link(mat, "clamp_value", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
{
|
||||
bNodeSocket *sock = BLI_findlink(&node->inputs, 1);
|
||||
nodeSetSocketAvailability(sock,
|
||||
!ELEM(node->custom1,
|
||||
NODE_MATH_SQRT,
|
||||
NODE_MATH_CEIL,
|
||||
NODE_MATH_SINE,
|
||||
NODE_MATH_ROUND,
|
||||
NODE_MATH_FLOOR,
|
||||
NODE_MATH_COSINE,
|
||||
NODE_MATH_ARCSINE,
|
||||
NODE_MATH_TANGENT,
|
||||
NODE_MATH_ABSOLUTE,
|
||||
NODE_MATH_FRACTION,
|
||||
NODE_MATH_ARCCOSINE,
|
||||
NODE_MATH_ARCTANGENT));
|
||||
}
|
||||
|
||||
void register_node_type_sh_math(void)
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
@ -373,9 +104,8 @@ void register_node_type_sh_math(void)
|
|||
sh_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
|
||||
node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
|
||||
node_type_label(&ntype, node_math_label);
|
||||
node_type_storage(&ntype, "", NULL, NULL);
|
||||
node_type_exec(&ntype, NULL, NULL, node_shader_exec_math);
|
||||
node_type_gpu(&ntype, gpu_shader_math);
|
||||
node_type_update(&ntype, node_shader_update_math);
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
|
|
@ -46,10 +46,10 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
case NODE_MATH_ADD:
|
||||
*out = in0 + in1;
|
||||
break;
|
||||
case NODE_MATH_SUB:
|
||||
case NODE_MATH_SUBTRACT:
|
||||
*out = in0 - in1;
|
||||
break;
|
||||
case NODE_MATH_MUL:
|
||||
case NODE_MATH_MULTIPLY:
|
||||
*out = in0 * in1;
|
||||
break;
|
||||
case NODE_MATH_DIVIDE: {
|
||||
|
@ -62,19 +62,19 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_SIN: {
|
||||
case NODE_MATH_SINE: {
|
||||
*out = sinf(in0);
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_COS: {
|
||||
case NODE_MATH_COSINE: {
|
||||
*out = cosf(in0);
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_TAN: {
|
||||
case NODE_MATH_TANGENT: {
|
||||
*out = tanf(in0);
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ASIN: {
|
||||
case NODE_MATH_ARCSINE: {
|
||||
/* Can't do the impossible... */
|
||||
if (in0 <= 1 && in0 >= -1) {
|
||||
*out = asinf(in0);
|
||||
|
@ -84,7 +84,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ACOS: {
|
||||
case NODE_MATH_ARCCOSINE: {
|
||||
/* Can't do the impossible... */
|
||||
if (in0 <= 1 && in0 >= -1) {
|
||||
*out = acosf(in0);
|
||||
|
@ -94,11 +94,11 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_ATAN: {
|
||||
case NODE_MATH_ARCTANGENT: {
|
||||
*out = atan(in0);
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_POW: {
|
||||
case NODE_MATH_POWER: {
|
||||
/* Only raise negative numbers by full integers */
|
||||
if (in0 >= 0) {
|
||||
out[0] = pow(in0, in1);
|
||||
|
@ -114,7 +114,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_LOG: {
|
||||
case NODE_MATH_LOGARITHM: {
|
||||
/* Don't want any imaginary numbers... */
|
||||
if (in0 > 0 && in1 > 0) {
|
||||
*out = log(in0) / log(in1);
|
||||
|
@ -124,7 +124,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_MIN: {
|
||||
case NODE_MATH_MINIMUM: {
|
||||
if (in0 < in1) {
|
||||
*out = in0;
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NODE_MATH_MAX: {
|
||||
case NODE_MATH_MAXIMUM: {
|
||||
if (in0 > in1) {
|
||||
*out = in0;
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
break;
|
||||
}
|
||||
|
||||
case NODE_MATH_LESS: {
|
||||
case NODE_MATH_LESS_THAN: {
|
||||
if (in0 < in1) {
|
||||
*out = 1.0f;
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
break;
|
||||
}
|
||||
|
||||
case NODE_MATH_GREATER: {
|
||||
case NODE_MATH_GREATER_THAN: {
|
||||
if (in0 > in1) {
|
||||
*out = 1.0f;
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
break;
|
||||
}
|
||||
|
||||
case NODE_MATH_MOD: {
|
||||
case NODE_MATH_MODULO: {
|
||||
if (in1 == 0.0f) {
|
||||
*out = 0.0f;
|
||||
}
|
||||
|
@ -177,12 +177,12 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
break;
|
||||
}
|
||||
|
||||
case NODE_MATH_ABS: {
|
||||
case NODE_MATH_ABSOLUTE: {
|
||||
*out = fabsf(in0);
|
||||
break;
|
||||
}
|
||||
|
||||
case NODE_MATH_ATAN2: {
|
||||
case NODE_MATH_ARCTAN2: {
|
||||
*out = atan2(in0, in1);
|
||||
break;
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
|
|||
break;
|
||||
}
|
||||
|
||||
case NODE_MATH_FRACT: {
|
||||
case NODE_MATH_FRACTION: {
|
||||
*out = in0 - floorf(in0);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue