Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/shader/nodes/node_shader_math.c
| Show All 25 Lines | |||||
| /* **************** SCALAR MATH ******************** */ | /* **************** SCALAR MATH ******************** */ | ||||
| static bNodeSocketTemplate sh_node_math_in[] = { | static bNodeSocketTemplate sh_node_math_in[] = { | ||||
| {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, | {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, | ||||
| {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, | {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, | ||||
| {-1, 0, ""}}; | {-1, 0, ""}}; | ||||
| static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}}; | 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, | static int gpu_shader_math(GPUMaterial *mat, | ||||
| bNode *node, | bNode *node, | ||||
| bNodeExecData *UNUSED(execdata), | bNodeExecData *UNUSED(execdata), | ||||
| GPUNodeStack *in, | GPUNodeStack *in, | ||||
| GPUNodeStack *out) | GPUNodeStack *out) | ||||
| { | { | ||||
| static const char *names[] = { | static const char *names[] = { | ||||
| "math_add", "math_subtract", "math_multiply", "math_divide", "math_sine", | [NODE_MATH_ADD] = "math_add", | ||||
| "math_cosine", "math_tangent", "math_asin", "math_acos", "math_atan", | [NODE_MATH_SUBTRACT] = "math_subtract", | ||||
| "math_pow", "math_log", "math_min", "math_max", "math_round", | [NODE_MATH_MULTIPLY] = "math_multiply", | ||||
| "math_less_than", "math_greater_than", "math_modulo", "math_abs", "math_atan2", | [NODE_MATH_DIVIDE] = "math_divide", | ||||
| "math_floor", "math_ceil", "math_fract", "math_sqrt", | |||||
| [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); | 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; | |||||
| } | |||||
| if (node->custom2 & SHD_MATH_CLAMP) { | if (node->custom2 & SHD_MATH_CLAMP) { | ||||
| float min[3] = {0.0f, 0.0f, 0.0f}; | float min[3] = {0.0f, 0.0f, 0.0f}; | ||||
| float max[3] = {1.0f, 1.0f, 1.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); | GPU_link(mat, "clamp_value", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link); | ||||
| } | } | ||||
| return 1; | 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) | void register_node_type_sh_math(void) | ||||
| { | { | ||||
| static bNodeType ntype; | static bNodeType ntype; | ||||
| sh_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0); | 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_socket_templates(&ntype, sh_node_math_in, sh_node_math_out); | ||||
| node_type_label(&ntype, node_math_label); | 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_gpu(&ntype, gpu_shader_math); | ||||
| node_type_update(&ntype, node_shader_update_math); | |||||
| nodeRegisterType(&ntype); | nodeRegisterType(&ntype); | ||||
| } | } | ||||