Geometry Nodes: Switch Node Fields Update
This update of the Switch node allows for field compatible types to be switched through the node. This includes the following: Float, Int, Bool, String, Vector, and Color The remaining types are processed with the orginal code: Geometry, Object, Collection, Texture, and Material Because the old types require a diffent "switch" socket than the field types, versioning for old files is included to move links of those types to a new switch socket. Once fields of other types are supported, this node can be updated to support them as well. Differential Revision: https://developer.blender.org/D12642
This commit is contained in:
parent
54927caf4f
commit
34cf33eb12
|
@ -39,7 +39,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 31
|
||||
#define BLENDER_FILE_SUBVERSION 32
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
|
|
@ -617,6 +617,32 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
|
|||
do_versions_idproperty_ui_data(bmain);
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 32)) {
|
||||
/* Update Switch Node Non-Fields switch input to Switch_001. */
|
||||
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
||||
if (ntree->type != NTREE_GEOMETRY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
|
||||
if (link->tonode->type == GEO_NODE_SWITCH) {
|
||||
if (STREQ(link->tosock->identifier, "Switch")) {
|
||||
bNode *to_node = link->tonode;
|
||||
|
||||
uint8_t mode = ((NodeSwitch *)to_node->storage)->input_type;
|
||||
if (ELEM(mode,
|
||||
SOCK_GEOMETRY,
|
||||
SOCK_OBJECT,
|
||||
SOCK_COLLECTION,
|
||||
SOCK_TEXTURE,
|
||||
SOCK_MATERIAL)) {
|
||||
link->tosock = link->tosock->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
|
|
@ -19,24 +19,37 @@
|
|||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_material.h"
|
||||
|
||||
#include "FN_multi_function_signature.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void geo_node_switch_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Bool>("Switch");
|
||||
b.add_input<decl::Bool>("Switch").default_value(false).supports_field();
|
||||
b.add_input<decl::Bool>("Switch", "Switch_001").default_value(false);
|
||||
|
||||
b.add_input<decl::Float>("False").supports_field();
|
||||
b.add_input<decl::Float>("True").supports_field();
|
||||
b.add_input<decl::Int>("False", "False_001").min(-100000).max(100000).supports_field();
|
||||
b.add_input<decl::Int>("True", "True_001").min(-100000).max(100000).supports_field();
|
||||
b.add_input<decl::Bool>("False", "False_002").default_value(false).hide_value().supports_field();
|
||||
b.add_input<decl::Bool>("True", "True_002").default_value(true).hide_value().supports_field();
|
||||
b.add_input<decl::Vector>("False", "False_003").supports_field();
|
||||
b.add_input<decl::Vector>("True", "True_003").supports_field();
|
||||
b.add_input<decl::Color>("False", "False_004")
|
||||
.default_value({0.8f, 0.8f, 0.8f, 1.0f})
|
||||
.supports_field();
|
||||
b.add_input<decl::Color>("True", "True_004")
|
||||
.default_value({0.8f, 0.8f, 0.8f, 1.0f})
|
||||
.supports_field();
|
||||
b.add_input<decl::String>("False", "False_005").supports_field();
|
||||
b.add_input<decl::String>("True", "True_005").supports_field();
|
||||
|
||||
b.add_input<decl::Float>("False");
|
||||
b.add_input<decl::Float>("True");
|
||||
b.add_input<decl::Int>("False", "False_001").min(-100000).max(100000);
|
||||
b.add_input<decl::Int>("True", "True_001").min(-100000).max(100000);
|
||||
b.add_input<decl::Bool>("False", "False_002");
|
||||
b.add_input<decl::Bool>("True", "True_002");
|
||||
b.add_input<decl::Vector>("False", "False_003");
|
||||
b.add_input<decl::Vector>("True", "True_003");
|
||||
b.add_input<decl::Color>("False", "False_004").default_value({0.8f, 0.8f, 0.8f, 1.0f});
|
||||
b.add_input<decl::Color>("True", "True_004").default_value({0.8f, 0.8f, 0.8f, 1.0f});
|
||||
b.add_input<decl::String>("False", "False_005");
|
||||
b.add_input<decl::String>("True", "True_005");
|
||||
b.add_input<decl::Geometry>("False", "False_006");
|
||||
b.add_input<decl::Geometry>("True", "True_006");
|
||||
b.add_input<decl::Object>("False", "False_007");
|
||||
|
@ -48,12 +61,12 @@ static void geo_node_switch_declare(NodeDeclarationBuilder &b)
|
|||
b.add_input<decl::Material>("False", "False_010");
|
||||
b.add_input<decl::Material>("True", "True_010");
|
||||
|
||||
b.add_output<decl::Float>("Output");
|
||||
b.add_output<decl::Int>("Output", "Output_001");
|
||||
b.add_output<decl::Bool>("Output", "Output_002");
|
||||
b.add_output<decl::Vector>("Output", "Output_003");
|
||||
b.add_output<decl::Color>("Output", "Output_004");
|
||||
b.add_output<decl::String>("Output", "Output_005");
|
||||
b.add_output<decl::Float>("Output").dependent_field();
|
||||
b.add_output<decl::Int>("Output", "Output_001").dependent_field();
|
||||
b.add_output<decl::Bool>("Output", "Output_002").dependent_field();
|
||||
b.add_output<decl::Vector>("Output", "Output_003").dependent_field();
|
||||
b.add_output<decl::Color>("Output", "Output_004").dependent_field();
|
||||
b.add_output<decl::String>("Output", "Output_005").dependent_field();
|
||||
b.add_output<decl::Geometry>("Output", "Output_006");
|
||||
b.add_output<decl::Object>("Output", "Output_007");
|
||||
b.add_output<decl::Collection>("Output", "Output_008");
|
||||
|
@ -77,91 +90,168 @@ static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node)
|
|||
{
|
||||
NodeSwitch *node_storage = (NodeSwitch *)node->storage;
|
||||
int index = 0;
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
|
||||
nodeSetSocketAvailability(
|
||||
socket, index == 0 || socket->type == (eNodeSocketDatatype)node_storage->input_type);
|
||||
index++;
|
||||
bNodeSocket *field_switch = (bNodeSocket *)node->inputs.first;
|
||||
bNodeSocket *non_field_switch = (bNodeSocket *)field_switch->next;
|
||||
|
||||
const bool fields_type = ELEM((eNodeSocketDatatype)node_storage->input_type,
|
||||
SOCK_FLOAT,
|
||||
SOCK_INT,
|
||||
SOCK_BOOLEAN,
|
||||
SOCK_VECTOR,
|
||||
SOCK_RGBA,
|
||||
SOCK_STRING);
|
||||
|
||||
nodeSetSocketAvailability(field_switch, fields_type);
|
||||
nodeSetSocketAvailability(non_field_switch, !fields_type);
|
||||
|
||||
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &node->inputs, index) {
|
||||
if (index <= 1) {
|
||||
continue;
|
||||
}
|
||||
nodeSetSocketAvailability(socket,
|
||||
socket->type == (eNodeSocketDatatype)node_storage->input_type);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
|
||||
nodeSetSocketAvailability(socket,
|
||||
socket->type == (eNodeSocketDatatype)node_storage->input_type);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void output_input(GeoNodeExecParams ¶ms,
|
||||
const bool input,
|
||||
const StringRef input_suffix,
|
||||
const StringRef output_identifier)
|
||||
template<typename T> class SwitchFieldsFunction : public fn::MultiFunction {
|
||||
public:
|
||||
SwitchFieldsFunction()
|
||||
{
|
||||
static fn::MFSignature signature = create_signature();
|
||||
this->set_signature(&signature);
|
||||
}
|
||||
static fn::MFSignature create_signature()
|
||||
{
|
||||
fn::MFSignatureBuilder signature{"Switch"};
|
||||
signature.single_input<bool>("Switch");
|
||||
signature.single_input<T>("False");
|
||||
signature.single_input<T>("True");
|
||||
signature.single_output<T>("Output");
|
||||
return signature.build();
|
||||
}
|
||||
|
||||
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
|
||||
{
|
||||
const VArray<bool> &switches = params.readonly_single_input<bool>(0, "Switch");
|
||||
const VArray<T> &falses = params.readonly_single_input<T>(1, "False");
|
||||
const VArray<T> &trues = params.readonly_single_input<T>(2, "True");
|
||||
MutableSpan<T> values = params.uninitialized_single_output_if_required<T>(3, "Output");
|
||||
for (int64_t i : mask) {
|
||||
new (&values[i]) T(switches[i] ? trues[i] : falses[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> void switch_fields(GeoNodeExecParams ¶ms, const StringRef suffix)
|
||||
{
|
||||
const std::string name_a = "False" + input_suffix;
|
||||
const std::string name_b = "True" + input_suffix;
|
||||
if (input) {
|
||||
params.set_input_unused(name_a);
|
||||
if (params.lazy_require_input(name_b)) {
|
||||
if (params.lazy_require_input("Switch")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string name_false = "False" + suffix;
|
||||
const std::string name_true = "True" + suffix;
|
||||
const std::string name_output = "Output" + suffix;
|
||||
|
||||
/* TODO: Allow for Laziness when the switch field is constant. */
|
||||
const bool require_false = params.lazy_require_input(name_false);
|
||||
const bool require_true = params.lazy_require_input(name_true);
|
||||
if (require_false | require_true) {
|
||||
return;
|
||||
}
|
||||
|
||||
Field<bool> switches_field = params.extract_input<Field<bool>>("Switch");
|
||||
Field<T> falses_field = params.extract_input<Field<T>>(name_false);
|
||||
Field<T> trues_field = params.extract_input<Field<T>>(name_true);
|
||||
|
||||
auto switch_fn = std::make_unique<SwitchFieldsFunction<T>>();
|
||||
auto switch_op = std::make_shared<FieldOperation>(FieldOperation(
|
||||
std::move(switch_fn),
|
||||
{std::move(switches_field), std::move(falses_field), std::move(trues_field)}));
|
||||
|
||||
params.set_output(name_output, Field<T>(switch_op, 0));
|
||||
}
|
||||
|
||||
template<typename T> void switch_no_fields(GeoNodeExecParams ¶ms, const StringRef suffix)
|
||||
{
|
||||
if (params.lazy_require_input("Switch_001")) {
|
||||
return;
|
||||
}
|
||||
bool switch_value = params.get_input<bool>("Switch_001");
|
||||
|
||||
const std::string name_false = "False" + suffix;
|
||||
const std::string name_true = "True" + suffix;
|
||||
const std::string name_output = "Output" + suffix;
|
||||
|
||||
if (switch_value) {
|
||||
params.set_input_unused(name_false);
|
||||
if (params.lazy_require_input(name_true)) {
|
||||
return;
|
||||
}
|
||||
params.set_output(output_identifier, params.extract_input<T>(name_b));
|
||||
params.set_output(name_output, params.extract_input<T>(name_true));
|
||||
}
|
||||
else {
|
||||
params.set_input_unused(name_b);
|
||||
if (params.lazy_require_input(name_a)) {
|
||||
params.set_input_unused(name_true);
|
||||
if (params.lazy_require_input(name_false)) {
|
||||
return;
|
||||
}
|
||||
params.set_output(output_identifier, params.extract_input<T>(name_a));
|
||||
params.set_output(name_output, params.extract_input<T>(name_false));
|
||||
}
|
||||
}
|
||||
|
||||
static void geo_node_switch_exec(GeoNodeExecParams params)
|
||||
{
|
||||
if (params.lazy_require_input("Switch")) {
|
||||
return;
|
||||
}
|
||||
const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage;
|
||||
const bool input = params.get_input<bool>("Switch");
|
||||
switch ((eNodeSocketDatatype)storage.input_type) {
|
||||
const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type);
|
||||
|
||||
switch (data_type) {
|
||||
|
||||
case SOCK_FLOAT: {
|
||||
output_input<float>(params, input, "", "Output");
|
||||
switch_fields<float>(params, "");
|
||||
break;
|
||||
}
|
||||
case SOCK_INT: {
|
||||
output_input<int>(params, input, "_001", "Output_001");
|
||||
switch_fields<int>(params, "_001");
|
||||
break;
|
||||
}
|
||||
case SOCK_BOOLEAN: {
|
||||
output_input<bool>(params, input, "_002", "Output_002");
|
||||
switch_fields<bool>(params, "_002");
|
||||
break;
|
||||
}
|
||||
case SOCK_VECTOR: {
|
||||
output_input<float3>(params, input, "_003", "Output_003");
|
||||
switch_fields<float3>(params, "_003");
|
||||
break;
|
||||
}
|
||||
case SOCK_RGBA: {
|
||||
output_input<ColorGeometry4f>(params, input, "_004", "Output_004");
|
||||
switch_fields<ColorGeometry4f>(params, "_004");
|
||||
break;
|
||||
}
|
||||
case SOCK_STRING: {
|
||||
output_input<std::string>(params, input, "_005", "Output_005");
|
||||
switch_fields<std::string>(params, "_005");
|
||||
break;
|
||||
}
|
||||
case SOCK_GEOMETRY: {
|
||||
output_input<GeometrySet>(params, input, "_006", "Output_006");
|
||||
switch_no_fields<GeometrySet>(params, "_006");
|
||||
break;
|
||||
}
|
||||
case SOCK_OBJECT: {
|
||||
output_input<Object *>(params, input, "_007", "Output_007");
|
||||
switch_no_fields<Object *>(params, "_007");
|
||||
break;
|
||||
}
|
||||
case SOCK_COLLECTION: {
|
||||
output_input<Collection *>(params, input, "_008", "Output_008");
|
||||
switch_no_fields<Collection *>(params, "_008");
|
||||
break;
|
||||
}
|
||||
case SOCK_TEXTURE: {
|
||||
output_input<Tex *>(params, input, "_009", "Output_009");
|
||||
switch_no_fields<Tex *>(params, "_009");
|
||||
break;
|
||||
}
|
||||
case SOCK_MATERIAL: {
|
||||
output_input<Material *>(params, input, "_010", "Output_010");
|
||||
switch_no_fields<Material *>(params, "_010");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue