Geometry Nodes: Add "Point Translate" and "Point Scale" nodes

The translate node moves every point in the geometry, and the scale
node multiplies the "scale" attribute of the input geometry by its input.
While these operations are already possible with the "Attribute" nodes,
these new nodes fit nicely with the nodes specifically for changing the
"rotation" attribute that already exist, and they provide a simpler way
to do the same thing.

Differential Revision: https://developer.blender.org/D10100
This commit is contained in:
Hans Goudey 2021-01-13 10:30:42 -06:00
parent bae4d00e2a
commit 1f4c1c5fc7
Notes: blender-bot 2023-02-14 07:39:46 +01:00
Referenced by issue #84660, Simple nodes for translating and scaling points
11 changed files with 268 additions and 1 deletions

View File

@ -515,6 +515,8 @@ geometry_node_categories = [
NodeItem("GeometryNodePointDistribute"),
NodeItem("GeometryNodePointInstance"),
NodeItem("GeometryNodePointSeparate"),
NodeItem("GeometryNodePointScale"),
NodeItem("GeometryNodePointTranslate"),
NodeItem("GeometryNodeRotatePoints"),
NodeItem("GeometryNodeAlignRotationToVector"),
]),

View File

@ -1359,6 +1359,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_POINT_ROTATE 1016
#define GEO_NODE_ATTRIBUTE_VECTOR_MATH 1017
#define GEO_NODE_ALIGN_ROTATION_TO_VECTOR 1018
#define GEO_NODE_POINT_TRANSLATE 1019
#define GEO_NODE_POINT_SCALE 1020
/** \} */

View File

@ -4739,6 +4739,8 @@ static void registerGeometryNodes(void)
register_node_type_geo_point_distribute();
register_node_type_geo_point_instance();
register_node_type_geo_point_separate();
register_node_type_geo_point_scale();
register_node_type_geo_point_translate();
register_node_type_geo_object_info();
register_node_type_geo_attribute_randomize();
register_node_type_geo_attribute_math();

View File

@ -3272,6 +3272,17 @@ static void node_geometry_buts_align_rotation_to_vector(uiLayout *layout,
uiItemR(col, ptr, "input_type_factor", DEFAULT_FLAGS, IFACE_("Factor"), ICON_NONE);
uiItemR(col, ptr, "input_type_vector", DEFAULT_FLAGS, IFACE_("Vector"), ICON_NONE);
}
static void node_geometry_buts_point_translate(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiItemR(layout, ptr, "input_type", DEFAULT_FLAGS, IFACE_("Type"), ICON_NONE);
}
static void node_geometry_buts_point_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "input_type", DEFAULT_FLAGS, IFACE_("Type"), ICON_NONE);
}
static void node_geometry_set_butfunc(bNodeType *ntype)
{
@ -3318,6 +3329,12 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
case GEO_NODE_ALIGN_ROTATION_TO_VECTOR:
ntype->draw_buttons = node_geometry_buts_align_rotation_to_vector;
break;
case GEO_NODE_POINT_TRANSLATE:
ntype->draw_buttons = node_geometry_buts_point_translate;
break;
case GEO_NODE_POINT_SCALE:
ntype->draw_buttons = node_geometry_buts_point_scale;
break;
}
}

View File

@ -1153,6 +1153,20 @@ typedef struct NodeGeometryAlignRotationToVector {
char _pad[5];
} NodeGeometryAlignRotationToVector;
typedef struct NodeGeometryPointScale {
/* GeometryNodeAttributeInputMode */
uint8_t input_type;
char _pad[7];
} NodeGeometryPointScale;
typedef struct NodeGeometryPointTranslate {
/* GeometryNodeAttributeInputMode */
uint8_t input_type;
char _pad[7];
} NodeGeometryPointTranslate;
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1

View File

