Geometry Nodes: Add explicit Float to Int conversion node

This patch adds a very simple node that explicitly converts a float to
an int. While this may seem redundant, it would offer 2 benefits to the
current requirement to use implicit float conversions:
 1. It makes the node tree's intent more clear and self-documenting
    (especially if changes in the future require integer inputs).
 2. It eliminates undefined behavior in current/future nodes from float
    inputs by guaranteeing that the input is an integer.

The node offers a variety of rounding techniques to make it more flexible.

Differential Revision: https://developer.blender.org/D11700
This commit is contained in:
Nikhil Shringarpurey 2021-07-05 11:52:10 -05:00 committed by Hans Goudey
parent 08241b313c
commit fd0370acc2
10 changed files with 148 additions and 0 deletions

View File

@ -572,6 +572,7 @@ geometry_node_categories = [
NodeItem("ShaderNodeMath"),
NodeItem("FunctionNodeBooleanMath"),
NodeItem("FunctionNodeFloatCompare"),
NodeItem("FunctionNodeFloatToInt"),
NodeItem("GeometryNodeSwitch"),
]),
GeometryNodeCategory("GEO_VECTOR", "Vector", items=[

View File

@ -1457,6 +1457,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define FN_NODE_RANDOM_FLOAT 1206
#define FN_NODE_INPUT_VECTOR 1207
#define FN_NODE_INPUT_STRING 1208
#define FN_NODE_FLOAT_TO_INT 1209
/** \} */

View File

@ -5105,6 +5105,7 @@ static void registerFunctionNodes()
{
register_node_type_fn_boolean_math();
register_node_type_fn_float_compare();
register_node_type_fn_float_to_int();
register_node_type_fn_input_string();
register_node_type_fn_input_vector();
register_node_type_fn_random_float();

View File

@ -1688,6 +1688,14 @@ typedef enum FloatCompareOperation {
NODE_FLOAT_COMPARE_NOT_EQUAL = 5,
} FloatCompareOperation;
/* Float to Int node operations. */
typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_ROUND = 0,
FN_NODE_FLOAT_TO_INT_FLOOR = 1,
FN_NODE_FLOAT_TO_INT_CEIL = 2,
FN_NODE_FLOAT_TO_INT_TRUNCATE = 3,
} FloatToIntRoundingMode;
/* Clamp node types. */
enum {
NODE_CLAMP_MINMAX = 0,

View File

@ -204,6 +204,7 @@ extern const EnumPropertyItem rna_enum_node_vec_math_items[];
extern const EnumPropertyItem rna_enum_node_boolean_math_items[];
extern const EnumPropertyItem rna_enum_node_float_compare_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];
extern const EnumPropertyItem rna_enum_node_float_to_int_items[];
extern const EnumPropertyItem rna_enum_node_map_range_items[];
extern const EnumPropertyItem rna_enum_node_clamp_items[];

View File

@ -337,6 +337,31 @@ const EnumPropertyItem rna_enum_node_float_compare_items[] = {
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_float_to_int_items[] = {
{FN_NODE_FLOAT_TO_INT_ROUND,
"ROUND",
0,
"Round",
"Round the float up or down to the nearest integer"},
{FN_NODE_FLOAT_TO_INT_FLOOR,
"FLOOR",
0,
"Floor",
"Round the float down to the next smallest integer"},
{FN_NODE_FLOAT_TO_INT_CEIL,
"CEILING",
0,
"Ceiling",
"Round the float up to the next largest integer"},
{FN_NODE_FLOAT_TO_INT_TRUNCATE,
"TRUNCATE",
0,
"Truncate",
"Round the float to the closest integer in the direction of zero (floor if positive; ceiling "
"if negative)"},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_map_range_items[] = {
{NODE_MAP_RANGE_LINEAR,
"LINEAR",
@ -4794,6 +4819,18 @@ static void def_float_compare(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_float_to_int(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "rounding_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_float_to_int_items);
RNA_def_property_ui_text(
prop, "Rounding Mode", "Method used to convert the float to an integer");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_vector_math(StructRNA *srna)
{
PropertyRNA *prop;

View File

@ -134,6 +134,7 @@ set(SRC
function/nodes/node_fn_boolean_math.cc
function/nodes/node_fn_float_compare.cc
function/nodes/node_fn_float_to_int.cc
function/nodes/node_fn_input_string.cc
function/nodes/node_fn_input_vector.cc
function/nodes/node_fn_random_float.cc

View File

@ -22,6 +22,7 @@ extern "C" {
void register_node_type_fn_boolean_math(void);
void register_node_type_fn_float_compare(void);
void register_node_type_fn_float_to_int(void);
void register_node_type_fn_input_string(void);
void register_node_type_fn_input_vector(void);
void register_node_type_fn_random_float(void);

View File

@ -263,6 +263,7 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DI
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
DefNode(FunctionNode, FN_NODE_FLOAT_COMPARE, def_float_compare, "FLOAT_COMPARE", FloatCompare, "Float Compare", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", InputString, "String", "")
DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "")
DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "")

View File

@ -0,0 +1,96 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <math.h>
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_function_util.hh"
static bNodeSocketTemplate fn_node_float_to_int_in[] = {
{SOCK_FLOAT, N_("Float"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
{-1, ""},
};
static bNodeSocketTemplate fn_node_float_to_int_out[] = {
{SOCK_INT, N_("Integer")},
{-1, ""},
};
static void fn_node_float_to_int_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "rounding_mode", 0, "", ICON_NONE);
}
static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_float_to_int_items, node->custom1, &name);
if (!enum_label) {
name = "Unknown";
}
BLI_strncpy(label, IFACE_(name), maxlen);
}
static const blender::fn::MultiFunction &get_multi_function(bNode &bnode)
{
static blender::fn::CustomMF_SI_SO<float, int> round_fn{"Round",
[](float a) { return std::round(a); }};
static blender::fn::CustomMF_SI_SO<float, int> floor_fn{"Floor",
[](float a) { return (int)floor(a); }};
static blender::fn::CustomMF_SI_SO<float, int> ceil_fn{"Ceiling",
[](float a) { return (int)ceil(a); }};
static blender::fn::CustomMF_SI_SO<float, int> trunc_fn{"Truncate",
[](float a) { return (int)trunc(a); }};
switch (static_cast<FloatToIntRoundingMode>(bnode.custom1)) {
case FN_NODE_FLOAT_TO_INT_ROUND:
return round_fn;
case FN_NODE_FLOAT_TO_INT_FLOOR:
return floor_fn;
case FN_NODE_FLOAT_TO_INT_CEIL:
return ceil_fn;
case FN_NODE_FLOAT_TO_INT_TRUNCATE:
return trunc_fn;
}
BLI_assert_unreachable();
return blender::fn::dummy_multi_function;
}
static void node_float_to_int_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
{
const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode());
builder.set_matching_fn(fn);
}
void register_node_type_fn_float_to_int()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, fn_node_float_to_int_in, fn_node_float_to_int_out);
node_type_label(&ntype, node_float_to_int_label);
ntype.expand_in_mf_network = node_float_to_int_expand_in_mf_network;
ntype.draw_buttons = fn_node_float_to_int_layout;
nodeRegisterType(&ntype);
}