diff options
32 files changed, 968 insertions, 307 deletions
diff --git a/.clang-format b/.clang-format index bbbe3f1bac4..b81403c46ce 100644 --- a/.clang-format +++ b/.clang-format @@ -224,7 +224,9 @@ ForEachMacros: - LISTBASE_CIRCULAR_BACKWARD_BEGIN - LISTBASE_CIRCULAR_FORWARD_BEGIN - LISTBASE_FOREACH + - LISTBASE_FOREACH_BACKWARD - LISTBASE_FOREACH_MUTABLE + - LISTBASE_FOREACH_BACKWARD_MUTABLE - MAN2D_ITER_AXES_BEGIN - MAN_ITER_AXES_BEGIN - NODE_INSTANCE_HASH_ITER diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index d38a97dc4ea..047cc82dbfc 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -1481,8 +1481,8 @@ void BlenderSession::update_resumable_tile_manager(int num_samples) /* Round after doing the multiplications with num_chunks and num_samples_per_chunk * to allow for many small chunks. */ - int rounded_range_start_sample = (int)floor(range_start_sample + 0.5f); - int rounded_range_num_samples = max((int)floor(range_num_samples + 0.5f), 1); + int rounded_range_start_sample = (int)floorf(range_start_sample + 0.5f); + int rounded_range_num_samples = max((int)floorf(range_num_samples + 0.5f), 1); /* Make sure we don't overshoot. */ if (rounded_range_start_sample + rounded_range_num_samples > num_samples) { diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 626a1dad7db..322a1771786 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -333,9 +333,9 @@ static ShaderNode *add_node(Scene *scene, } else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) { BL::ShaderNodeVectorMath b_vector_math_node(b_node); - VectorMathNode *vmath = new VectorMathNode(); - vmath->type = (NodeVectorMath)b_vector_math_node.operation(); - node = vmath; + VectorMathNode *vector_math_node = new VectorMathNode(); + vector_math_node->type = (NodeVectorMathType)b_vector_math_node.operation(); + node = vector_math_node; } else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) { BL::ShaderNodeVectorTransform b_vector_transform_node(b_node); diff --git a/intern/cycles/kernel/shaders/node_vector_math.osl b/intern/cycles/kernel/shaders/node_vector_math.osl index 10bb0c7283c..fd5e27aa144 100644 --- a/intern/cycles/kernel/shaders/node_vector_math.osl +++ b/intern/cycles/kernel/shaders/node_vector_math.osl @@ -16,34 +16,97 @@ #include "stdosl.h" +float safe_divide(float a, float b) +{ + return (b != 0.0) ? a / b : 0.0; +} + +vector safe_divide(vector a, vector b) +{ + return vector((b[0] != 0.0) ? a[0] / b[0] : 0.0, + (b[1] != 0.0) ? a[1] / b[1] : 0.0, + (b[2] != 0.0) ? a[2] / b[2] : 0.0); +} + +vector project(vector v, vector v_proj) +{ + float lenSquared = dot(v_proj, v_proj); + return (lenSquared != 0.0) ? (dot(v, v_proj) / lenSquared) * v_proj : vector(0.0); +} + +vector snap(vector a, vector b) +{ + return floor(safe_divide(a, b)) * b; +} + shader node_vector_math(string type = "add", vector Vector1 = vector(0.0, 0.0, 0.0), vector Vector2 = vector(0.0, 0.0, 0.0), + float Scale = 1.0, output float Value = 0.0, output vector Vector = vector(0.0, 0.0, 0.0)) { if (type == "add") { Vector = Vector1 + Vector2; - Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0; } else if (type == "subtract") { Vector = Vector1 - Vector2; - Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0; } - else if (type == "average") { - Value = length(Vector1 + Vector2); - Vector = normalize(Vector1 + Vector2); + else if (type == "multiply") { + Vector = Vector1 * Vector2; + } + else if (type == "divide") { + Vector = safe_divide(Vector1, Vector2); + } + else if (type == "cross_product") { + Vector = cross(Vector1, Vector2); + } + else if (type == "project") { + Vector = project(Vector1, Vector2); + } + else if (type == "reflect") { + Vector = reflect(Vector1, normalize(Vector2)); } else if (type == "dot_product") { Value = dot(Vector1, Vector2); } - else if (type == "cross_product") { - vector c = cross(Vector1, Vector2); - Value = length(c); - Vector = normalize(c); + else if (type == "distance") { + Value = distance(Vector1, Vector2); } - else if (type == "normalize") { + else if (type == "length") { Value = length(Vector1); + } + else if (type == "scale") { + Vector = Vector1 * Scale; + } + else if (type == "normalize") { Vector = normalize(Vector1); } + else if (type == "snap") { + Vector = snap(Vector1, Vector2); + } + else if (type == "floor") { + Vector = floor(Vector1); + } + else if (type == "ceil") { + Vector = ceil(Vector1); + } + else if (type == "modulo") { + Vector = mod(Vector1, Vector2); + } + else if (type == "fraction") { + Vector = Vector1 - floor(Vector1); + } + else if (type == "absolute") { + Vector = abs(Vector1); + } + else if (type == "minimum") { + Vector = min(Vector1, Vector2); + } + else if (type == "maximum") { + Vector = max(Vector1, Vector2); + } + else { + warning("%s", "Unknown vector math operator!"); + } } diff --git a/intern/cycles/kernel/svm/svm_math.h b/intern/cycles/kernel/svm/svm_math.h index 402290d7218..c577a7f13c7 100644 --- a/intern/cycles/kernel/svm/svm_math.h +++ b/intern/cycles/kernel/svm/svm_math.h @@ -37,25 +37,29 @@ ccl_device void svm_node_math(KernelGlobals *kg, ccl_device void svm_node_vector_math(KernelGlobals *kg, ShaderData *sd, float *stack, - uint itype, - uint v1_offset, - uint v2_offset, + uint type, + uint inputs_stack_offsets, + uint outputs_stack_offsets, int *offset) { - NodeVectorMath type = (NodeVectorMath)itype; - float3 v1 = stack_load_float3(stack, v1_offset); - float3 v2 = stack_load_float3(stack, v2_offset); - float f; - float3 v; + uint value_stack_offset, vector_stack_offset; + uint a_stack_offset, b_stack_offset, scale_stack_offset; + decode_node_uchar4( + inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &scale_stack_offset, NULL); + decode_node_uchar4(outputs_stack_offsets, &value_stack_offset, &vector_stack_offset, NULL, NULL); - svm_vector_math(&f, &v, type, v1, v2); + float3 a = stack_load_float3(stack, a_stack_offset); + float3 b = stack_load_float3(stack, b_stack_offset); + float scale = stack_load_float(stack, scale_stack_offset); - uint4 node1 = read_node(kg, offset); + float value; + float3 vector; + svm_vector_math(&value, &vector, (NodeVectorMathType)type, a, b, scale); - if (stack_valid(node1.y)) - stack_store_float(stack, node1.y, f); - if (stack_valid(node1.z)) - stack_store_float3(stack, node1.z, v); + if (stack_valid(value_stack_offset)) + stack_store_float(stack, value_stack_offset, value); + if (stack_valid(vector_stack_offset)) + stack_store_float3(stack, vector_stack_offset, vector); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h index d8804226487..c87ca0defa7 100644 --- a/intern/cycles/kernel/svm/svm_math_util.h +++ b/intern/cycles/kernel/svm/svm_math_util.h @@ -16,38 +16,73 @@ CCL_NAMESPACE_BEGIN -ccl_device float average_fac(float3 v) -{ - return (fabsf(v.x) + fabsf(v.y) + fabsf(v.z)) / 3.0f; -} - ccl_device void svm_vector_math( - float *Fac, float3 *Vector, NodeVectorMath type, float3 Vector1, float3 Vector2) + float *value, float3 *vector, NodeVectorMathType type, float3 a, float3 b, float scale) { - if (type == NODE_VECTOR_MATH_ADD) { - *Vector = Vector1 + Vector2; - *Fac = average_fac(*Vector); - } - else if (type == NODE_VECTOR_MATH_SUBTRACT) { - *Vector = Vector1 - Vector2; - *Fac = average_fac(*Vector); - } - else if (type == NODE_VECTOR_MATH_AVERAGE) { - *Vector = safe_normalize_len(Vector1 + Vector2, Fac); - } - else if (type == NODE_VECTOR_MATH_DOT_PRODUCT) { - *Fac = dot(Vector1, Vector2); - *Vector = make_float3(0.0f, 0.0f, 0.0f); - } - else if (type == NODE_VECTOR_MATH_CROSS_PRODUCT) { - *Vector = safe_normalize_len(cross(Vector1, Vector2), Fac); - } - else if (type == NODE_VECTOR_MATH_NORMALIZE) { - *Vector = safe_normalize_len(Vector1, Fac); - } - else { - *Fac = 0.0f; - *Vector = make_float3(0.0f, 0.0f, 0.0f); + switch (type) { + case NODE_VECTOR_MATH_ADD: + *vector = a + b; + break; + case NODE_VECTOR_MATH_SUBTRACT: + *vector = a - b; + break; + case NODE_VECTOR_MATH_MULTIPLY: + *vector = a * b; + break; + case NODE_VECTOR_MATH_DIVIDE: + *vector = safe_divide_float3_float3(a, b); + break; + case NODE_VECTOR_MATH_CROSS_PRODUCT: + *vector = cross(a, b); + break; + case NODE_VECTOR_MATH_PROJECT: + *vector = project(a, b); + break; + case NODE_VECTOR_MATH_REFLECT: + *vector = reflect(a, b); + break; + case NODE_VECTOR_MATH_DOT_PRODUCT: + *value = dot(a, b); + break; + case NODE_VECTOR_MATH_DISTANCE: + *value = distance(a, b); + break; + case NODE_VECTOR_MATH_LENGTH: + *value = len(a); + break; + case NODE_VECTOR_MATH_SCALE: + *vector = a * scale; + break; + case NODE_VECTOR_MATH_NORMALIZE: + *vector = safe_normalize(a); + break; + case NODE_VECTOR_MATH_SNAP: + *vector = floor(safe_divide_float3_float3(a, b)) * b; + break; + case NODE_VECTOR_MATH_FLOOR: + *vector = floor(a); + break; + case NODE_VECTOR_MATH_CEIL: + *vector = ceil(a); + break; + case NODE_VECTOR_MATH_MODULO: + *vector = make_float3(safe_modulo(a.x, b.x), safe_modulo(a.y, b.y), safe_modulo(a.z, b.z)); + break; + case NODE_VECTOR_MATH_FRACTION: + *vector = fract(a); + break; + case NODE_VECTOR_MATH_ABSOLUTE: + *vector = fabs(a); + break; + case NODE_VECTOR_MATH_MINIMUM: + *vector = min(a, b); + break; + case NODE_VECTOR_MATH_MAXIMUM: + *vector = max(a, b); + break; + default: + *vector = make_float3(0.0f, 0.0f, 0.0f); + *value = 0.0f; } } diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 6b0d10adc74..884ad76a9b7 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -271,14 +271,31 @@ typedef enum NodeMathType { NODE_MATH_SQRT, } NodeMathType; -typedef enum NodeVectorMath { +typedef enum NodeVectorMathType { NODE_VECTOR_MATH_ADD, NODE_VECTOR_MATH_SUBTRACT, - NODE_VECTOR_MATH_AVERAGE, - NODE_VECTOR_MATH_DOT_PRODUCT, + NODE_VECTOR_MATH_MULTIPLY, + NODE_VECTOR_MATH_DIVIDE, + NODE_VECTOR_MATH_CROSS_PRODUCT, - NODE_VECTOR_MATH_NORMALIZE -} NodeVectorMath; + NODE_VECTOR_MATH_PROJECT, + NODE_VECTOR_MATH_REFLECT, + NODE_VECTOR_MATH_DOT_PRODUCT, + + NODE_VECTOR_MATH_DISTANCE, + NODE_VECTOR_MATH_LENGTH, + NODE_VECTOR_MATH_SCALE, + NODE_VECTOR_MATH_NORMALIZE, + + NODE_VECTOR_MATH_SNAP, + NODE_VECTOR_MATH_FLOOR, + NODE_VECTOR_MATH_CEIL, + NODE_VECTOR_MATH_MODULO, + NODE_VECTOR_MATH_FRACTION, + NODE_VECTOR_MATH_ABSOLUTE, + NODE_VECTOR_MATH_MINIMUM, + NODE_VECTOR_MATH_MAXIMUM, +} NodeVectorMathType; typedef enum NodeVectorTransformType { NODE_VECTOR_TRANSFORM_TYPE_VECTOR, diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index 73893921500..b906357b7b5 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -124,7 +124,7 @@ BakeData *BakeManager::init(const int object, const size_t tri_offset, const siz void BakeManager::set_shader_limit(const size_t x, const size_t y) { m_shader_limit = x * y; - m_shader_limit = (size_t)pow(2, ceil(log(m_shader_limit) / log(2))); + m_shader_limit = (size_t)pow(2, std::ceil(log(m_shader_limit) / log(2))); } bool BakeManager::bake(Device *device, diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp index d6fdc49434e..851d4b71df8 100644 --- a/intern/cycles/render/constant_fold.cpp +++ b/intern/cycles/render/constant_fold.cpp @@ -359,10 +359,11 @@ void ConstantFolder::fold_math(NodeMathType type) const } } -void ConstantFolder::fold_vector_math(NodeVectorMath type) const +void ConstantFolder::fold_vector_math(NodeVectorMathType type) const { ShaderInput *vector1_in = node->input("Vector1"); ShaderInput *vector2_in = node->input("Vector2"); + ShaderInput *scale_in = node->input("Scale"); switch (type) { case NODE_VECTOR_MATH_ADD: @@ -380,6 +381,27 @@ void ConstantFolder::fold_vector_math(NodeVectorMath type) const try_bypass_or_make_constant(vector1_in); } break; + case NODE_VECTOR_MATH_MULTIPLY: + /* X * 0 == 0 * X == 0 */ + if (is_zero(vector1_in) || is_zero(vector2_in)) { + make_zero(); + } /* X * 1 == 1 * X == X */ + else if (is_one(vector1_in)) { + try_bypass_or_make_constant(vector2_in); + } + else if (is_one(vector2_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; + case NODE_VECTOR_MATH_DIVIDE: + /* X / 0 == 0 / X == 0 */ + if (is_zero(vector1_in) || is_zero(vector2_in)) { + make_zero(); + } /* X / 1 == X */ + else if (is_one(vector2_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; case NODE_VECTOR_MATH_DOT_PRODUCT: case NODE_VECTOR_MATH_CROSS_PRODUCT: /* X * 0 == 0 * X == 0 */ @@ -387,6 +409,21 @@ void ConstantFolder::fold_vector_math(NodeVectorMath type) const make_zero(); } break; + case NODE_VECTOR_MATH_LENGTH: + case NODE_VECTOR_MATH_ABSOLUTE: + if (is_zero(vector1_in)) { + make_zero(); + } + break; + case NODE_VECTOR_MATH_SCALE: + /* X * 0 == 0 * X == 0 */ + if (is_zero(vector1_in) || is_zero(scale_in)) { + make_zero(); + } /* X * 1 == X */ + else if (is_one(scale_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; default: break; } diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h index d223fd86197..881636a9fe1 100644 --- a/intern/cycles/render/constant_fold.h +++ b/intern/cycles/render/constant_fold.h @@ -65,7 +65,7 @@ class ConstantFolder { /* Specific nodes. */ void fold_mix(NodeMix type, bool clamp) const; void fold_math(NodeMathType type) const; - void fold_vector_math(NodeVectorMath type) const; + void fold_vector_math(NodeVectorMathType type) const; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 642f7beaf3c..8c8bb559c30 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -163,8 +163,10 @@ void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_ou } if (type == NORMAL) { - compiler.add_node(NODE_VECTOR_MATH, NODE_VECTOR_MATH_NORMALIZE, offset_out, offset_out); - compiler.add_node(NODE_VECTOR_MATH, SVM_STACK_INVALID, offset_out); + compiler.add_node(NODE_VECTOR_MATH, + NODE_VECTOR_MATH_NORMALIZE, + compiler.encode_uchar4(offset_out, offset_out, offset_out), + compiler.encode_uchar4(SVM_STACK_INVALID, offset_out)); } } @@ -5496,14 +5498,32 @@ NODE_DEFINE(VectorMathNode) static NodeEnum type_enum; type_enum.insert("add", NODE_VECTOR_MATH_ADD); type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT); - type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE); - type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT); + type_enum.insert("multiply", NODE_VECTOR_MATH_MULTIPLY); + type_enum.insert("divide", NODE_VECTOR_MATH_DIVIDE); + type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT); + type_enum.insert("project", NODE_VECTOR_MATH_PROJECT); + type_enum.insert("reflect", NODE_VECTOR_MATH_REFLECT); + type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT); + + type_enum.insert("distance", NODE_VECTOR_MATH_DISTANCE); + type_enum.insert("length", NODE_VECTOR_MATH_LENGTH); + type_enum.insert("scale", NODE_VECTOR_MATH_SCALE); type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE); + + type_enum.insert("snap", NODE_VECTOR_MATH_SNAP); + type_enum.insert("floor", NODE_VECTOR_MATH_FLOOR); + type_enum.insert("ceil", NODE_VECTOR_MATH_CEIL); + type_enum.insert("modulo", NODE_VECTOR_MATH_MODULO); + type_enum.insert("fraction", NODE_VECTOR_MATH_FRACTION); + type_enum.insert("absolute", NODE_VECTOR_MATH_ABSOLUTE); + type_enum.insert("minimum", NODE_VECTOR_MATH_MINIMUM); + type_enum.insert("maximum", NODE_VECTOR_MATH_MAXIMUM); SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD); SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f)); SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); SOCKET_OUT_FLOAT(value, "Value"); SOCKET_OUT_VECTOR(vector, "Vector"); @@ -5521,8 +5541,7 @@ void VectorMathNode::constant_fold(const ConstantFolder &folder) float3 vector; if (folder.all_inputs_constant()) { - svm_vector_math(&value, &vector, type, vector1, vector2); - + svm_vector_math(&value, &vector, type, vector1, vector2, scale); if (folder.output == output("Value")) { folder.make_constant(value); } @@ -5539,15 +5558,21 @@ void VectorMathNode::compile(SVMCompiler &compiler) { ShaderInput *vector1_in = input("Vector1"); ShaderInput *vector2_in = input("Vector2"); + ShaderInput *scale_in = input("Scale"); ShaderOutput *value_out = output("Value"); ShaderOutput *vector_out = output("Vector"); - compiler.add_node(NODE_VECTOR_MATH, - type, - compiler.stack_assign(vector1_in), - compiler.stack_assign(vector2_in)); + int vector1_stack_offset = compiler.stack_assign(vector1_in); + int vector2_stack_offset = compiler.stack_assign(vector2_in); + int scale_stack_offset = compiler.stack_assign(scale_in); + int value_stack_offset = compiler.stack_assign_if_linked(value_out); + int vector_stack_offset = compiler.stack_assign_if_linked(vector_out); + compiler.add_node( - NODE_VECTOR_MATH, compiler.stack_assign(value_out), compiler.stack_assign(vector_out)); + NODE_VECTOR_MATH, + type, + compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, scale_stack_offset), + compiler.encode_uchar4(value_stack_offset, vector_stack_offset)); } void VectorMathNode::compile(OSLCompiler &compiler) diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 514ab3db8eb..417623c7562 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -1292,7 +1292,8 @@ class VectorMathNode : public ShaderNode { float3 vector1; float3 vector2; - NodeVectorMath type; + float scale; + NodeVectorMathType type; }; class VectorTransformNode : public ShaderNode { diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index fb96be5065b..914b408911e 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -323,8 +323,8 @@ void QuadDice::dice(SubPatch &sub, EdgeFactors &ef) float S = 1.0f; #endif - Mu = max((int)ceil(S * Mu), 2); // XXX handle 0 & 1? - Mv = max((int)ceil(S * Mv), 2); // XXX handle 0 & 1? + Mu = max((int)ceilf(S * Mu), 2); // XXX handle 0 & 1? + Mv = max((int)ceilf(S * Mv), 2); // XXX handle 0 & 1? /* reserve space for new verts */ int offset = params.mesh->verts.size(); diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp index e6603632ba7..e5b85fcfd60 100644 --- a/intern/cycles/subd/subd_split.cpp +++ b/intern/cycles/subd/subd_split.cpp @@ -80,9 +80,9 @@ int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend) Plast = P; } - int tmin = (int)ceil(Lsum / params.dicing_rate); - int tmax = (int)ceil((params.test_steps - 1) * Lmax / - params.dicing_rate); // XXX paper says N instead of N-1, seems wrong? + int tmin = (int)ceilf(Lsum / params.dicing_rate); + int tmax = (int)ceilf((params.test_steps - 1) * Lmax / + params.dicing_rate); // XXX paper says N instead of N-1, seems wrong? if (tmax - tmin > params.split_threshold) return DSPLIT_NON_UNIFORM; @@ -99,7 +99,7 @@ void DiagSplit::partition_edge( *t1 = T(patch, *P, Pend); } else { - int I = (int)floor((float)t * 0.5f); + int I = (int)floorf((float)t * 0.5f); *P = interp(Pstart, Pend, (t == 0) ? 0 : I / (float)t); /* XXX is t faces or verts */ *t0 = I; *t1 = t - I; diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp index 7d4b600350b..ca93f8b02d0 100644 --- a/intern/cycles/test/render_graph_finalize_test.cpp +++ b/intern/cycles/test/render_graph_finalize_test.cpp @@ -1163,21 +1163,14 @@ TEST_F(RenderGraph, constant_fold_part_math_pow_1) TEST_F(RenderGraph, constant_fold_vector_math) { EXPECT_ANY_MESSAGE(log); - CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Value to constant (1)."); CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Vector to constant (3, 0, 0)."); - CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_float::value_float to constant (1)."); - CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (2)."); - CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (2, 2, 2)."); builder .add_node(ShaderNodeBuilder<VectorMathNode>("VectorMath") .set(&VectorMathNode::type, NODE_VECTOR_MATH_SUBTRACT) .set("Vector1", make_float3(1.3f, 0.5f, 0.7f)) .set("Vector2", make_float3(-1.7f, 0.5f, 0.7f))) - .add_node(ShaderNodeBuilder<MathNode>("Math").set(&MathNode::type, NODE_MATH_ADD)) - .add_connection("VectorMath::Vector", "Math::Value1") - .add_connection("VectorMath::Value", "Math::Value2") - .output_color("Math::Value"); + .output_color("VectorMath::Vector"); graph.finalize(scene); } @@ -1187,7 +1180,7 @@ TEST_F(RenderGraph, constant_fold_vector_math) * Includes 2 tests: constant on each side. */ static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder, - NodeVectorMath type, + NodeVectorMathType type, float3 constval) { builder @@ -1241,22 +1234,6 @@ TEST_F(RenderGraph, constant_fold_part_vecmath_sub_0) } /* - * Tests: partial folding for Vector Math Dot Product with known 0. - */ -TEST_F(RenderGraph, constant_fold_part_vecmath_dot_0) -{ - EXPECT_ANY_MESSAGE(log); - /* X * 0 == 0 * X == X */ - CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0)."); - CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0)."); - CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0)."); - CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode."); - - build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_DOT_PRODUCT, make_float3(0, 0, 0)); - graph.finalize(scene); -} - -/* * Tests: partial folding for Vector Math Cross Product with known 0. */ TEST_F(RenderGraph, constant_fold_part_vecmath_cross_0) diff --git a/intern/cycles/util/util_math_float3.h b/intern/cycles/util/util_math_float3.h index 554b7408148..0d7588da690 100644 --- a/intern/cycles/util/util_math_float3.h +++ b/intern/cycles/util/util_math_float3.h @@ -47,6 +47,7 @@ ccl_device_inline float3 operator/=(float3 &a, float f); ccl_device_inline bool operator==(const float3 &a, const float3 &b); ccl_device_inline bool operator!=(const float3 &a, const float3 &b); +ccl_device_inline float distance(const float3 &a, const float3 &b); ccl_device_inline float dot(const float3 &a, const float3 &b); ccl_device_inline float dot_xy(const float3 &a, const float3 &b); ccl_device_inline float3 cross(const float3 &a, const float3 &b); @@ -58,6 +59,9 @@ ccl_device_inline float3 fabs(const float3 &a); ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t); ccl_device_inline float3 rcp(const float3 &a); ccl_device_inline float3 sqrt(const float3 &a); +ccl_device_inline float3 floor(const float3 &a); +ccl_device_inline float3 ceil(const float3 &a); +ccl_device_inline float3 fract(const float3 &a); #endif /* !__KERNEL_OPENCL__ */ ccl_device_inline float min3(float3 a); @@ -65,10 +69,15 @@ ccl_device_inline float max3(float3 a); ccl_device_inline float len(const float3 a); ccl_device_inline float len_squared(const float3 a); +ccl_device_inline float3 reflect(const float3 incident, const float3 normal); +ccl_device_inline float3 project(const float3 v, const float3 v_proj); + ccl_device_inline float3 saturate3(float3 a); ccl_device_inline float3 safe_normalize(const float3 a); ccl_device_inline float3 normalize_len(const float3 a, float *t); ccl_device_inline float3 safe_normalize_len(const float3 a, float *t); +ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b); +ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b); ccl_device_inline float3 interp(float3 a, float3 b, float t); ccl_device_inline float3 sqr3(float3 a); @@ -205,6 +214,11 @@ ccl_device_inline bool operator!=(const float3 &a, const float3 &b) return !(a == b); } +ccl_device_inline float distance(const float3 &a, const float3 &b) +{ + return len(a - b); +} + ccl_device_inline float dot(const float3 &a, const float3 &b) { # if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) @@ -281,6 +295,29 @@ ccl_device_inline float3 sqrt(const float3 &a) # endif } +ccl_device_inline float3 floor(const float3 &a) +{ +# ifdef __KERNEL_SSE__ + return float3(_mm_floor_ps(a)); +# else + return make_float3(floorf(a.x), floorf(a.y), floorf(a.z)); +# endif +} + +ccl_device_inline float3 ceil(const float3 &a) +{ +# ifdef __KERNEL_SSE__ + return float3(_mm_ceil_ps(a)); +# else + return make_float3(ceilf(a.x), ceilf(a.y), ceilf(a.z)); +# endif +} + +ccl_device_inline float3 fract(const float3 &a) +{ + return a - floor(a); +} + ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t) { return a + t * (b - a); @@ -321,6 +358,19 @@ ccl_device_inline float len_squared(const float3 a) return dot(a, a); } +ccl_device_inline float3 reflect(const float3 incident, const float3 normal) +{ + float3 unit_normal = normalize(normal); + return incident - 2.0f * unit_normal * dot(incident, unit_normal); +} + +ccl_device_inline float3 project(const float3 v, const float3 v_proj) +{ + float len_squared = dot(v_proj, v_proj); + return (len_squared != 0.0f) ? (dot(v, v_proj) / len_squared) * v_proj : + make_float3(0.0f, 0.0f, 0.0f); +} + ccl_device_inline float3 saturate3(float3 a) { return make_float3(saturate(a.x), saturate(a.y), saturate(a.z)); @@ -345,6 +395,18 @@ ccl_device_inline float3 safe_normalize_len(const float3 a, float *t) return (*t != 0.0f) ? a / (*t) : a; } +ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b) +{ + return make_float3((b.x != 0.0f) ? a.x / b.x : 0.0f, + (b.y != 0.0f) ? a.y / b.y : 0.0f, + (b.z != 0.0f) ? a.z / b.z : 0.0f); +} + +ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b) +{ + return (b != 0.0f) ? a / b : make_float3(0.0f, 0.0f, 0.0f); +} + ccl_device_inline float3 interp(float3 a, float3 b, float t) { return a + t * (b - a); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 7d427cb7799..1b7debe4496 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -895,7 +895,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, #define SH_NODE_CURVE_RGB 111 #define SH_NODE_CAMERA 114 #define SH_NODE_MATH 115 -#define SH_NODE_VECT_MATH 116 +#define SH_NODE_VECTOR_MATH 116 #define SH_NODE_SQUEEZE 117 //#define SH_NODE_MATERIAL_EXT 118 #define SH_NODE_INVERT 119 diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index d64a5a33ef1..7e455ba742a 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3232,11 +3232,6 @@ void ntreeTagUsedSockets(bNodeTree *ntree) } for (link = ntree->links.first; link; link = link->next) { - /* link is unused if either side is disabled */ - if ((link->fromsock->flag & SOCK_UNAVAIL) || (link->tosock->flag & SOCK_UNAVAIL)) { - continue; - } - link->fromsock->flag |= SOCK_IN_USE; link->tosock->flag |= SOCK_IN_USE; } diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index c235a72e7e4..b8b62dd3451 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -171,12 +171,21 @@ struct LinkData *BLI_genericNodeN(void *data); #define LISTBASE_FOREACH(type, var, list) \ for (type var = (type)((list)->first); var != NULL; var = (type)(((Link *)(var))->next)) +#define LISTBASE_FOREACH_BACKWARD(type, var, list) \ + for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev)) + /** A version of #LISTBASE_FOREACH that supports removing the item we're looping over. */ #define LISTBASE_FOREACH_MUTABLE(type, var, list) \ for (type var = (type)((list)->first), *var##_iter_next; \ ((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \ var = var##_iter_next) +/** A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over. */ +#define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \ + for (type var = (type)((list)->last), *var##_iter_prev; \ + ((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \ + var = var##_iter_prev) + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index 10f24cff61b..a3e9b8dc206 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -45,6 +45,11 @@ #include "BLO_readfile.h" #include "readfile.h" +static bool socket_is_used(bNodeSocket *sock) +{ + return sock->flag & SOCK_IN_USE; +} + static float *cycles_node_socket_float_value(bNodeSocket *socket) { bNodeSocketValueFloat *socket_data = socket->default_value; @@ -57,6 +62,12 @@ static float *cycles_node_socket_rgba_value(bNodeSocket *socket) return socket_data->value; } +static float *cycles_node_socket_vector_value(bNodeSocket *socket) +{ + bNodeSocketValueVector *socket_data = socket->default_value; + return socket_data->value; +} + static IDProperty *cycles_properties_from_ID(ID *id) { IDProperty *idprop = IDP_GetProperties(id, false); @@ -426,6 +437,325 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree) } } +/* The Value output of the Vector Math node is no longer available in the Add + * and Subtract operators. Previously, this Value output was computed from the + * Vector output V as follows: + * + * Value = (abs(V.x) + abs(V.y) + abs(V.z)) / 3 + * + * Or more compactly using vector operators: + * + * Value = dot(abs(V), (1 / 3, 1 / 3, 1 / 3)) + * + * To correct this, if the Value output was used, we are going to compute + * it using the second equation by adding an absolute and a dot node, and + * then connect them appropriately. + */ +static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree) +{ + bool need_update = false; + + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_VECTOR_MATH) { + bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value"); + if (socket_is_used(sockOutValue) && + ELEM(node->custom1, NODE_VECTOR_MATH_ADD, NODE_VECTOR_MATH_SUBTRACT)) { + + bNode *absNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); + absNode->custom1 = NODE_VECTOR_MATH_ABSOLUTE; + absNode->locx = node->locx + node->width + 20.0f; + absNode->locy = node->locy; + + bNode *dotNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); + dotNode->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT; + dotNode->locx = absNode->locx + absNode->width + 20.0f; + dotNode->locy = absNode->locy; + bNodeSocket *sockDotB = BLI_findlink(&dotNode->inputs, 1); + bNodeSocket *sockDotOutValue = nodeFindSocket(dotNode, SOCK_OUT, "Value"); + copy_v3_fl(cycles_node_socket_vector_value(sockDotB), 1 / 3.0f); + + LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) { + if (link->fromsock == sockOutValue) { + nodeAddLink(ntree, dotNode, sockDotOutValue, link->tonode, link->tosock); + nodeRemLink(ntree, link); + } + } + + bNodeSocket *sockAbsA = BLI_findlink(&absNode->inputs, 0); + bNodeSocket *sockDotA = BLI_findlink(&dotNode->inputs, 0); + bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector"); + bNodeSocket *sockAbsOutVector = nodeFindSocket(absNode, SOCK_OUT, "Vector"); + + nodeAddLink(ntree, node, sockOutVector, absNode, sockAbsA); + nodeAddLink(ntree, absNode, sockAbsOutVector, dotNode, sockDotA); + + need_update = true; + } + } + } + + if (need_update) { + ntreeUpdateTree(NULL, ntree); + } +} + +/* The Vector output of the Vector Math node is no longer available in the Dot + * Product operator. Previously, this Vector was always zero initialized. To + * correct this, we zero out any socket the Vector Output was connected to. + */ +static void update_vector_math_node_dot_product_operator(bNodeTree *ntree) +{ + bool need_update = false; + + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_VECTOR_MATH) { + bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector"); + if (socket_is_used(sockOutVector) && node->custom1 == NODE_VECTOR_MATH_DOT_PRODUCT) { + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { + if (link->fromsock == sockOutVector) { + switch (link->tosock->type) { + case SOCK_FLOAT: + *cycles_node_socket_float_value(link->tosock) = 0.0f; + break; + case SOCK_VECTOR: + copy_v3_fl(cycles_node_socket_vector_value(link->tosock), 0.0f); + break; + case SOCK_RGBA: + copy_v4_fl(cycles_node_socket_rgba_value(link->tosock), 0.0f); + break; + } + nodeRemLink(ntree, link); + } + } + need_update = true; + } + } + } + + if (need_update) { + ntreeUpdateTree(NULL, ntree); + } +} + +/* Previously, the Vector output of the cross product operator was normalized. + * To correct this, a Normalize node is added to normalize the output if used. + * Moreover, the Value output was removed. This Value was equal to the length + * of the cross product. To correct this, a Length node is added if needed. + */ +static void update_vector_math_node_cross_product_operator(bNodeTree *ntree) +{ + bool need_update = false; + + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_VECTOR_MATH) { + if (node->custom1 == NODE_VECTOR_MATH_CROSS_PRODUCT) { + bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector"); + if (socket_is_used(sockOutVector)) { + bNode *normalizeNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); + normalizeNode->custom1 = NODE_VECTOR_MATH_NORMALIZE; + normalizeNode->locx = node->locx + node->width + 20.0f; + normalizeNode->locy = node->locy; + bNodeSocket *sockNormalizeOut = nodeFindSocket(normalizeNode, SOCK_OUT, "Vector"); + + LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) { + if (link->fromsock == sockOutVector) { + nodeAddLink(ntree, normalizeNode, sockNormalizeOut, link->tonode, link->tosock); + nodeRemLink(ntree, link); + } + } + bNodeSocket *sockNormalizeA = BLI_findlink(&normalizeNode->inputs, 0); + nodeAddLink(ntree, node, sockOutVector, normalizeNode, sockNormalizeA); + + need_update = true; + } + + bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value"); + if (socket_is_used(sockOutValue)) { + bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); + lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH; + lengthNode->locx = node->locx + node->width + 20.0f; + if (socket_is_used(sockOutVector)) { + lengthNode->locy = node->locy - lengthNode->height - 20.0f; + } + else { + lengthNode->locy = node->locy; + } + bNodeSocket *sockLengthOut = nodeFindSocket(lengthNode, SOCK_OUT, "Value"); + + LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) { + if (link->fromsock == sockOutValue) { + nodeAddLink(ntree, lengthNode, sockLengthOut, link->tonode, link->tosock); + nodeRemLink(ntree, link); + } + } + bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0); + nodeAddLink(ntree, node, sockOutVector, lengthNode, sockLengthA); + + need_update = true; + } + } + } + } + + if (need_update) { + ntreeUpdateTree(NULL, ntree); + } +} + +/* The Value output of the Vector Math node is no longer available in the + * Normalize operator. This Value output was equal to the length of the + * the input vector A. To correct this, we either add a Length node or + * convert the Normalize node into a Length node, depending on if the + * Vector output is needed. + */ +static void update_vector_math_node_normalize_operator(bNodeTree *ntree) +{ + bool need_update = false; + + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_VECTOR_MATH) { + bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value"); + if (node->custom1 == NODE_VECTOR_MATH_NORMALIZE && socket_is_used(sockOutValue)) { + bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector"); + if (socket_is_used(sockOutVector)) { + bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); + lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH; + lengthNode->locx = node->locx + node->width + 20.0f; + lengthNode->locy = node->locy; + bNodeSocket *sockLengthValue = nodeFindSocket(lengthNode, SOCK_OUT, "Value"); + + LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) { + if (link->fromsock == sockOutValue) { + nodeAddLink(ntree, lengthNode, sockLengthValue, link->tonode, link->tosock); + nodeRemLink(ntree, link); + } + } + bNodeSocket *sockA = BLI_findlink(&node->inputs, 0); + bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0); + if (sockA->link) { + bNodeLink *link = sockA->link; + nodeAddLink(ntree, link->fromnode, link->fromsock, lengthNode, sockLengthA); + } + else { + copy_v3_v3(cycles_node_socket_vector_value(sockLengthA), + cycles_node_socket_vector_value(sockA)); + } + + need_update = true; + } + else { + node->custom1 = NODE_VECTOR_MATH_LENGTH; + } + } + } + } + if (need_update) { + ntreeUpdateTree(NULL, ntree); + } +} + +/* The Vector Math operator types didn't have an enum, but rather, their + * values were hard coded into the code. After the enum was created and + * after more vector operators were added, the hard coded values needs + * to be remapped to their correct enum values. To fix this, we remap + * the values according to the following rules: + * + * Dot Product Operator : 3 -> 7 + * Normalize Operator : 5 -> 11 + * + * Additionally, since the Average operator was removed, it is assigned + * a value of -1 just to be identified later in the versioning code: + * + * Average Operator : 2 -> -1 + * + */ +static void update_vector_math_node_operators_enum_mapping(bNodeTree *ntree) +{ + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_VECTOR_MATH) { + switch (node->custom1) { + case 2: + node->custom1 = -1; + break; + case 3: + node->custom1 = 7; + break; + case 5: + node->custom1 = 11; + break; + } + } + } +} + +/* The Average operator is no longer available in the Vector Math node. + * The Vector output was equal to the normalized sum of input vectors while + * the Value output was equal to the length of the sum of input vectors. + * To correct this, we convert the node into an Add node and add a length + * node or a normalize node if needed. + */ +static void update_vector_math_node_average_operator(bNodeTree *ntree) +{ + bool need_update = false; + + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_VECTOR_MATH) { + /* See update_vector_math_node_operators_enum_mapping. */ + if (node->custom1 == -1) { + node->custom1 = NODE_VECTOR_MATH_ADD; + bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector"); + if (socket_is_used(sockOutVector)) { + bNode *normalizeNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); + normalizeNode->custom1 = NODE_VECTOR_MATH_NORMALIZE; + normalizeNode->locx = node->locx + node->width + 20.0f; + normalizeNode->locy = node->locy; + bNodeSocket *sockNormalizeOut = nodeFindSocket(normalizeNode, SOCK_OUT, "Vector"); + + LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) { + if (link->fromsock == sockOutVector) { + nodeAddLink(ntree, normalizeNode, sockNormalizeOut, link->tonode, link->tosock); + nodeRemLink(ntree, link); + } + } + bNodeSocket *sockNormalizeA = BLI_findlink(&normalizeNode->inputs, 0); + nodeAddLink(ntree, node, sockOutVector, normalizeNode, sockNormalizeA); + + need_update = true; + } + + bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value"); + if (socket_is_used(sockOutValue)) { + bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); + lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH; + lengthNode->locx = node->locx + node->width + 20.0f; + if (socket_is_used(sockOutVector)) { + lengthNode->locy = node->locy - lengthNode->height - 20.0f; + } + else { + lengthNode->locy = node->locy; + } + bNodeSocket *sockLengthOut = nodeFindSocket(lengthNode, SOCK_OUT, "Value"); + + LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) { + if (link->fromsock == sockOutValue) { + nodeAddLink(ntree, lengthNode, sockLengthOut, link->tonode, link->tosock); + nodeRemLink(ntree, link); + } + } + bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0); + nodeAddLink(ntree, node, sockOutVector, lengthNode, sockLengthA); + + 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. */ @@ -458,6 +788,15 @@ void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bm } } } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + update_vector_math_node_operators_enum_mapping(ntree); + } + } + FOREACH_NODETREE_END; + } } void do_versions_after_linking_cycles(Main *bmain) @@ -576,4 +915,17 @@ void do_versions_after_linking_cycles(Main *bmain) } FOREACH_NODETREE_END; } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + update_vector_math_node_add_and_subtract_operators(ntree); + update_vector_math_node_dot_product_operator(ntree); + update_vector_math_node_cross_product_operator(ntree); + update_vector_math_node_normalize_operator(ntree); + update_vector_math_node_average_operator(ntree); + } + } + FOREACH_NODETREE_END; + } } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index c3ecc34aaf4..4201fe7c289 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1220,7 +1220,7 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_MATH: ntype->draw_buttons = node_buts_math; break; - case SH_NODE_VECT_MATH: + case SH_NODE_VECTOR_MATH: ntype->draw_buttons = node_shader_buts_vect_math; break; case SH_NODE_VECT_TRANSFORM: diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 1529279ca03..1817efd35d2 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -400,46 +400,118 @@ void map_range( } } -void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval) +vec3 safe_divide(vec3 a, vec3 b) { + return vec3((b.x != 0.0) ? a.x / b.x : 0.0, + (b.y != 0.0) ? a.y / b.y : 0.0, + (b.z != 0.0) ? a.z / b.z : 0.0); +} + +void vector_math_add(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = a + b; +} + +void vector_math_subtract(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = a - b; +} + +void vector_math_multiply(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = a * b; +} + +void vector_math_divide(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = safe_divide(a, b); +} + +void vector_math_cross(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = cross(a, b); +} + +void vector_math_project(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + float lenSquared = dot(b, b); + outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0); +} + +void vector_math_reflect(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = reflect(a, normalize(b)); +} + +void vector_math_dot(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) { - outvec = v1 + v2; - outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333; + outValue = dot(a, b); } -void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval) +void vector_math_distance(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) { - outvec = v1 - v2; - outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333; + outValue = distance(a, b); } -void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval) +void vector_math_length(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) { - outvec = v1 + v2; - outval = length(outvec); - outvec = normalize(outvec); + outValue = length(a); } -void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec) + +void vector_math_scale(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = a * scale; +} + +void vector_math_normalize(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = normalize(a); +} + +void vector_math_snap(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = floor(safe_divide(a, b)) * b; +} + +void vector_math_floor(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = floor(a); +} + +void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = ceil(a); +} + +void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + math_modulo(a.x, b.x, outVector.x); + math_modulo(a.y, b.y, outVector.y); + math_modulo(a.z, b.z, outVector.z); +} + +void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) +{ + outVector = fract(a); +} + +void vector_math_absolute(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) { - outvec = strength * v1 + (1 - strength) * v2; + outVector = abs(a); } -void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval) +void vector_math_minimum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) { - outvec = vec3(0); - outval = dot(v1, v2); + outVector = min(a, b); } -void vec_math_cross(vec3 v1, vec3 v2, out vec3 outvec, out float outval) +void vector_math_maximum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue) { - outvec = cross(v1, v2); - outval = length(outvec); - outvec /= outval; + outVector = max(a, b); } -void vec_math_normalize(vec3 v, out vec3 outvec, out float outval) +void vector_math_mix(float strength, vec3 a, vec3 b, out vec3 outVector) { - outval = length(v); - outvec = normalize(v); + outVector = strength * a + (1 - strength) * b; } void vec_math_negate(vec3 v, out vec3 outv) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 81b93ce6541..385a5bd4428 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1195,6 +1195,33 @@ enum { NODE_MATH_SQRT = 23, }; +/* Vector Math node operations. */ +enum { + NODE_VECTOR_MATH_ADD = 0, + NODE_VECTOR_MATH_SUBTRACT = 1, + NODE_VECTOR_MATH_MULTIPLY = 2, + NODE_VECTOR_MATH_DIVIDE = 3, + + NODE_VECTOR_MATH_CROSS_PRODUCT = 4, + NODE_VECTOR_MATH_PROJECT = 5, + NODE_VECTOR_MATH_REFLECT = 6, + NODE_VECTOR_MATH_DOT_PRODUCT = 7, + + NODE_VECTOR_MATH_DISTANCE = 8, + NODE_VECTOR_MATH_LENGTH = 9, + NODE_VECTOR_MATH_SCALE = 10, + NODE_VECTOR_MATH_NORMALIZE = 11, + + NODE_VECTOR_MATH_SNAP = 12, + NODE_VECTOR_MATH_FLOOR = 13, + NODE_VECTOR_MATH_CEIL = 14, + NODE_VECTOR_MATH_MODULO = 15, + NODE_VECTOR_MATH_FRACTION = 16, + NODE_VECTOR_MATH_ABSOLUTE = 17, + NODE_VECTOR_MATH_MINIMUM = 18, + NODE_VECTOR_MATH_MAXIMUM = 19, +}; + /* mix rgb node flags */ #define SHD_MIXRGB_USE_ALPHA 1 #define SHD_MIXRGB_CLAMP 2 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 020f4296ddd..f377ae9a84f 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -136,12 +136,37 @@ const EnumPropertyItem rna_enum_node_math_items[] = { }; const EnumPropertyItem rna_enum_node_vec_math_items[] = { - {0, "ADD", 0, "Add", ""}, - {1, "SUBTRACT", 0, "Subtract", ""}, - {2, "AVERAGE", 0, "Average", ""}, - {3, "DOT_PRODUCT", 0, "Dot Product", ""}, - {4, "CROSS_PRODUCT", 0, "Cross Product", ""}, - {5, "NORMALIZE", 0, "Normalize", ""}, + {NODE_VECTOR_MATH_ADD, "ADD", 0, "Add", "A + B"}, + {NODE_VECTOR_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"}, + {NODE_VECTOR_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "Entrywise multiply"}, + {NODE_VECTOR_MATH_DIVIDE, "DIVIDE", 0, "Divide", "Entrywise divide"}, + {0, "", ICON_NONE, NULL, NULL}, + {NODE_VECTOR_MATH_CROSS_PRODUCT, "CROSS_PRODUCT", 0, "Cross Product", "A cross B"}, + {NODE_VECTOR_MATH_PROJECT, "PROJECT", 0, "Project", "Project A onto B"}, + {NODE_VECTOR_MATH_REFLECT, + "REFLECT", + 0, + "Reflect", + "Reflect A around the normal B. B needn't be normalized"}, + {NODE_VECTOR_MATH_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "A dot B"}, + {0, "", ICON_NONE, NULL, NULL}, + {NODE_VECTOR_MATH_DISTANCE, "DISTANCE", 0, "Distance", "Distance between A and B"}, + {NODE_VECTOR_MATH_LENGTH, "LENGTH", 0, "Length", "Length of A"}, + {NODE_VECTOR_MATH_SCALE, "SCALE", 0, "Scale", "A multiplied by Scale"}, + {NODE_VECTOR_MATH_NORMALIZE, "NORMALIZE", 0, "Normalize", "Normalize A"}, + {0, "", ICON_NONE, NULL, NULL}, + {NODE_VECTOR_MATH_SNAP, + "SNAP", + 0, + "Snap", + "Round A to the largest integer multiple of B less than or equal A"}, + {NODE_VECTOR_MATH_FLOOR, "FLOOR", 0, "Floor", "Entrywise floor"}, + {NODE_VECTOR_MATH_CEIL, "CEIL", 0, "Ceil", "Entrywise ceil"}, + {NODE_VECTOR_MATH_MODULO, "MODULO", 0, "Modulo", "Entrywise modulo"}, + {NODE_VECTOR_MATH_FRACTION, "FRACTION", 0, "Fraction", "The fraction part of A entrywise"}, + {NODE_VECTOR_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Entrywise absolute"}, + {NODE_VECTOR_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "Entrywise minimum"}, + {NODE_VECTOR_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "Entrywise maximum"}, {0, NULL, 0, NULL, NULL}, }; @@ -3873,7 +3898,7 @@ static void def_vector_math(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_vec_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"); } static void def_rgb_curve(StructRNA *srna) diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 284eaa8b70b..3c97bdae929 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -204,7 +204,7 @@ set(SRC shader/nodes/node_shader_uvmap.c shader/nodes/node_shader_valToRgb.c shader/nodes/node_shader_value.c - shader/nodes/node_shader_vectMath.c + shader/nodes/node_shader_vector_math.c shader/nodes/node_shader_vectTransform.c shader/nodes/node_shader_vector_displacement.c shader/nodes/node_shader_volume_absorption.c diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index c72e97642a2..c08911c1db8 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -53,7 +53,7 @@ DefNode(ShaderNode, SH_NODE_CAMERA, 0, "CAMERA DefNode(ShaderNode, SH_NODE_MAP_RANGE, def_map_range, "MAP_RANGE", MapRange, "Map Range", "" ) DefNode(ShaderNode, SH_NODE_CLAMP, 0, "CLAMP", Clamp, "Clamp", "" ) DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" ) -DefNode(ShaderNode, SH_NODE_VECT_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" ) +DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" ) DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" ) DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" ) DefNode(ShaderNode, SH_NODE_SEPRGB, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" ) diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index e9a825b5b3f..0d7f19fb67a 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -100,7 +100,7 @@ void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int max BLI_strncpy(label, IFACE_(name), maxlen); } -void node_vect_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) { const char *name; RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name); diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 7eef70db498..49117b38aba 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -71,7 +71,7 @@ extern void *node_initexec_curves(struct bNodeExecContext *context, void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); +void node_vector_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); /*** Link Handling */ diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 4891fb323ad..60a6cc91630 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -799,7 +799,7 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod nodeRemLink(ntree, displacement_link); /* Convert displacement vector to bump height. */ - bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECT_MATH); + bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY); bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal"); dot_node->custom1 = 3; /* dot product */ diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c index 3d034372300..712c64084cc 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c @@ -114,7 +114,7 @@ static int gpu_shader_normal_map(GPUMaterial *mat, break; } - GPU_link(mat, "vec_math_mix", strength, realnorm, negnorm, &out[0].link); + GPU_link(mat, "vector_math_mix", strength, realnorm, negnorm, &out[0].link); GPU_link(mat, "vect_normalize", out[0].link, &out[0].link); return true; diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c deleted file mode 100644 index 41273a6dc1d..00000000000 --- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2005 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup shdnodes - */ - -#include "node_shader_util.h" - -/* **************** VECTOR MATH ******************** */ -static bNodeSocketTemplate sh_node_vect_math_in[] = { - {SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {-1, 0, ""}}; - -static bNodeSocketTemplate sh_node_vect_math_out[] = { - {SOCK_VECTOR, 0, N_("Vector")}, {SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}}; - -static void node_shader_exec_vect_math(void *UNUSED(data), - int UNUSED(thread), - bNode *node, - bNodeExecData *UNUSED(execdata), - bNodeStack **in, - bNodeStack **out) -{ - float vec1[3], vec2[3]; - - nodestack_get_vec(vec1, SOCK_VECTOR, in[0]); - nodestack_get_vec(vec2, SOCK_VECTOR, in[1]); - - if (node->custom1 == 0) { /* Add */ - out[0]->vec[0] = vec1[0] + vec2[0]; - out[0]->vec[1] = vec1[1] + vec2[1]; - out[0]->vec[2] = vec1[2] + vec2[2]; - - out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) / - 3.0f; - } - else if (node->custom1 == 1) { /* Subtract */ - out[0]->vec[0] = vec1[0] - vec2[0]; - out[0]->vec[1] = vec1[1] - vec2[1]; - out[0]->vec[2] = vec1[2] - vec2[2]; - - out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) / - 3.0f; - } - else if (node->custom1 == 2) { /* Average */ - out[0]->vec[0] = vec1[0] + vec2[0]; - out[0]->vec[1] = vec1[1] + vec2[1]; - out[0]->vec[2] = vec1[2] + vec2[2]; - - out[1]->vec[0] = normalize_v3(out[0]->vec); - } - else if (node->custom1 == 3) { /* Dot product */ - out[1]->vec[0] = (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]); - } - else if (node->custom1 == 4) { /* Cross product */ - out[0]->vec[0] = (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]); - out[0]->vec[1] = (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]); - out[0]->vec[2] = (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]); - - out[1]->vec[0] = normalize_v3(out[0]->vec); - } - else if (node->custom1 == 5) { /* Normalize */ - /* This one only takes one input, so we've got to choose. */ - if (in[0]->hasinput || !in[1]->hasinput) { - out[0]->vec[0] = vec1[0]; - out[0]->vec[1] = vec1[1]; - out[0]->vec[2] = vec1[2]; - } - else { - out[0]->vec[0] = vec2[0]; - out[0]->vec[1] = vec2[1]; - out[0]->vec[2] = vec2[2]; - } - - out[1]->vec[0] = normalize_v3(out[0]->vec); - } -} - -static int gpu_shader_vect_math(GPUMaterial *mat, - bNode *node, - bNodeExecData *UNUSED(execdata), - GPUNodeStack *in, - GPUNodeStack *out) -{ - static const char *names[] = { - "vec_math_add", - "vec_math_sub", - "vec_math_average", - "vec_math_dot", - "vec_math_cross", - "vec_math_normalize", - }; - - switch (node->custom1) { - case 0: - case 1: - case 2: - case 3: - case 4: - GPU_stack_link(mat, node, names[node->custom1], in, out); - break; - case 5: - 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 false; - } - - return true; -} - -void register_node_type_sh_vect_math(void) -{ - static bNodeType ntype; - - sh_node_type_base(&ntype, SH_NODE_VECT_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0); - node_type_socket_templates(&ntype, sh_node_vect_math_in, sh_node_vect_math_out); - node_type_label(&ntype, node_vect_math_label); - node_type_storage(&ntype, "", NULL, NULL); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_math); - node_type_gpu(&ntype, gpu_shader_vect_math); - - nodeRegisterType(&ntype); -} diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.c b/source/blender/nodes/shader/nodes/node_shader_vector_math.c new file mode 100644 index 00000000000..03de83655b5 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.c @@ -0,0 +1,113 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup shdnodes + */ + +#include "node_shader_util.h" + +/* **************** VECTOR MATH ******************** */ +static bNodeSocketTemplate sh_node_vector_math_in[] = { + {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, + {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, + {SOCK_FLOAT, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, + {-1, 0, ""}}; + +static bNodeSocketTemplate sh_node_vector_math_out[] = { + {SOCK_VECTOR, 0, N_("Vector")}, {SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}}; + +static int gpu_shader_vector_math(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + static const char *names[] = { + [NODE_VECTOR_MATH_ADD] = "vector_math_add", + [NODE_VECTOR_MATH_SUBTRACT] = "vector_math_subtract", + [NODE_VECTOR_MATH_MULTIPLY] = "vector_math_multiply", + [NODE_VECTOR_MATH_DIVIDE] = "vector_math_divide", + + [NODE_VECTOR_MATH_CROSS_PRODUCT] = "vector_math_cross", + [NODE_VECTOR_MATH_PROJECT] = "vector_math_project", + [NODE_VECTOR_MATH_REFLECT] = "vector_math_reflect", + [NODE_VECTOR_MATH_DOT_PRODUCT] = "vector_math_dot", + + [NODE_VECTOR_MATH_DISTANCE] = "vector_math_distance", + [NODE_VECTOR_MATH_LENGTH] = "vector_math_length", + [NODE_VECTOR_MATH_SCALE] = "vector_math_scale", + [NODE_VECTOR_MATH_NORMALIZE] = "vector_math_normalize", + + [NODE_VECTOR_MATH_SNAP] = "vector_math_snap", + [NODE_VECTOR_MATH_FLOOR] = "vector_math_floor", + [NODE_VECTOR_MATH_CEIL] = "vector_math_ceil", + [NODE_VECTOR_MATH_MODULO] = "vector_math_modulo", + [NODE_VECTOR_MATH_FRACTION] = "vector_math_fraction", + [NODE_VECTOR_MATH_ABSOLUTE] = "vector_math_absolute", + [NODE_VECTOR_MATH_MINIMUM] = "vector_math_minimum", + [NODE_VECTOR_MATH_MAXIMUM] = "vector_math_maximum", + }; + + GPU_stack_link(mat, node, names[node->custom1], in, out); + return true; +} + +static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sockB = BLI_findlink(&node->inputs, 1); + bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale"); + + bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector"); + bNodeSocket *sockValue = nodeFindSocket(node, SOCK_OUT, "Value"); + + nodeSetSocketAvailability(sockB, + !ELEM(node->custom1, + NODE_VECTOR_MATH_CEIL, + NODE_VECTOR_MATH_SCALE, + NODE_VECTOR_MATH_FLOOR, + NODE_VECTOR_MATH_LENGTH, + NODE_VECTOR_MATH_ABSOLUTE, + NODE_VECTOR_MATH_FRACTION, + NODE_VECTOR_MATH_NORMALIZE)); + nodeSetSocketAvailability(sockScale, node->custom1 == NODE_VECTOR_MATH_SCALE); + nodeSetSocketAvailability(sockVector, + !ELEM(node->custom1, + NODE_VECTOR_MATH_LENGTH, + NODE_VECTOR_MATH_DISTANCE, + NODE_VECTOR_MATH_DOT_PRODUCT)); + nodeSetSocketAvailability(sockValue, + ELEM(node->custom1, + NODE_VECTOR_MATH_LENGTH, + NODE_VECTOR_MATH_DISTANCE, + NODE_VECTOR_MATH_DOT_PRODUCT)); +} + +void register_node_type_sh_vect_math(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0); + node_type_socket_templates(&ntype, sh_node_vector_math_in, sh_node_vector_math_out); + node_type_label(&ntype, node_vector_math_label); + node_type_gpu(&ntype, gpu_shader_vector_math); + node_type_update(&ntype, node_shader_update_vector_math); + + nodeRegisterType(&ntype); +} |