@ -8822,6 +8822,30 @@ static void def_geo_align_rotation_to_vector(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_point_scale(StructRNA *srna)
{
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryPointScale", "storage");
prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
RNA_def_property_ui_text(prop, "Input Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_point_translate(StructRNA *srna)
{
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryPointTranslate", "storage");
prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
RNA_def_property_ui_text(prop, "Input Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)

View File

@ -155,8 +155,10 @@ set(SRC
geometry/nodes/node_geo_object_info.cc
geometry/nodes/node_geo_point_distribute.cc
geometry/nodes/node_geo_point_instance.cc
geometry/nodes/node_geo_point_separate.cc
geometry/nodes/node_geo_point_rotate.cc
geometry/nodes/node_geo_point_scale.cc
geometry/nodes/node_geo_point_separate.cc
geometry/nodes/node_geo_point_translate.cc
geometry/nodes/node_geo_subdivision_surface.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc

View File

@ -40,6 +40,8 @@ void register_node_type_geo_attribute_randomize(void);
void register_node_type_geo_attribute_math(void);
void register_node_type_geo_join_geometry(void);
void register_node_type_geo_point_separate(void);
void register_node_type_geo_point_scale(void);
void register_node_type_geo_point_translate(void);
void register_node_type_geo_attribute_compare(void);
void register_node_type_geo_attribute_mix(void);
void register_node_type_geo_attribute_color_ramp(void);

View File

@ -287,6 +287,8 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_co
DefNode(GeometryNode, GEO_NODE_POINT_ROTATE, def_geo_point_rotate, "POINT_ROTATE", RotatePoints, "Point Rotate", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_math, "ATTRIBUTE_VECTOR_MATH", AttributeVectorMath, "Attribute Vector Math", "")
DefNode(GeometryNode, GEO_NODE_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "ALIGN_ROTATION_TO_VECTOR", AlignRotationToVector, "Align Rotation to Vector", "")
DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE", PointScale, "Point Scale", "")
DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "")
/* undefine macros */
#undef DefNode

View File

@ -0,0 +1,99 @@
/*
* 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 "node_geometry_util.hh"
#include "BKE_colorband.h"
static bNodeSocketTemplate geo_node_point_scale_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Factor")},
{SOCK_VECTOR, N_("Factor"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
{-1, ""},
};
static bNodeSocketTemplate geo_node_point_scale_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
Float3WriteAttribute scale_attribute = component.attribute_try_ensure_for_write(
"scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
ReadAttributePtr attribute = params.get_input_attribute(
"Factor", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
if (!attribute) {
return;
}
Span<float3> data = attribute->get_span<float3>();
MutableSpan<float3> scale_span = scale_attribute.get_span();
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * data[i];
}
scale_attribute.apply_span();
}
static void geo_node_point_scale_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
}
if (geometry_set.has<PointCloudComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
}
params.set_output("Geometry", std::move(geometry_set));
}
static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN(
sizeof(NodeGeometryPointScale), __func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
static void geo_node_point_scale_update(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage;
update_attribute_input_socket_availabilities(
*node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type);
}
} // namespace blender::nodes
void register_node_type_geo_point_scale()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(&ntype, geo_node_point_scale_in, geo_node_point_scale_out);
node_type_init(&ntype, blender::nodes::geo_node_point_scale_init);
node_type_update(&ntype, blender::nodes::geo_node_point_scale_update);
node_type_storage(
&ntype, "NodeGeometryPointScale", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_point_scale_exec;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,101 @@
/*
* 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 "node_geometry_util.hh"
#include "BKE_colorband.h"
static bNodeSocketTemplate geo_node_point_translate_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Translation")},
{SOCK_VECTOR, N_("Translation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{-1, ""},
};
static bNodeSocketTemplate geo_node_point_translate_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
Float3WriteAttribute position_attribute = component.attribute_try_ensure_for_write(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
ReadAttributePtr attribute = params.get_input_attribute(
"Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
if (!attribute) {
return;
}
Span<float3> data = attribute->get_span<float3>();
MutableSpan<float3> scale_span = position_attribute.get_span();
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] + data[i];
}
position_attribute.apply_span();
}
static void geo_node_point_translate_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
}
if (geometry_set.has<PointCloudComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
}
params.set_output("Geometry", std::move(geometry_set));
}
static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN(
sizeof(NodeGeometryPointTranslate), __func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
static void geo_node_point_translate_update(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
update_attribute_input_socket_availabilities(
*node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type);
}
} // namespace blender::nodes
void register_node_type_geo_point_translate()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(&ntype, geo_node_point_translate_in, geo_node_point_translate_out);
node_type_init(&ntype, blender::nodes::geo_node_point_translate_init);
node_type_update(&ntype, blender::nodes::geo_node_point_translate_update);
node_type_storage(&ntype,
"NodeGeometryPointTranslate",
node_free_standard_storage,
node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_point_translate_exec;
nodeRegisterType(&ntype);
}