Page MenuHome
Paste P2371

New Point Translate Node
ActivePublic

Authored by Hans Goudey (HooglyBoogly) on Sep 7 2021, 8:13 PM.
/*
* 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 "FN_multi_function_builder.hh"
#include "node_geometry_util.hh"
namespace blender::nodes {
static void geo_node_point_translate_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Vector>("Translation", "Translation_001").subtype(PROP_TRANSLATION);
b.add_input<decl::Bool>("Selection").default_value(true);
b.add_output<decl::Geometry>("Geometry");
}
class SpanFieldInput final : public fn::FieldInput {
GSpan span_;
public:
SpanFieldInput(GSpan span) : FieldInput(CPPType::get<float3>(), "Span"), span_(span)
{
}
const GVArray *get_varray_for_context(const fn::FieldContext &UNUSED(context),
IndexMask UNUSED(mask),
ResourceScope &scope) const final
{
return &scope.construct<fn::GVArray_For_GSpan>(__func__, span_);
}
};
static void execute_on_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<float3> &translation_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
MutableSpan<float3> position_span = positions.as_span();
fn::Field<float3> position_field{std::make_shared<SpanFieldInput>(position_span.as_span())};
/* Add an add operation field on top of the provided translation field, which can be evaluated
* directly into the position virtual array. That way, any optimizations can be done more
* generally for the whole evaluation system. In the general case it may not work to share the
* same span for the input and output of an evaluation, but in this case there there is only one
* output, so it is fine. */
static const fn::CustomMF_SI_SI_SO<float3, float3, float3> add_fn = {
"Add", [](float3 a, float3 b) { return a + b; }};
std::shared_ptr<fn::FieldOperation> add_operation = std::make_shared<fn::FieldOperation>(
fn::FieldOperation(add_fn, {position_field, translation_field}));
fn::FieldEvaluator position_evaluator{field_context, &selection};
position_evaluator.add_with_destination({add_operation}, position_span);
position_evaluator.evaluate();
positions.save();
}
static void geo_node_point_translate_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
geometry_set = geometry_set_realize_instances(geometry_set);
Field<bool> selection = params.extract_input<Field<bool>>("Selection");
Field<float3> translation = params.extract_input<Field<float3>>("Translation_001");
static const Array<GeometryComponentType> types{
GEO_COMPONENT_TYPE_MESH,
GEO_COMPONENT_TYPE_POINT_CLOUD,
GEO_COMPONENT_TYPE_CURVE,
};
for (const GeometryComponentType type : types) {
if (geometry_set.has(type)) {
execute_on_component(geometry_set.get_component_for_write(type), selection, translation);
}
}
params.set_output("Geometry", std::move(geometry_set));
}
} // 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);
ntype.declare = blender::nodes::geo_node_point_translate_declare;
ntype.geometry_node_execute = blender::nodes::geo_node_point_translate_exec;
nodeRegisterType(&ntype);
}