Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/blender/shader.cpp91
-rw-r--r--intern/cycles/kernel/osl/shaders/CMakeLists.txt5
-rw-r--r--intern/cycles/kernel/osl/shaders/node_color_blend.h264
-rw-r--r--intern/cycles/kernel/osl/shaders/node_mix_color.osl57
-rw-r--r--intern/cycles/kernel/osl/shaders/node_mix_float.osl11
-rw-r--r--intern/cycles/kernel/osl/shaders/node_mix_vector.osl14
-rw-r--r--intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl14
-rw-r--r--intern/cycles/kernel/svm/color_util.h12
-rw-r--r--intern/cycles/kernel/svm/mix.h86
-rw-r--r--intern/cycles/kernel/svm/node_types_template.h4
-rw-r--r--intern/cycles/kernel/svm/svm.h12
-rw-r--r--intern/cycles/kernel/svm/types.h2
-rw-r--r--intern/cycles/scene/constant_fold.cpp95
-rw-r--r--intern/cycles/scene/constant_fold.h1
-rw-r--r--intern/cycles/scene/shader_nodes.cpp244
-rw-r--r--intern/cycles/scene/shader_nodes.h46
-rw-r--r--release/scripts/startup/nodeitems_builtins.py4
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/intern/node.cc1
-rw-r--r--source/blender/blenloader/intern/versioning_300.c29
-rw-r--r--source/blender/editors/space_node/drawnode.cc2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp4
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl537
-rw-r--r--source/blender/makesdna/DNA_node_types.h16
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c54
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix.cc443
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc4
31 files changed, 2040 insertions, 21 deletions
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index 04eb1576330..9505f4ba58f 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -350,6 +350,33 @@ static ShaderNode *add_node(Scene *scene,
mix->set_use_clamp(b_mix_node.use_clamp());
node = mix;
}
+ else if (b_node.is_a(&RNA_ShaderNodeMix)) {
+ BL::ShaderNodeMix b_mix_node(b_node);
+ if (b_mix_node.data_type() == BL::ShaderNodeMix::data_type_VECTOR) {
+ if (b_mix_node.factor_mode() == BL::ShaderNodeMix::factor_mode_UNIFORM) {
+ MixVectorNode *mix_node = graph->create_node<MixVectorNode>();
+ mix_node->set_use_clamp(b_mix_node.clamp_factor());
+ node = mix_node;
+ }
+ else {
+ MixVectorNonUniformNode *mix_node = graph->create_node<MixVectorNonUniformNode>();
+ mix_node->set_use_clamp(b_mix_node.clamp_factor());
+ node = mix_node;
+ }
+ }
+ else if (b_mix_node.data_type() == BL::ShaderNodeMix::data_type_RGBA) {
+ MixColorNode *mix_node = graph->create_node<MixColorNode>();
+ mix_node->set_blend_type((NodeMix)b_mix_node.blend_type());
+ mix_node->set_use_clamp(b_mix_node.clamp_factor());
+ mix_node->set_use_clamp_result(b_mix_node.clamp_result());
+ node = mix_node;
+ }
+ else {
+ MixFloatNode *mix_node = graph->create_node<MixFloatNode>();
+ mix_node->set_use_clamp(b_mix_node.clamp_factor());
+ node = mix_node;
+ }
+ }
else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
node = graph->create_node<SeparateRGBNode>();
}
@@ -1072,7 +1099,9 @@ static bool node_use_modified_socket_name(ShaderNode *node)
return true;
}
-static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
+static ShaderInput *node_find_input_by_name(BL::Node b_node,
+ ShaderNode *node,
+ BL::NodeSocket &b_socket)
{
string name = b_socket.identifier();
ShaderInput *input = node->input(name.c_str());
@@ -1082,6 +1111,35 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_
if (string_startswith(name, "Shader")) {
string_replace(name, "Shader", "Closure");
}
+
+ /* Map mix node internal name for shader. */
+ if (b_node.is_a(&RNA_ShaderNodeMix)) {
+ if (string_endswith(name, "Factor_Float")) {
+ string_replace(name, "Factor_Float", "Factor");
+ }
+ else if (string_endswith(name, "Factor_Vector")) {
+ string_replace(name, "Factor_Vector", "Factor");
+ }
+ else if (string_endswith(name, "A_Float")) {
+ string_replace(name, "A_Float", "A");
+ }
+ else if (string_endswith(name, "B_Float")) {
+ string_replace(name, "B_Float", "B");
+ }
+ else if (string_endswith(name, "A_Color")) {
+ string_replace(name, "A_Color", "A");
+ }
+ else if (string_endswith(name, "B_Color")) {
+ string_replace(name, "B_Color", "B");
+ }
+ else if (string_endswith(name, "A_Vector")) {
+ string_replace(name, "A_Vector", "A");
+ }
+ else if (string_endswith(name, "B_Vector")) {
+ string_replace(name, "B_Vector", "B");
+ }
+ }
+
input = node->input(name.c_str());
if (!input) {
@@ -1111,7 +1169,9 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_
return input;
}
-static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
+static ShaderOutput *node_find_output_by_name(BL::Node b_node,
+ ShaderNode *node,
+ BL::NodeSocket &b_socket)
{
string name = b_socket.identifier();
ShaderOutput *output = node->output(name.c_str());
@@ -1122,6 +1182,21 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket &
name = "Closure";
output = node->output(name.c_str());
}
+ /* Map internal name for shader. */
+ if (b_node.is_a(&RNA_ShaderNodeMix)) {
+ if (string_endswith(name, "Result_Float")) {
+ string_replace(name, "Result_Float", "Result");
+ output = node->output(name.c_str());
+ }
+ else if (string_endswith(name, "Result_Color")) {
+ string_replace(name, "Result_Color", "Result");
+ output = node->output(name.c_str());
+ }
+ else if (string_endswith(name, "Result_Vector")) {
+ string_replace(name, "Result_Vector", "Result");
+ output = node->output(name.c_str());
+ }
+ }
}
return output;
@@ -1267,7 +1342,11 @@ static void add_nodes(Scene *scene,
if (node) {
/* map node sockets for linking */
for (BL::NodeSocket &b_input : b_node.inputs) {
- ShaderInput *input = node_find_input_by_name(node, b_input);
+ if (b_input.is_unavailable()) {
+ /* Skip unavailable sockets. */
+ continue;
+ }
+ ShaderInput *input = node_find_input_by_name(b_node, node, b_input);
if (!input) {
/* XXX should not happen, report error? */
continue;
@@ -1277,7 +1356,11 @@ static void add_nodes(Scene *scene,
set_default_value(input, b_input, b_data, b_ntree);
}
for (BL::NodeSocket &b_output : b_node.outputs) {
- ShaderOutput *output = node_find_output_by_name(node, b_output);
+ if (b_output.is_unavailable()) {
+ /* Skip unavailable sockets. */
+ continue;
+ }
+ ShaderOutput *output = node_find_output_by_name(b_node, node, b_output);
if (!output) {
/* XXX should not happen, report error? */
continue;
diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
index 741bce7c399..c79af3f6112 100644
--- a/intern/cycles/kernel/osl/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
@@ -57,6 +57,10 @@ set(SRC_OSL
node_math.osl
node_mix.osl
node_mix_closure.osl
+ node_mix_color.osl
+ node_mix_float.osl
+ node_mix_vector.osl
+ node_mix_vector_non_uniform.osl
node_musgrave_texture.osl
node_noise_texture.osl
node_normal.osl
@@ -109,6 +113,7 @@ file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h)
set(SRC_OSL_HEADERS
node_color.h
+ node_color_blend.h
node_fresnel.h
node_hash.h
node_math.h
diff --git a/intern/cycles/kernel/osl/shaders/node_color_blend.h b/intern/cycles/kernel/osl/shaders/node_color_blend.h
new file mode 100644
index 00000000000..ab4b4809a97
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_color_blend.h
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+color node_mix_blend(float t, color col1, color col2)
+{
+ return mix(col1, col2, t);
+}
+
+color node_mix_add(float t, color col1, color col2)
+{
+ return mix(col1, col1 + col2, t);
+}
+
+color node_mix_mul(float t, color col1, color col2)
+{
+ return mix(col1, col1 * col2, t);
+}
+
+color node_mix_screen(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ return color(1.0) - (color(tm) + t * (color(1.0) - col2)) * (color(1.0) - col1);
+}
+
+color node_mix_overlay(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color outcol = col1;
+
+ if (outcol[0] < 0.5)
+ outcol[0] *= tm + 2.0 * t * col2[0];
+ else
+ outcol[0] = 1.0 - (tm + 2.0 * t * (1.0 - col2[0])) * (1.0 - outcol[0]);
+
+ if (outcol[1] < 0.5)
+ outcol[1] *= tm + 2.0 * t * col2[1];
+ else
+ outcol[1] = 1.0 - (tm + 2.0 * t * (1.0 - col2[1])) * (1.0 - outcol[1]);
+
+ if (outcol[2] < 0.5)
+ outcol[2] *= tm + 2.0 * t * col2[2];
+ else
+ outcol[2] = 1.0 - (tm + 2.0 * t * (1.0 - col2[2])) * (1.0 - outcol[2]);
+
+ return outcol;
+}
+
+color node_mix_sub(float t, color col1, color col2)
+{
+ return mix(col1, col1 - col2, t);
+}
+
+color node_mix_div(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color outcol = col1;
+
+ if (col2[0] != 0.0)
+ outcol[0] = tm * outcol[0] + t * outcol[0] / col2[0];
+ if (col2[1] != 0.0)
+ outcol[1] = tm * outcol[1] + t * outcol[1] / col2[1];
+ if (col2[2] != 0.0)
+ outcol[2] = tm * outcol[2] + t * outcol[2] / col2[2];
+
+ return outcol;
+}
+
+color node_mix_diff(float t, color col1, color col2)
+{
+ return mix(col1, abs(col1 - col2), t);
+}
+
+color node_mix_dark(float t, color col1, color col2)
+{
+ return mix(col1, min(col1, col2), t);
+}
+
+color node_mix_light(float t, color col1, color col2)
+{
+ return mix(col1, max(col1, col2), t);
+}
+
+color node_mix_dodge(float t, color col1, color col2)
+{
+ color outcol = col1;
+
+ if (outcol[0] != 0.0) {
+ float tmp = 1.0 - t * col2[0];
+ if (tmp <= 0.0)
+ outcol[0] = 1.0;
+ else if ((tmp = outcol[0] / tmp) > 1.0)
+ outcol[0] = 1.0;
+ else
+ outcol[0] = tmp;
+ }
+ if (outcol[1] != 0.0) {
+ float tmp = 1.0 - t * col2[1];
+ if (tmp <= 0.0)
+ outcol[1] = 1.0;
+ else if ((tmp = outcol[1] / tmp) > 1.0)
+ outcol[1] = 1.0;
+ else
+ outcol[1] = tmp;
+ }
+ if (outcol[2] != 0.0) {
+ float tmp = 1.0 - t * col2[2];
+ if (tmp <= 0.0)
+ outcol[2] = 1.0;
+ else if ((tmp = outcol[2] / tmp) > 1.0)
+ outcol[2] = 1.0;
+ else
+ outcol[2] = tmp;
+ }
+
+ return outcol;
+}
+
+color node_mix_burn(float t, color col1, color col2)
+{
+ float tmp, tm = 1.0 - t;
+
+ color outcol = col1;
+
+ tmp = tm + t * col2[0];
+ if (tmp <= 0.0)
+ outcol[0] = 0.0;
+ else if ((tmp = (1.0 - (1.0 - outcol[0]) / tmp)) < 0.0)
+ outcol[0] = 0.0;
+ else if (tmp > 1.0)
+ outcol[0] = 1.0;
+ else
+ outcol[0] = tmp;
+
+ tmp = tm + t * col2[1];
+ if (tmp <= 0.0)
+ outcol[1] = 0.0;
+ else if ((tmp = (1.0 - (1.0 - outcol[1]) / tmp)) < 0.0)
+ outcol[1] = 0.0;
+ else if (tmp > 1.0)
+ outcol[1] = 1.0;
+ else
+ outcol[1] = tmp;
+
+ tmp = tm + t * col2[2];
+ if (tmp <= 0.0)
+ outcol[2] = 0.0;
+ else if ((tmp = (1.0 - (1.0 - outcol[2]) / tmp)) < 0.0)
+ outcol[2] = 0.0;
+ else if (tmp > 1.0)
+ outcol[2] = 1.0;
+ else
+ outcol[2] = tmp;
+
+ return outcol;
+}
+
+color node_mix_hue(float t, color col1, color col2)
+{
+ color outcol = col1;
+ color hsv2 = rgb_to_hsv(col2);
+
+ if (hsv2[1] != 0.0) {
+ color hsv = rgb_to_hsv(outcol);
+ hsv[0] = hsv2[0];
+ color tmp = hsv_to_rgb(hsv);
+
+ outcol = mix(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+color node_mix_sat(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color outcol = col1;
+
+ color hsv = rgb_to_hsv(outcol);
+
+ if (hsv[1] != 0.0) {
+ color hsv2 = rgb_to_hsv(col2);
+
+ hsv[1] = tm * hsv[1] + t * hsv2[1];
+ outcol = hsv_to_rgb(hsv);
+ }
+
+ return outcol;
+}
+
+color node_mix_val(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color hsv = rgb_to_hsv(col1);
+ color hsv2 = rgb_to_hsv(col2);
+
+ hsv[2] = tm * hsv[2] + t * hsv2[2];
+
+ return hsv_to_rgb(hsv);
+}
+
+color node_mix_color(float t, color col1, color col2)
+{
+ color outcol = col1;
+ color hsv2 = rgb_to_hsv(col2);
+
+ if (hsv2[1] != 0.0) {
+ color hsv = rgb_to_hsv(outcol);
+ hsv[0] = hsv2[0];
+ hsv[1] = hsv2[1];
+ color tmp = hsv_to_rgb(hsv);
+
+ outcol = mix(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+color node_mix_soft(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color one = color(1.0);
+ color scr = one - (one - col2) * (one - col1);
+
+ return tm * col1 + t * ((one - col1) * col2 * col1 + col1 * scr);
+}
+
+color node_mix_linear(float t, color col1, color col2)
+{
+ color outcol = col1;
+
+ if (col2[0] > 0.5)
+ outcol[0] = col1[0] + t * (2.0 * (col2[0] - 0.5));
+ else
+ outcol[0] = col1[0] + t * (2.0 * (col2[0]) - 1.0);
+
+ if (col2[1] > 0.5)
+ outcol[1] = col1[1] + t * (2.0 * (col2[1] - 0.5));
+ else
+ outcol[1] = col1[1] + t * (2.0 * (col2[1]) - 1.0);
+
+ if (col2[2] > 0.5)
+ outcol[2] = col1[2] + t * (2.0 * (col2[2] - 0.5));
+ else
+ outcol[2] = col1[2] + t * (2.0 * (col2[2]) - 1.0);
+
+ return outcol;
+}
+
+color node_mix_clamp(color col)
+{
+ color outcol = col;
+
+ outcol[0] = clamp(col[0], 0.0, 1.0);
+ outcol[1] = clamp(col[1], 0.0, 1.0);
+ outcol[2] = clamp(col[2], 0.0, 1.0);
+
+ return outcol;
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_mix_color.osl b/intern/cycles/kernel/osl/shaders/node_mix_color.osl
new file mode 100644
index 00000000000..3ddd89ed306
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_mix_color.osl
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "node_color.h"
+#include "node_color_blend.h"
+#include "stdcycles.h"
+
+shader node_mix_color(string blend_type = "mix",
+ int use_clamp = 0,
+ int use_clamp_result = 0,
+ float Factor = 0.5,
+ color A = 0.0,
+ color B = 0.0,
+ output color Result = 0.0)
+{
+ float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor;
+
+ if (blend_type == "mix")
+ Result = mix(A, B, t);
+ if (blend_type == "add")
+ Result = node_mix_add(t, A, B);
+ if (blend_type == "multiply")
+ Result = node_mix_mul(t, A, B);
+ if (blend_type == "screen")
+ Result = node_mix_screen(t, A, B);
+ if (blend_type == "overlay")
+ Result = node_mix_overlay(t, A, B);
+ if (blend_type == "subtract")
+ Result = node_mix_sub(t, A, B);
+ if (blend_type == "divide")
+ Result = node_mix_div(t, A, B);
+ if (blend_type == "difference")
+ Result = node_mix_diff(t, A, B);
+ if (blend_type == "darken")
+ Result = node_mix_dark(t, A, B);
+ if (blend_type == "lighten")
+ Result = node_mix_light(t, A, B);
+ if (blend_type == "dodge")
+ Result = node_mix_dodge(t, A, B);
+ if (blend_type == "burn")
+ Result = node_mix_burn(t, A, B);
+ if (blend_type == "hue")
+ Result = node_mix_hue(t, A, B);
+ if (blend_type == "saturation")
+ Result = node_mix_sat(t, A, B);
+ if (blend_type == "value")
+ Result = node_mix_val(t, A, B);
+ if (blend_type == "color")
+ Result = node_mix_color(t, A, B);
+ if (blend_type == "soft_light")
+ Result = node_mix_soft(t, A, B);
+ if (blend_type == "linear_light")
+ Result = node_mix_linear(t, A, B);
+
+ if (use_clamp_result)
+ Result = clamp(Result, 0.0, 1.0);
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_mix_float.osl b/intern/cycles/kernel/osl/shaders/node_mix_float.osl
new file mode 100644
index 00000000000..fdc7b4eff6e
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_mix_float.osl
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "stdcycles.h"
+
+shader node_mix_float(
+ int use_clamp = 0, float Factor = 0.5, float A = 0.0, float B = 0.0, output float Result = 0.0)
+{
+ float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor;
+ Result = mix(A, B, t);
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_mix_vector.osl b/intern/cycles/kernel/osl/shaders/node_mix_vector.osl
new file mode 100644
index 00000000000..d76396afb0d
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_mix_vector.osl
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "stdcycles.h"
+
+shader node_mix_vector(int use_clamp = 0,
+ float Factor = 0.5,
+ vector A = 0.0,
+ vector B = 0.0,
+ output vector Result = 0.0)
+{
+ float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor;
+ Result = mix(A, B, t);
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl b/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl
new file mode 100644
index 00000000000..217856bcf2a
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "stdcycles.h"
+
+shader node_mix_vector_non_uniform(int use_clamp = 0,
+ vector Factor = 0.5,
+ vector A = 0.0,
+ vector B = 0.0,
+ output vector Result = 0.0)
+{
+ vector t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor;
+ Result = mix(A, B, t);
+}
diff --git a/intern/cycles/kernel/svm/color_util.h b/intern/cycles/kernel/svm/color_util.h
index 41f44378ff0..96adb6fd64c 100644
--- a/intern/cycles/kernel/svm/color_util.h
+++ b/intern/cycles/kernel/svm/color_util.h
@@ -247,10 +247,8 @@ ccl_device float3 svm_mix_clamp(float3 col)
return saturate(col);
}
-ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
+ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float t, float3 c1, float3 c2)
{
- float t = saturatef(fac);
-
switch (type) {
case NODE_MIX_BLEND:
return svm_mix_blend(t, c1, c2);
@@ -282,7 +280,7 @@ ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float
return svm_mix_sat(t, c1, c2);
case NODE_MIX_VAL:
return svm_mix_val(t, c1, c2);
- case NODE_MIX_COLOR:
+ case NODE_MIX_COL:
return svm_mix_color(t, c1, c2);
case NODE_MIX_SOFT:
return svm_mix_soft(t, c1, c2);
@@ -295,6 +293,12 @@ ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float
return make_float3(0.0f, 0.0f, 0.0f);
}
+ccl_device_noinline_cpu float3 svm_mix_clamped_factor(NodeMix type, float t, float3 c1, float3 c2)
+{
+ float fac = saturatef(t);
+ return svm_mix(type, fac, c1, c2);
+}
+
ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast)
{
float a = 1.0f + contrast;
diff --git a/intern/cycles/kernel/svm/mix.h b/intern/cycles/kernel/svm/mix.h
index a9796096410..ead2fc44685 100644
--- a/intern/cycles/kernel/svm/mix.h
+++ b/intern/cycles/kernel/svm/mix.h
@@ -21,10 +21,94 @@ ccl_device_noinline int svm_node_mix(KernelGlobals kg,
float fac = stack_load_float(stack, fac_offset);
float3 c1 = stack_load_float3(stack, c1_offset);
float3 c2 = stack_load_float3(stack, c2_offset);
- float3 result = svm_mix((NodeMix)node1.y, fac, c1, c2);
+ float3 result = svm_mix_clamped_factor((NodeMix)node1.y, fac, c1, c2);
stack_store_float3(stack, node1.z, result);
return offset;
}
+ccl_device_noinline void svm_node_mix_color(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint options,
+ uint input_offset,
+ uint result_offset)
+{
+ uint use_clamp, blend_type, use_clamp_result;
+ uint fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset;
+ svm_unpack_node_uchar3(options, &use_clamp, &blend_type, &use_clamp_result);
+ svm_unpack_node_uchar3(
+ input_offset, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset);
+
+ float t = stack_load_float(stack, fac_in_stack_offset);
+ if (use_clamp > 0) {
+ t = saturatef(t);
+ }
+ float3 a = stack_load_float3(stack, a_in_stack_offset);
+ float3 b = stack_load_float3(stack, b_in_stack_offset);
+ float3 result = svm_mix((NodeMix)blend_type, t, a, b);
+ if (use_clamp_result) {
+ result = saturate(result);
+ }
+ stack_store_float3(stack, result_offset, result);
+}
+
+ccl_device_noinline void svm_node_mix_float(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint use_clamp,
+ uint input_offset,
+ uint result_offset)
+{
+ uint fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset;
+ svm_unpack_node_uchar3(
+ input_offset, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset);
+
+ float t = stack_load_float(stack, fac_in_stack_offset);
+ if (use_clamp > 0) {
+ t = saturatef(t);
+ }
+ float a = stack_load_float(stack, a_in_stack_offset);
+ float b = stack_load_float(stack, b_in_stack_offset);
+ float result = a * (1 - t) + b * t;
+
+ stack_store_float(stack, result_offset, result);
+}
+
+ccl_device_noinline void svm_node_mix_vector(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint input_offset,
+ uint result_offset)
+{
+ uint use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset;
+ svm_unpack_node_uchar4(
+ input_offset, &use_clamp, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset);
+
+ float t = stack_load_float(stack, fac_in_stack_offset);
+ if (use_clamp > 0) {
+ t = saturatef(t);
+ }
+ float3 a = stack_load_float3(stack, a_in_stack_offset);
+ float3 b = stack_load_float3(stack, b_in_stack_offset);
+ float3 result = a * (one_float3() - t) + b * t;
+ stack_store_float3(stack, result_offset, result);
+}
+
+ccl_device_noinline void svm_node_mix_vector_non_uniform(ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint input_offset,
+ uint result_offset)
+{
+ uint use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset;
+ svm_unpack_node_uchar4(
+ input_offset, &use_clamp, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset);
+
+ float3 t = stack_load_float3(stack, fac_in_stack_offset);
+ if (use_clamp > 0) {
+ t = saturate(t);
+ }
+ float3 a = stack_load_float3(stack, a_in_stack_offset);
+ float3 b = stack_load_float3(stack, b_in_stack_offset);
+ float3 result = a * (one_float3() - t) + b * t;
+ stack_store_float3(stack, result_offset, result);
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/node_types_template.h b/intern/cycles/kernel/svm/node_types_template.h
index 39d279be4cb..aab9b9f1158 100644
--- a/intern/cycles/kernel/svm/node_types_template.h
+++ b/intern/cycles/kernel/svm/node_types_template.h
@@ -103,6 +103,10 @@ SHADER_NODE_TYPE(NODE_AOV_START)
SHADER_NODE_TYPE(NODE_AOV_COLOR)
SHADER_NODE_TYPE(NODE_AOV_VALUE)
SHADER_NODE_TYPE(NODE_FLOAT_CURVE)
+SHADER_NODE_TYPE(NODE_MIX_COLOR)
+SHADER_NODE_TYPE(NODE_MIX_FLOAT)
+SHADER_NODE_TYPE(NODE_MIX_VECTOR)
+SHADER_NODE_TYPE(NODE_MIX_VECTOR_NON_UNIFORM)
/* Padding for struct alignment. */
SHADER_NODE_TYPE(NODE_PAD1)
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 9d6d3e9222c..3ca632c5f0b 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -585,6 +585,18 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
SVM_CASE(NODE_AOV_VALUE)
svm_node_aov_value<node_feature_mask>(kg, state, sd, stack, node, render_buffer);
break;
+ SVM_CASE(NODE_MIX_COLOR)
+ svm_node_mix_color(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_MIX_FLOAT)
+ svm_node_mix_float(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_MIX_VECTOR)
+ svm_node_mix_vector(sd, stack, node.y, node.z);
+ break;
+ SVM_CASE(NODE_MIX_VECTOR_NON_UNIFORM)
+ svm_node_mix_vector_non_uniform(sd, stack, node.y, node.z);
+ break;
default:
kernel_assert(!"Unknown node type was passed to the SVM machine");
return;
diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h
index 98dfe6a4375..9dd8f196e0f 100644
--- a/intern/cycles/kernel/svm/types.h
+++ b/intern/cycles/kernel/svm/types.h
@@ -133,7 +133,7 @@ typedef enum NodeMix {
NODE_MIX_HUE,
NODE_MIX_SAT,
NODE_MIX_VAL,
- NODE_MIX_COLOR,
+ NODE_MIX_COL,
NODE_MIX_SOFT,
NODE_MIX_LINEAR,
NODE_MIX_CLAMP /* used for the clamp UI option */
diff --git a/intern/cycles/scene/constant_fold.cpp b/intern/cycles/scene/constant_fold.cpp
index 4bce5661f9b..1aa4515a087 100644
--- a/intern/cycles/scene/constant_fold.cpp
+++ b/intern/cycles/scene/constant_fold.cpp
@@ -291,6 +291,101 @@ void ConstantFolder::fold_mix(NodeMix type, bool clamp) const
}
}
+void ConstantFolder::fold_mix_color(NodeMix type, bool clamp_factor, bool clamp) const
+{
+ ShaderInput *fac_in = node->input("Factor");
+ ShaderInput *color1_in = node->input("A");
+ ShaderInput *color2_in = node->input("B");
+
+ float fac = clamp_factor ? saturatef(node->get_float(fac_in->socket_type)) :
+ node->get_float(fac_in->socket_type);
+ bool fac_is_zero = !fac_in->link && fac == 0.0f;
+ bool fac_is_one = !fac_in->link && fac == 1.0f;
+
+ /* remove no-op node when factor is 0.0 */
+ if (fac_is_zero) {
+ /* note that some of the modes will clamp out of bounds values even without use_clamp */
+ if (!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) {
+ if (try_bypass_or_make_constant(color1_in, clamp)) {
+ return;
+ }
+ }
+ }
+
+ switch (type) {
+ case NODE_MIX_BLEND:
+ /* remove useless mix colors nodes */
+ if (color1_in->link && color2_in->link) {
+ if (color1_in->link == color2_in->link) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ break;
+ }
+ }
+ else if (!color1_in->link && !color2_in->link) {
+ float3 color1 = node->get_float3(color1_in->socket_type);
+ float3 color2 = node->get_float3(color2_in->socket_type);
+ if (color1 == color2) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ break;
+ }
+ }
+ /* remove no-op mix color node when factor is 1.0 */
+ if (fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ break;
+ }
+ break;
+ case NODE_MIX_ADD:
+ /* 0 + X (fac 1) == X */
+ if (is_zero(color1_in) && fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ }
+ /* X + 0 (fac ?) == X */
+ else if (is_zero(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ break;
+ case NODE_MIX_SUB:
+ /* X - 0 (fac ?) == X */
+ if (is_zero(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* X - X (fac 1) == 0 */
+ else if (color1_in->link && color1_in->link == color2_in->link && fac_is_one) {
+ make_zero();
+ }
+ break;
+ case NODE_MIX_MUL:
+ /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */
+ if (is_one(color1_in) && fac_is_one) {
+ try_bypass_or_make_constant(color2_in, clamp);
+ }
+ else if (is_one(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */
+ else if (is_zero(color1_in)) {
+ make_zero();
+ }
+ else if (is_zero(color2_in) && fac_is_one) {
+ make_zero();
+ }
+ break;
+ case NODE_MIX_DIV:
+ /* X / 1 (fac ?) == X */
+ if (is_one(color2_in)) {
+ try_bypass_or_make_constant(color1_in, clamp);
+ }
+ /* 0 / ? (fac ?) == 0 */
+ else if (is_zero(color1_in)) {
+ make_zero();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
void ConstantFolder::fold_math(NodeMathType type) const
{
ShaderInput *value1_in = node->input("Value1");
diff --git a/intern/cycles/scene/constant_fold.h b/intern/cycles/scene/constant_fold.h
index 090ce367e6c..246ff2d31ee 100644
--- a/intern/cycles/scene/constant_fold.h
+++ b/intern/cycles/scene/constant_fold.h
@@ -51,6 +51,7 @@ class ConstantFolder {
/* Specific nodes. */
void fold_mix(NodeMix type, bool clamp) const;
+ void fold_mix_color(NodeMix type, bool clamp_factor, bool clamp) const;
void fold_math(NodeMathType type) const;
void fold_vector_math(NodeVectorMathType type) const;
void fold_mapping(NodeMappingType type) const;
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index bedb0fe2902..a9cd453947b 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -4950,7 +4950,7 @@ NODE_DEFINE(MixNode)
type_enum.insert("hue", NODE_MIX_HUE);
type_enum.insert("saturation", NODE_MIX_SAT);
type_enum.insert("value", NODE_MIX_VAL);
- type_enum.insert("color", NODE_MIX_COLOR);
+ type_enum.insert("color", NODE_MIX_COL);
type_enum.insert("soft_light", NODE_MIX_SOFT);
type_enum.insert("linear_light", NODE_MIX_LINEAR);
SOCKET_ENUM(mix_type, "Type", type_enum, NODE_MIX_BLEND);
@@ -4999,13 +4999,253 @@ void MixNode::compile(OSLCompiler &compiler)
void MixNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
- folder.make_constant_clamp(svm_mix(mix_type, fac, color1, color2), use_clamp);
+ folder.make_constant_clamp(svm_mix_clamped_factor(mix_type, fac, color1, color2), use_clamp);
}
else {
folder.fold_mix(mix_type, use_clamp);
}
}
+/* Mix Color */
+
+NODE_DEFINE(MixColorNode)
+{
+ NodeType *type = NodeType::add("mix_color", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("mix", NODE_MIX_BLEND);
+ type_enum.insert("add", NODE_MIX_ADD);
+ type_enum.insert("multiply", NODE_MIX_MUL);
+ type_enum.insert("screen", NODE_MIX_SCREEN);
+ type_enum.insert("overlay", NODE_MIX_OVERLAY);
+ type_enum.insert("subtract", NODE_MIX_SUB);
+ type_enum.insert("divide", NODE_MIX_DIV);
+ type_enum.insert("difference", NODE_MIX_DIFF);
+ type_enum.insert("darken", NODE_MIX_DARK);
+ type_enum.insert("lighten", NODE_MIX_LIGHT);
+ type_enum.insert("dodge", NODE_MIX_DODGE);
+ type_enum.insert("burn", NODE_MIX_BURN);
+ type_enum.insert("hue", NODE_MIX_HUE);
+ type_enum.insert("saturation", NODE_MIX_SAT);
+ type_enum.insert("value", NODE_MIX_VAL);
+ type_enum.insert("color", NODE_MIX_COL);
+ type_enum.insert("soft_light", NODE_MIX_SOFT);
+ type_enum.insert("linear_light", NODE_MIX_LINEAR);
+ SOCKET_ENUM(blend_type, "Type", type_enum, NODE_MIX_BLEND);
+
+ SOCKET_IN_FLOAT(fac, "Factor", 0.5f);
+ SOCKET_IN_COLOR(a, "A", zero_float3());
+ SOCKET_IN_COLOR(b, "B", zero_float3());
+ SOCKET_BOOLEAN(use_clamp_result, "Use Clamp Result", false);
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", true);
+
+ SOCKET_OUT_COLOR(result, "Result");
+
+ return type;
+}
+
+MixColorNode::MixColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void MixColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *fac_in = input("Factor");
+ ShaderInput *a_in = input("A");
+ ShaderInput *b_in = input("B");
+ ShaderOutput *result_out = output("Result");
+
+ int fac_in_stack_offset = compiler.stack_assign(fac_in);
+ int a_in_stack_offset = compiler.stack_assign(a_in);
+ int b_in_stack_offset = compiler.stack_assign(b_in);
+
+ compiler.add_node(
+ NODE_MIX_COLOR,
+ compiler.encode_uchar4(use_clamp, blend_type, use_clamp_result),
+ compiler.encode_uchar4(fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset),
+ compiler.stack_assign(result_out));
+}
+
+void MixColorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "blend_type");
+ compiler.parameter(this, "use_clamp");
+ compiler.parameter(this, "use_clamp_result");
+ compiler.add(this, "node_mix_color");
+}
+
+void MixColorNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ if (use_clamp) {
+ fac = clamp(fac, 0.0f, 1.0f);
+ }
+ folder.make_constant_clamp(svm_mix(blend_type, fac, a, b), use_clamp_result);
+ }
+ else {
+ folder.fold_mix_color(blend_type, use_clamp, use_clamp_result);
+ }
+}
+
+/* Mix Float */
+
+NODE_DEFINE(MixFloatNode)
+{
+ NodeType *type = NodeType::add("mix_float", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(fac, "Factor", 0.5f);
+ SOCKET_IN_FLOAT(a, "A", 0.0f);
+ SOCKET_IN_FLOAT(b, "B", 0.0f);
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", true);
+ SOCKET_OUT_FLOAT(result, "Result");
+
+ return type;
+}
+
+MixFloatNode::MixFloatNode() : ShaderNode(get_node_type())
+{
+}
+
+void MixFloatNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *fac_in = input("Factor");
+ ShaderInput *a_in = input("A");
+ ShaderInput *b_in = input("B");
+ ShaderOutput *result_out = output("Result");
+
+ int fac_in_stack_offset = compiler.stack_assign(fac_in);
+ int a_in_stack_offset = compiler.stack_assign(a_in);
+ int b_in_stack_offset = compiler.stack_assign(b_in);
+
+ compiler.add_node(
+ NODE_MIX_FLOAT,
+ use_clamp,
+ compiler.encode_uchar4(fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset),
+ compiler.stack_assign(result_out));
+}
+
+void MixFloatNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "use_clamp");
+ compiler.add(this, "node_mix_float");
+}
+
+void MixFloatNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ if (use_clamp) {
+ fac = clamp(fac, 0.0f, 1.0f);
+ }
+ folder.make_constant(a * (1 - fac) + b * fac);
+ }
+}
+
+/* Mix Vector */
+
+NODE_DEFINE(MixVectorNode)
+{
+ NodeType *type = NodeType::add("mix_vector", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(fac, "Factor", 0.5f);
+ SOCKET_IN_VECTOR(a, "A", zero_float3());
+ SOCKET_IN_VECTOR(b, "B", zero_float3());
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", true);
+
+ SOCKET_OUT_VECTOR(result, "Result");
+
+ return type;
+}
+
+MixVectorNode::MixVectorNode() : ShaderNode(get_node_type())
+{
+}
+
+void MixVectorNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *fac_in = input("Factor");
+ ShaderInput *a_in = input("A");
+ ShaderInput *b_in = input("B");
+ ShaderOutput *result_out = output("Result");
+
+ int fac_in_stack_offset = compiler.stack_assign(fac_in);
+ int a_in_stack_offset = compiler.stack_assign(a_in);
+ int b_in_stack_offset = compiler.stack_assign(b_in);
+
+ compiler.add_node(
+ NODE_MIX_VECTOR,
+ compiler.encode_uchar4(use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset),
+ compiler.stack_assign(result_out));
+}
+
+void MixVectorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "use_clamp");
+ compiler.add(this, "node_mix_vector");
+}
+
+void MixVectorNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ if (use_clamp) {
+ fac = clamp(fac, 0.0f, 1.0f);
+ }
+ folder.make_constant(a * (one_float3() - fac) + b * fac);
+ }
+}
+
+/* Mix Vector Non Uniform */
+
+NODE_DEFINE(MixVectorNonUniformNode)
+{
+ NodeType *type = NodeType::add("mix_vector_non_uniform", create, NodeType::SHADER);
+
+ SOCKET_IN_VECTOR(fac, "Factor", make_float3(0.5f, 0.5f, 0.5f));
+ SOCKET_IN_VECTOR(a, "A", zero_float3());
+ SOCKET_IN_VECTOR(b, "B", zero_float3());
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", true);
+
+ SOCKET_OUT_VECTOR(result, "Result");
+
+ return type;
+}
+
+MixVectorNonUniformNode::MixVectorNonUniformNode() : ShaderNode(get_node_type())
+{
+}
+
+void MixVectorNonUniformNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *fac_in = input("Factor");
+ ShaderInput *a_in = input("A");
+ ShaderInput *b_in = input("B");
+ ShaderOutput *result_out = output("Result");
+
+ int fac_in_stack_offset = compiler.stack_assign(fac_in);
+ int a_in_stack_offset = compiler.stack_assign(a_in);
+ int b_in_stack_offset = compiler.stack_assign(b_in);
+
+ compiler.add_node(
+ NODE_MIX_VECTOR_NON_UNIFORM,
+ compiler.encode_uchar4(use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset),
+ compiler.stack_assign(result_out));
+}
+
+void MixVectorNonUniformNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "use_clamp");
+ compiler.add(this, "node_mix_vector_non_uniform");
+}
+
+void MixVectorNonUniformNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ if (use_clamp) {
+ fac = saturate(fac);
+ }
+ folder.make_constant(a * (one_float3() - fac) + b * fac);
+ }
+}
+
/* Combine Color */
NODE_DEFINE(CombineColorNode)
diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h
index ac40a397c1e..cc3a71a0697 100644
--- a/intern/cycles/scene/shader_nodes.h
+++ b/intern/cycles/scene/shader_nodes.h
@@ -1101,6 +1101,52 @@ class MixNode : public ShaderNode {
NODE_SOCKET_API(float, fac)
};
+class MixColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MixColorNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, a)
+ NODE_SOCKET_API(float3, b)
+ NODE_SOCKET_API(float, fac)
+ NODE_SOCKET_API(bool, use_clamp)
+ NODE_SOCKET_API(bool, use_clamp_result)
+ NODE_SOCKET_API(NodeMix, blend_type)
+};
+
+class MixFloatNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MixFloatNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float, a)
+ NODE_SOCKET_API(float, b)
+ NODE_SOCKET_API(float, fac)
+ NODE_SOCKET_API(bool, use_clamp)
+};
+
+class MixVectorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MixVectorNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, a)
+ NODE_SOCKET_API(float3, b)
+ NODE_SOCKET_API(float, fac)
+ NODE_SOCKET_API(bool, use_clamp)
+};
+
+class MixVectorNonUniformNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MixVectorNonUniformNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(float3, a)
+ NODE_SOCKET_API(float3, b)
+ NODE_SOCKET_API(float3, fac)
+ NODE_SOCKET_API(bool, use_clamp)
+};
+
class CombineColorNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineColorNode)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 2342ba33a3b..2091457aa59 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -424,7 +424,6 @@ shader_node_categories = [
NodeItem("ShaderNodeTexWhiteNoise"),
]),
ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[
- NodeItem("ShaderNodeMixRGB"),
NodeItem("ShaderNodeRGBCurve"),
NodeItem("ShaderNodeInvert"),
NodeItem("ShaderNodeLightFalloff"),
@@ -448,6 +447,7 @@ shader_node_categories = [
NodeItem("ShaderNodeFloatCurve"),
NodeItem("ShaderNodeClamp"),
NodeItem("ShaderNodeMath"),
+ NodeItem("ShaderNodeMix"),
NodeItem("ShaderNodeValToRGB"),
NodeItem("ShaderNodeRGBToBW"),
NodeItem("ShaderNodeShaderToRGB", poll=object_eevee_shader_nodes_poll),
@@ -651,7 +651,6 @@ geometry_node_categories = [
NodeItem("GeometryNodeStoreNamedAttribute"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
- NodeItem("ShaderNodeMixRGB"),
NodeItem("ShaderNodeRGBCurve"),
NodeItem("ShaderNodeValToRGB"),
NodeItem("FunctionNodeSeparateColor"),
@@ -719,6 +718,7 @@ geometry_node_categories = [
NodeItem("FunctionNodeBooleanMath"),
NodeItem("FunctionNodeRotateEuler"),
NodeItem("FunctionNodeCompare"),
+ NodeItem("ShaderNodeMix"),
NodeItem("FunctionNodeFloatToInt"),
NodeItem("GeometryNodeSwitch"),
NodeItem("FunctionNodeRandomValue"),
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 509de0620c6..1118552b643 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1102,7 +1102,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
//#define SH_NODE_MATERIAL 100
#define SH_NODE_RGB 101
#define SH_NODE_VALUE 102
-#define SH_NODE_MIX_RGB 103
+#define SH_NODE_MIX_RGB_LEGACY 103
#define SH_NODE_VALTORGB 104
#define SH_NODE_RGBTOBW 105
#define SH_NODE_SHADERTORGB 106
@@ -1205,6 +1205,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_POINT_INFO 710
#define SH_NODE_COMBINE_COLOR 711
#define SH_NODE_SEPARATE_COLOR 712
+#define SH_NODE_MIX 713
/** \} */
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 4ed2885dd90..1a40c0a18ed 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4583,6 +4583,7 @@ static void registerShaderNodes()
register_node_type_sh_wavelength();
register_node_type_sh_blackbody();
register_node_type_sh_mix_rgb();
+ register_node_type_sh_mix();
register_node_type_sh_valtorgb();
register_node_type_sh_rgbtobw();
register_node_type_sh_shadertorgb();
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index b98f8996a2c..4d604fc7eec 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -1697,6 +1697,27 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
}
}
+static void versioning_replace_legacy_mix_rgb_node(bNodeTree *ntree)
+{
+ version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Fac", "Factor_Float");
+ version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color1", "A_Color");
+ version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color2", "B_Color");
+ version_node_output_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color", "Result_Color");
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MIX_RGB_LEGACY) {
+ strcpy(node->idname, "ShaderNodeMix");
+ node->type = SH_NODE_MIX;
+ NodeShaderMix *data = (NodeShaderMix *)MEM_callocN(sizeof(NodeShaderMix), __func__);
+ data->blend_type = node->custom1;
+ data->clamp_result = node->custom2;
+ data->clamp_factor = 1;
+ data->data_type = SOCK_RGBA;
+ data->factor_mode = NODE_MIX_MODE_UNIFORM;
+ node->storage = data;
+ }
+ }
+}
+
static void version_fix_image_format_copy(Main *bmain, ImageFormatData *format)
{
/* Fix bug where curves in image format were not properly copied to file output
@@ -3332,5 +3353,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Convert mix rgb node to new mix node and add storage. */
+ {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ versioning_replace_legacy_mix_rgb_node(ntree);
+ }
+ FOREACH_NODETREE_END;
+ }
}
}
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 25ab06850f5..e8325d658ca 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -477,7 +477,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_RGB:
ntype->draw_buttons = node_buts_rgb;
break;
- case SH_NODE_MIX_RGB:
+ case SH_NODE_MIX_RGB_LEGACY:
ntype->draw_buttons = node_buts_mix_rgb;
break;
case SH_NODE_VALTORGB:
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 87a2d1620aa..3df0d723aec 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -232,7 +232,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain,
storage = (NodeShaderAttribute *)input_attr_color->storage;
BLI_strncpy(storage->name, "Color", sizeof(storage->name));
- bNode *mix_rgb_color = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB);
+ bNode *mix_rgb_color = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB_LEGACY);
mix_rgb_color->custom1 = MA_RAMP_BLEND; // Mix
mix_rgb_color->locx = 200.0f;
mix_rgb_color->locy = -200.0f;
@@ -246,7 +246,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain,
storage = (NodeShaderAttribute *)input_attr_alpha->storage;
BLI_strncpy(storage->name, "Alpha", sizeof(storage->name));
- bNode *mix_rgb_alpha = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB);
+ bNode *mix_rgb_alpha = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB_LEGACY);
mix_rgb_alpha->custom1 = MA_RAMP_BLEND; // Mix
mix_rgb_alpha->locx = 600.0f;
mix_rgb_alpha->locy = 300.0f;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 0c11ecb293b..c289a21421a 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -394,6 +394,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_light_path.glsl
shaders/material/gpu_shader_material_mapping.glsl
shaders/material/gpu_shader_material_map_range.glsl
+ shaders/material/gpu_shader_material_mix_color.glsl
shaders/material/gpu_shader_material_mix_shader.glsl
shaders/material/gpu_shader_material_noise.glsl
shaders/material/gpu_shader_material_normal.glsl
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl
new file mode 100644
index 00000000000..933a8de9cb7
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl
@@ -0,0 +1,537 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void node_mix_blend(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+ outcol = mix(col1, col2, fac);
+ outcol.a = col1.a;
+}
+
+void node_mix_add(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ outcol = mix(col1, col1 + col2, fac);
+ outcol.a = col1.a;
+}
+
+void node_mix_mult(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ outcol = mix(col1, col1 * col2, fac);
+ outcol.a = col1.a;
+}
+
+void node_mix_screen(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float facm = 1.0 - fac;
+
+ outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
+ outcol.a = col1.a;
+}
+
+void node_mix_overlay(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ if (outcol.r < 0.5) {
+ outcol.r *= facm + 2.0 * fac * col2.r;
+ }
+ else {
+ outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r);
+ }
+
+ if (outcol.g < 0.5) {
+ outcol.g *= facm + 2.0 * fac * col2.g;
+ }
+ else {
+ outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g);
+ }
+
+ if (outcol.b < 0.5) {
+ outcol.b *= facm + 2.0 * fac * col2.b;
+ }
+ else {
+ outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b);
+ }
+}
+
+void node_mix_sub(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ outcol = mix(col1, col1 - col2, fac);
+ outcol.a = col1.a;
+}
+
+/* A variant of mix_div that fallback to the first color upon zero division. */
+void node_mix_div_fallback(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ if (col2.r != 0.0) {
+ outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
+ }
+ if (col2.g != 0.0) {
+ outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
+ }
+ if (col2.b != 0.0) {
+ outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
+ }
+}
+
+void node_mix_diff(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ outcol = mix(col1, abs(col1 - col2), fac);
+ outcol.a = col1.a;
+}
+
+void node_mix_dark(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ outcol.rgb = mix(col1.rgb, min(col1.rgb, col2.rgb), fac);
+ outcol.a = col1.a;
+}
+
+void node_mix_light(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+ outcol.rgb = mix(col1.rgb, max(col1.rgb, col2.rgb), fac);
+ outcol.a = col1.a;
+}
+
+void node_mix_dodge(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+ outcol = col1;
+
+ if (outcol.r != 0.0) {
+ float tmp = 1.0 - fac * col2.r;
+ if (tmp <= 0.0) {
+ outcol.r = 1.0;
+ }
+ else if ((tmp = outcol.r / tmp) > 1.0) {
+ outcol.r = 1.0;
+ }
+ else {
+ outcol.r = tmp;
+ }
+ }
+ if (outcol.g != 0.0) {
+ float tmp = 1.0 - fac * col2.g;
+ if (tmp <= 0.0) {
+ outcol.g = 1.0;
+ }
+ else if ((tmp = outcol.g / tmp) > 1.0) {
+ outcol.g = 1.0;
+ }
+ else {
+ outcol.g = tmp;
+ }
+ }
+ if (outcol.b != 0.0) {
+ float tmp = 1.0 - fac * col2.b;
+ if (tmp <= 0.0) {
+ outcol.b = 1.0;
+ }
+ else if ((tmp = outcol.b / tmp) > 1.0) {
+ outcol.b = 1.0;
+ }
+ else {
+ outcol.b = tmp;
+ }
+ }
+}
+
+void node_mix_burn(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float tmp, facm = 1.0 - fac;
+
+ outcol = col1;
+
+ tmp = facm + fac * col2.r;
+ if (tmp <= 0.0) {
+ outcol.r = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0) {
+ outcol.r = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.r = 1.0;
+ }
+ else {
+ outcol.r = tmp;
+ }
+
+ tmp = facm + fac * col2.g;
+ if (tmp <= 0.0) {
+ outcol.g = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0) {
+ outcol.g = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.g = 1.0;
+ }
+ else {
+ outcol.g = tmp;
+ }
+
+ tmp = facm + fac * col2.b;
+ if (tmp <= 0.0) {
+ outcol.b = 0.0;
+ }
+ else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0) {
+ outcol.b = 0.0;
+ }
+ else if (tmp > 1.0) {
+ outcol.b = 1.0;
+ }
+ else {
+ outcol.b = tmp;
+ }
+}
+
+void node_mix_hue(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2, tmp;
+ rgb_to_hsv(col2, hsv2);
+
+ if (hsv2.y != 0.0) {
+ rgb_to_hsv(outcol, hsv);
+ hsv.x = hsv2.x;
+ hsv_to_rgb(hsv, tmp);
+
+ outcol = mix(outcol, tmp, fac);
+ outcol.a = col1.a;
+ }
+}
+
+void node_mix_sat(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2;
+ rgb_to_hsv(outcol, hsv);
+
+ if (hsv.y != 0.0) {
+ rgb_to_hsv(col2, hsv2);
+
+ hsv.y = facm * hsv.y + fac * hsv2.y;
+ hsv_to_rgb(hsv, outcol);
+ }
+}
+
+void node_mix_val(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float facm = 1.0 - fac;
+
+ vec4 hsv, hsv2;
+ rgb_to_hsv(col1, hsv);
+ rgb_to_hsv(col2, hsv2);
+
+ hsv.z = facm * hsv.z + fac * hsv2.z;
+ hsv_to_rgb(hsv, outcol);
+}
+
+void node_mix_color(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float facm = 1.0 - fac;
+
+ outcol = col1;
+
+ vec4 hsv, hsv2, tmp;
+ rgb_to_hsv(col2, hsv2);
+
+ if (hsv2.y != 0.0) {
+ rgb_to_hsv(outcol, hsv);
+ hsv.x = hsv2.x;
+ hsv.y = hsv2.y;
+ hsv_to_rgb(hsv, tmp);
+
+ outcol = mix(outcol, tmp, fac);
+ outcol.a = col1.a;
+ }
+}
+
+void node_mix_soft(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ float facm = 1.0 - fac;
+
+ vec4 one = vec4(1.0);
+ vec4 scr = one - (one - col2) * (one - col1);
+ outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
+}
+
+void node_mix_linear(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
+}
+
+void node_mix_float(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ outfloat = mix(f1, f2, fac);
+}
+
+void node_mix_vector(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+
+ outvec = mix(v1, v2, fac);
+}
+
+void node_mix_vector_non_uniform(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+ outvec = mix(v1, v2, facvec);
+}
+
+void node_mix_rgba(float fac,
+ vec3 facvec,
+ float f1,
+ float f2,
+ vec3 v1,
+ vec3 v2,
+ vec4 col1,
+ vec4 col2,
+ out float outfloat,
+ out vec3 outvec,
+ out vec4 outcol)
+{
+ outcol = mix(col1, col2, fac);
+}
+
+void node_mix_clamp_vector(vec3 vec, vec3 min, vec3 max, out vec3 outvec)
+{
+ outvec = clamp(vec, min, max);
+}
+
+void node_mix_clamp_value(float value, float min, float max, out float outfloat)
+{
+ outfloat = clamp(value, min, max);
+}
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 3477105f519..4ae06d0a5e4 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1475,6 +1475,17 @@ typedef struct NodeCombSepColor {
int8_t mode;
} NodeCombSepColor;
+typedef struct NodeShaderMix {
+ /* eNodeSocketDatatype */
+ int8_t data_type;
+ /* NodeShaderMixMode */
+ int8_t factor_mode;
+ int8_t clamp_factor;
+ int8_t clamp_result;
+ int8_t blend_type;
+ char _pad[3];
+} NodeShaderMix;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1762,6 +1773,11 @@ typedef enum NodeBooleanMathOperation {
NODE_BOOLEAN_MATH_NIMPLY = 8,
} NodeBooleanMathOperation;
+typedef enum NodeShaderMixMode {
+ NODE_MIX_MODE_UNIFORM = 0,
+ NODE_MIX_MODE_NON_UNIFORM = 1,
+} NodeShaderMixMode;
+
typedef enum NodeCompareMode {
NODE_COMPARE_MODE_ELEMENT = 0,
NODE_COMPARE_MODE_LENGTH = 1,
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 1573a1df002..60a57bae78a 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -4927,6 +4927,54 @@ static void def_compare(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_sh_mix(StructRNA *srna)
+{
+ static const EnumPropertyItem rna_enum_mix_data_type_items[] = {
+ {SOCK_FLOAT, "FLOAT", 0, "Float", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_RGBA, "RGBA", 0, "Color", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem rna_enum_mix_mode_items[] = {
+ {NODE_MIX_MODE_UNIFORM, "UNIFORM", 0, "Uniform", "Use a single factor for all components"},
+ {NODE_MIX_MODE_NON_UNIFORM, "NON_UNIFORM", 0, "Non-Uniform", "Per component factor"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeShaderMix", "storage");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_mix_data_type_items);
+ RNA_def_property_enum_default(prop, SOCK_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "factor_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_mix_mode_items);
+ RNA_def_property_enum_default(prop, SOCK_FLOAT);
+ RNA_def_property_ui_text(prop, "Factor Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "blend_type");
+ RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
+ RNA_def_property_ui_text(prop, "Blending Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "clamp_factor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "clamp_factor", 1);
+ RNA_def_property_ui_text(prop, "Clamp Factor", "Clamp the factor to [0,1] range");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "clamp_result", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "clamp_result", 1);
+ RNA_def_property_ui_text(prop, "Clamp Result", "Clamp the result to [0,1] range");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_float_to_int(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10964,6 +11012,12 @@ static void rna_def_node_socket(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Linked", "True if the socket is connected");
+ prop = RNA_def_property(srna, "is_unavailable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_UNAVAIL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop, "Unavailable", "True if the socket is unavailable");
+
prop = RNA_def_property(srna, "is_multi_input", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_MULTI_INPUT);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 1d1310360b8..8fe77bffaad 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -26,6 +26,7 @@ void register_node_type_sh_camera(void);
void register_node_type_sh_value(void);
void register_node_type_sh_rgb(void);
void register_node_type_sh_mix_rgb(void);
+void register_node_type_sh_mix(void);
void register_node_type_sh_valtorgb(void);
void register_node_type_sh_rgbtobw(void);
void register_node_type_sh_shadertorgb(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 786ce88152e..e6cdd462c66 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -25,7 +25,7 @@ DefNode(Node, NODE_REROUTE, 0, "REROUT
DefNode(ShaderNode, SH_NODE_RGB, 0, "RGB", RGB, "RGB", "A color picker")
DefNode(ShaderNode, SH_NODE_VALUE, 0, "VALUE", Value, "Value", "Used to Input numerical values to other nodes in the tree")
-DefNode(ShaderNode, SH_NODE_MIX_RGB, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "Mix two input colors")
+DefNode(ShaderNode, SH_NODE_MIX_RGB_LEGACY, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "Mix two input colors")
DefNode(ShaderNode, SH_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "Map values to colors with the use of a gradient")
DefNode(ShaderNode, SH_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "Convert a color's luminance to a grayscale value")
DefNode(ShaderNode, SH_NODE_SHADERTORGB, 0, "SHADERTORGB", ShaderToRGB, "Shader to RGB", "Convert rendering effect (such as light and shadow) to color. Typically used for non-photorealistic rendering, to apply additional effects on the output of BSDFs.\nNote: only supported for Eevee")
@@ -122,6 +122,7 @@ DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUT
DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "Map an input float to a curve and outputs a float value")
DefNode(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "Create a color from individual components using multiple models")
DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "Split a color into its individual components using multiple models")
+DefNode(ShaderNode, SH_NODE_MIX, def_sh_mix, "MIX", Mix, "Mix", "Mix values by a factor")
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
index 3e90f185168..d135f9a12a4 100644
--- a/source/blender/nodes/shader/CMakeLists.txt
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRC
nodes/node_shader_mapping.cc
nodes/node_shader_math.cc
nodes/node_shader_mix_rgb.cc
+ nodes/node_shader_mix.cc
nodes/node_shader_mix_shader.cc
nodes/node_shader_normal.cc
nodes/node_shader_normal_map.cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix.cc b/source/blender/nodes/shader/nodes/node_shader_mix.cc
new file mode 100644
index 00000000000..05aad262af8
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_mix.cc
@@ -0,0 +1,443 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2005 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include <algorithm>
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_shader_util.hh"
+
+#include "NOD_socket_search_link.hh"
+#include "RNA_enum_types.h"
+
+namespace blender::nodes::node_sh_mix_cc {
+
+NODE_STORAGE_FUNCS(NodeShaderMix)
+
+static void sh_node_mix_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("Factor"), "Factor_Float")
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Factor"), "Factor_Vector")
+ .default_value(float3(0.5f))
+ .subtype(PROP_FACTOR);
+
+ b.add_input<decl::Float>(N_("A"), "A_Float")
+ .min(-10000.0f)
+ .max(10000.0f)
+ .is_default_link_socket();
+ b.add_input<decl::Float>(N_("B"), "B_Float").min(-10000.0f).max(10000.0f);
+
+ b.add_input<decl::Vector>(N_("A"), "A_Vector").is_default_link_socket();
+ b.add_input<decl::Vector>(N_("B"), "B_Vector");
+
+ b.add_input<decl::Color>(N_("A"), "A_Color")
+ .default_value({0.5f, 0.5f, 0.5f, 1.0f})
+ .is_default_link_socket();
+ b.add_input<decl::Color>(N_("B"), "B_Color").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+
+ b.add_output<decl::Float>(N_("Result"), "Result_Float");
+ b.add_output<decl::Vector>(N_("Result"), "Result_Vector");
+ b.add_output<decl::Color>(N_("Result"), "Result_Color");
+};
+
+static void sh_node_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ const NodeShaderMix &data = node_storage(*static_cast<const bNode *>(ptr->data));
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ if (data.data_type == SOCK_VECTOR) {
+ uiItemR(layout, ptr, "factor_mode", 0, "", ICON_NONE);
+ }
+ if (data.data_type == SOCK_RGBA) {
+ uiItemR(layout, ptr, "blend_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "clamp_result", 0, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "clamp_factor", 0, nullptr, ICON_NONE);
+ }
+ else {
+ uiItemR(layout, ptr, "clamp_factor", 0, nullptr, ICON_NONE);
+ }
+}
+
+static void sh_node_mix_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
+{
+ const NodeShaderMix &storage = node_storage(*node);
+ if (storage.data_type == SOCK_RGBA) {
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, storage.blend_type, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+ }
+}
+
+static int sh_node_mix_ui_class(const bNode *node)
+{
+ const NodeShaderMix &storage = node_storage(*node);
+ const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.data_type);
+
+ switch (data_type) {
+ case SOCK_VECTOR:
+ return NODE_CLASS_OP_VECTOR;
+ case SOCK_RGBA:
+ return NODE_CLASS_OP_COLOR;
+ default:
+ return NODE_CLASS_CONVERTER;
+ }
+}
+
+static void sh_node_mix_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeShaderMix &storage = node_storage(*node);
+ const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.data_type);
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == data_type);
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == data_type);
+ }
+
+ bool use_vector_factor = data_type == SOCK_VECTOR &&
+ storage.factor_mode != NODE_MIX_MODE_UNIFORM;
+
+ bNodeSocket *sock_factor = (bNodeSocket *)BLI_findlink(&node->inputs, 0);
+ nodeSetSocketAvailability(ntree, sock_factor, !use_vector_factor);
+
+ bNodeSocket *sock_factor_vec = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+ nodeSetSocketAvailability(ntree, sock_factor_vec, use_vector_factor);
+}
+
+static void node_mix_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const eNodeSocketDatatype sock_type = static_cast<eNodeSocketDatatype>(
+ params.other_socket().type);
+
+ if (ELEM(sock_type, SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_VECTOR, SOCK_INT)) {
+ const eNodeSocketDatatype type = ELEM(sock_type, SOCK_BOOLEAN, SOCK_INT) ? SOCK_FLOAT :
+ sock_type;
+
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(IFACE_("Result"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeMix");
+ node_storage(node).data_type = type;
+ params.update_and_connect_available_socket(node, "Result");
+ });
+ }
+ else {
+ if (ELEM(sock_type, SOCK_VECTOR, SOCK_RGBA)) {
+ params.add_item(IFACE_("Factor (Non-Uniform)"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeMix");
+ node_storage(node).data_type = SOCK_VECTOR;
+ node_storage(node).factor_mode = NODE_MIX_MODE_NON_UNIFORM;
+ params.update_and_connect_available_socket(node, "Factor");
+ });
+ }
+ params.add_item(IFACE_("Factor"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeMix");
+ node_storage(node).data_type = type;
+ params.update_and_connect_available_socket(node, "Factor");
+ });
+ params.add_item(IFACE_("A"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeMix");
+ node_storage(node).data_type = type;
+ params.update_and_connect_available_socket(node, "A");
+ });
+ params.add_item(IFACE_("B"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeMix");
+ node_storage(node).data_type = type;
+ params.update_and_connect_available_socket(node, "B");
+ });
+ }
+ }
+}
+
+static void node_mix_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeShaderMix *data = MEM_cnew<NodeShaderMix>(__func__);
+ data->data_type = SOCK_FLOAT;
+ data->factor_mode = NODE_MIX_MODE_UNIFORM;
+ data->clamp_factor = 1;
+ data->clamp_result = 0;
+ data->blend_type = MA_RAMP_BLEND;
+ node->storage = data;
+}
+
+static const char *gpu_shader_get_name(eNodeSocketDatatype data_type,
+ const bool non_uniform,
+ const int blend_type)
+{
+ switch (data_type) {
+ case SOCK_FLOAT:
+ return "node_mix_float";
+ case SOCK_VECTOR:
+ return (non_uniform) ? "node_mix_vector_non_uniform" : "node_mix_vector";
+ case SOCK_RGBA:
+ switch (blend_type) {
+ case MA_RAMP_BLEND:
+ return "node_mix_blend";
+ case MA_RAMP_ADD:
+ return "node_mix_add";
+ case MA_RAMP_MULT:
+ return "node_mix_mult";
+ case MA_RAMP_SUB:
+ return "node_mix_sub";
+ case MA_RAMP_SCREEN:
+ return "node_mix_screen";
+ case MA_RAMP_DIV:
+ return "node_mix_div_fallback";
+ case MA_RAMP_DIFF:
+ return "node_mix_diff";
+ case MA_RAMP_DARK:
+ return "node_mix_dark";
+ case MA_RAMP_LIGHT:
+ return "node_mix_light";
+ case MA_RAMP_OVERLAY:
+ return "node_mix_overlay";
+ case MA_RAMP_DODGE:
+ return "node_mix_dodge";
+ case MA_RAMP_BURN:
+ return "node_mix_burn";
+ case MA_RAMP_HUE:
+ return "node_mix_hue";
+ case MA_RAMP_SAT:
+ return "node_mix_sat";
+ case MA_RAMP_VAL:
+ return "node_mix_val";
+ case MA_RAMP_COLOR:
+ return "node_mix_color";
+ case MA_RAMP_SOFT:
+ return "node_mix_soft";
+ case MA_RAMP_LINEAR:
+ return "node_mix_linear";
+ default:
+ BLI_assert_unreachable();
+ return nullptr;
+ }
+ default:
+ BLI_assert_unreachable();
+ return nullptr;
+ }
+}
+
+static int gpu_shader_mix(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const NodeShaderMix &storage = node_storage(*node);
+ const bool is_non_uniform = storage.factor_mode == NODE_MIX_MODE_NON_UNIFORM;
+ const bool is_color_mode = storage.data_type == SOCK_RGBA;
+ const bool is_vector_mode = storage.data_type == SOCK_VECTOR;
+ const int blend_type = storage.blend_type;
+ const char *name = gpu_shader_get_name(
+ (eNodeSocketDatatype)storage.data_type, is_non_uniform, blend_type);
+
+ if (name == nullptr) {
+ return 0;
+ }
+
+ if (storage.clamp_factor) {
+ if (is_non_uniform && is_vector_mode) {
+ const float min[3] = {0.0f, 0.0f, 0.0f};
+ const float max[3] = {1.0f, 1.0f, 1.0f};
+ const GPUNodeLink *factor_link = in[1].link ? in[1].link : GPU_uniform(in[1].vec);
+ GPU_link(mat,
+ "node_mix_clamp_vector",
+ factor_link,
+ GPU_constant(min),
+ GPU_constant(max),
+ &in[1].link);
+ }
+ else {
+ const float min = 0.0f;
+ const float max = 1.0f;
+ const GPUNodeLink *factor_link = in[0].link ? in[0].link : GPU_uniform(in[0].vec);
+ GPU_link(mat,
+ "node_mix_clamp_value",
+ factor_link,
+ GPU_constant(&min),
+ GPU_constant(&max),
+ &in[0].link);
+ }
+ }
+
+ int ret = GPU_stack_link(mat, node, name, in, out);
+
+ if (ret && is_color_mode && storage.clamp_result) {
+ const float min[3] = {0.0f, 0.0f, 0.0f};
+ const float max[3] = {1.0f, 1.0f, 1.0f};
+ GPU_link(mat,
+ "node_mix_clamp_vector",
+ out[2].link,
+ GPU_constant(min),
+ GPU_constant(max),
+ &out[2].link);
+ }
+ return ret;
+}
+
+class MixColorFunction : public fn::MultiFunction {
+ private:
+ const bool clamp_factor_;
+ const bool clamp_result_;
+ const int blend_type_;
+
+ public:
+ MixColorFunction(const bool clamp_factor, const bool clamp_result, const int blend_type)
+ : clamp_factor_(clamp_factor), clamp_result_(clamp_result), blend_type_(blend_type)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"MixColor"};
+ signature.single_input<float>("Factor");
+ signature.single_input<ColorGeometry4f>("A");
+ signature.single_input<ColorGeometry4f>("B");
+ signature.single_output<ColorGeometry4f>("Result");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float> &fac = params.readonly_single_input<float>(0, "Factor");
+ const VArray<ColorGeometry4f> &col1 = params.readonly_single_input<ColorGeometry4f>(1, "A");
+ const VArray<ColorGeometry4f> &col2 = params.readonly_single_input<ColorGeometry4f>(2, "B");
+ MutableSpan<ColorGeometry4f> results = params.uninitialized_single_output<ColorGeometry4f>(
+ 3, "Result");
+
+ if (clamp_factor_) {
+ for (int64_t i : mask) {
+ results[i] = col1[i];
+ ramp_blend(blend_type_, results[i], std::clamp(fac[i], 0.0f, 1.0f), col2[i]);
+ }
+ }
+ else {
+ for (int64_t i : mask) {
+ results[i] = col1[i];
+ ramp_blend(blend_type_, results[i], fac[i], col2[i]);
+ }
+ }
+
+ if (clamp_result_) {
+ for (int64_t i : mask) {
+ clamp_v3(results[i], 0.0f, 1.0f);
+ }
+ }
+ }
+};
+
+static const fn::MultiFunction *get_multi_function(bNode &node)
+{
+ const NodeShaderMix *data = (NodeShaderMix *)node.storage;
+ bool uniform_factor = data->factor_mode == NODE_MIX_MODE_UNIFORM;
+ const bool clamp_factor = data->clamp_factor;
+ switch (data->data_type) {
+ case SOCK_FLOAT: {
+ if (clamp_factor) {
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
+ "Clamp Mix Float", [](float t, const float a, const float b) {
+ return math::interpolate(a, b, std::clamp(t, 0.0f, 1.0f));
+ }};
+ return &fn;
+ }
+ else {
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
+ "Mix Float", [](const float t, const float a, const float b) {
+ return math::interpolate(a, b, t);
+ }};
+ return &fn;
+ }
+ }
+ case SOCK_VECTOR: {
+ if (clamp_factor) {
+ if (uniform_factor) {
+ static fn::CustomMF_SI_SI_SI_SO<float, float3, float3, float3> fn{
+ "Clamp Mix Vector", [](const float t, const float3 a, const float3 b) {
+ return math::interpolate(a, b, std::clamp(t, 0.0f, 1.0f));
+ }};
+ return &fn;
+ }
+ else {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
+ "Clamp Mix Vector Non Uniform", [](float3 t, const float3 a, const float3 b) {
+ t = math::clamp(t, 0.0f, 1.0f);
+ return a * (float3(1.0f) - t) + b * t;
+ }};
+ return &fn;
+ }
+ }
+ else {
+ if (uniform_factor) {
+ static fn::CustomMF_SI_SI_SI_SO<float, float3, float3, float3> fn{
+ "Mix Vector", [](const float t, const float3 a, const float3 b) {
+ return math::interpolate(a, b, t);
+ }};
+ return &fn;
+ }
+ else {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
+ "Mix Vector Non Uniform", [](const float3 t, const float3 a, const float3 b) {
+ return a * (float3(1.0f) - t) + b * t;
+ }};
+ return &fn;
+ }
+ }
+ }
+ }
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static void sh_node_mix_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const NodeShaderMix &storage = node_storage(builder.node());
+
+ if (storage.data_type == SOCK_RGBA) {
+ builder.construct_and_set_matching_fn<MixColorFunction>(
+ storage.clamp_factor, storage.clamp_result, storage.blend_type);
+ }
+ else {
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+ }
+}
+
+} // namespace blender::nodes::node_sh_mix_cc
+
+void register_node_type_sh_mix()
+{
+ namespace file_ns = blender::nodes::node_sh_mix_cc;
+
+ static bNodeType ntype;
+ sh_fn_node_type_base(&ntype, SH_NODE_MIX, "Mix", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_mix_declare;
+ ntype.ui_class = file_ns::sh_node_mix_ui_class;
+ node_type_gpu(&ntype, file_ns::gpu_shader_mix);
+ node_type_update(&ntype, file_ns::sh_node_mix_update);
+ node_type_init(&ntype, file_ns::node_mix_init);
+ node_type_storage(
+ &ntype, "NodeShaderMix", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = file_ns::sh_node_mix_build_multi_function;
+ ntype.draw_buttons = file_ns::sh_node_mix_layout;
+ ntype.labelfunc = file_ns::sh_node_mix_label;
+ ntype.gather_link_search_ops = file_ns::node_mix_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
index 478a6812c36..edbded43acf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -150,11 +150,11 @@ void register_node_type_sh_mix_rgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
+ sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB_LEGACY, "Mix", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::sh_node_mix_rgb_declare;
ntype.labelfunc = node_blend_label;
node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb);
ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
-
+ ntype.gather_link_search_ops = nullptr;
nodeRegisterType(&ntype);
}