Nodes: improve mix node usage inference when some inputs are unknown

This is similar to #139331. If the mix factor is 0 or 1, we can sometimes
compute the output value even if an input of the mix node is unknown.

Pull Request: https://projects.blender.org/blender/blender/pulls/139513
This commit is contained in:
Jacques Lucke
2025-05-28 07:33:39 +02:00
parent d1c1c58945
commit 281886cfdc

View File

@@ -597,6 +597,14 @@ struct SocketUsageInferencer {
this->value_task__output__generic_switch(socket, menu_switch__is_socket_selected);
return;
}
case SH_NODE_MIX: {
this->value_task__output__generic_switch(socket, mix_node__is_socket_selected);
return;
}
case SH_NODE_MIX_SHADER: {
this->value_task__output__generic_switch(socket, shader_mix_node__is_socket_selected);
return;
}
case SH_NODE_MATH: {
this->value_task__output__float_math(socket);
return;
@@ -853,8 +861,8 @@ struct SocketUsageInferencer {
}
/**
* Assumes that the first input is a condition that selects one of the remaining inputs which is
* then output. If necessary, this can trigger a value task for the condition socket.
* Assumes that the first available input is a condition that selects one of the remaining inputs
* which is then output.
*/
void value_task__output__generic_switch(
const SocketInContext &socket,
@@ -863,9 +871,10 @@ struct SocketUsageInferencer {
{
const NodeInContext node = socket.owner_node();
BLI_assert(node->input_sockets().size() >= 1);
BLI_assert(node->output_sockets().size() == 1);
BLI_assert(node->output_sockets().size() >= 1);
const SocketInContext condition_socket = node.input_socket(0);
const SocketInContext condition_socket{
socket.context, this->get_first_available_bsocket(node->input_sockets())};
const std::optional<const void *> condition_value = all_socket_values_.lookup_try(
condition_socket);
if (!condition_value.has_value()) {
@@ -877,24 +886,46 @@ struct SocketUsageInferencer {
all_socket_values_.add_new(socket, nullptr);
return;
}
for (const int input_i : node->input_sockets().index_range().drop_front(1)) {
Vector<const bNodeSocket *> selected_inputs;
for (const int input_i :
node->input_sockets().index_range().drop_front(condition_socket->index() + 1))
{
const SocketInContext input_socket = node.input_socket(input_i);
if (!input_socket->is_available()) {
continue;
}
if (input_socket->type == SOCK_CUSTOM && STREQ(input_socket->idname, "NodeSocketVirtual")) {
continue;
}
const bool is_selected = is_selected_socket(input_socket, *condition_value);
if (!is_selected) {
continue;
if (is_selected) {
selected_inputs.append(input_socket.socket);
}
const std::optional<const void *> input_value = all_socket_values_.lookup_try(input_socket);
}
if (selected_inputs.is_empty()) {
all_socket_values_.add_new(socket, nullptr);
return;
}
if (selected_inputs.size() == 1) {
/* A single input is selected, so just pass through this value without regarding others. */
const SocketInContext selected_input{socket.context, selected_inputs[0]};
const std::optional<const void *> input_value = all_socket_values_.lookup_try(
selected_input);
if (!input_value.has_value()) {
this->push_value_task(input_socket);
this->push_value_task(selected_input);
return;
}
all_socket_values_.add_new(socket, *input_value);
return;
}
/* The condition did not match any of the inputs, so the output is unknown. */
/* Multiple inputs are selected. */
if (node->typeinfo->build_multi_function) {
/* Try to compute the output value from the multiple selected inputs. */
this->value_task__output__multi_function_node(socket);
return;
}
/* Can't compute the output value, so set it to be unknown. */
all_socket_values_.add_new(socket, nullptr);
}