Node: Mix node
This patch is a response to T92588 and is implemented as a Function/Shader node. This node has support for Float, Vector and Color data types. For Vector it supports uniform and non-uniform mixing. For Color it now has the option to remove factor clamping. It replaces the Mix RGB for Shader and Geometry node trees. As discussed in T96219, this patch converts existing nodes in .blend files. The old node is still available in the Python API but hidden from the menus. Reviewed By: HooglyBoogly, JacquesLucke, simonthommes, brecht Maniphest Tasks: T92588 Differential Revision: https://developer.blender.org/D13749temp-outliner-new-element-storage
parent
0331a8c67c
commit
bfa0ee13d5
Notes:
blender-bot
7 hours ago
Referenced by issue #92588: Mix Node
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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 ¶ms)
|
||||
{
|
||||
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 ¶ms) {
|
||||
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 ¶ms) {
|
||||
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 ¶ms) {
|
||||
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 ¶ms) {
|
||||
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 ¶ms) {
|
||||
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);
|
||||
}
|
||||
Loading…
Reference in new issue