Geometry Nodes: extract geometry transform functions to separate file

This commit is contained in:
Jacques Lucke
2024-02-01 13:18:35 +01:00
parent 1b6e3d46a9
commit fcc17780a8
8 changed files with 334 additions and 284 deletions

View File

@@ -41,6 +41,7 @@ set(SRC
intern/set_curve_type.cc
intern/smooth_curves.cc
intern/subdivide_curves.cc
intern/transform.cc
intern/trim_curves.cc
intern/uv_pack.cc
intern/uv_parametrizer.cc
@@ -71,6 +72,7 @@ set(SRC
GEO_set_curve_type.hh
GEO_smooth_curves.hh
GEO_subdivide_curves.hh
GEO_transform.hh
GEO_trim_curves.hh
GEO_uv_pack.hh
GEO_uv_parametrizer.hh

View File

@@ -0,0 +1,30 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <optional>
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector_types.hh"
struct Mesh;
namespace blender::bke {
struct GeometrySet;
}
namespace blender::geometry {
void transform_mesh(Mesh &mesh, float3 translation, math::Quaternion rotation, float3 scale);
struct TransformGeometryErrors {
bool volume_too_small = false;
};
std::optional<TransformGeometryErrors> transform_geometry(bke::GeometrySet &geometry,
const float4x4 &transform);
void translate_geometry(bke::GeometrySet &geometry, const float3 translation);
} // namespace blender::geometry

View File

@@ -0,0 +1,273 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifdef WITH_OPENVDB
# include <openvdb/openvdb.h>
#endif
#include "GEO_transform.hh"
#include "BLI_math_base.h"
#include "BLI_math_matrix.h"
#include "BLI_math_rotation.hh"
#include "BLI_math_vector.hh"
#include "BLI_task.hh"
#include "DNA_grease_pencil_types.h"
#include "DNA_mesh_types.h"
#include "DNA_pointcloud_types.h"
#include "DNA_volume_types.h"
#include "BKE_attribute.hh"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_instances.hh"
#include "BKE_mesh.hh"
#include "BKE_pointcloud.hh"
#include "BKE_volume.hh"
namespace blender::geometry {
static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
{
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position += translation;
}
});
}
static void transform_positions(MutableSpan<float3> positions, const float4x4 &matrix)
{
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position = math::transform_point(matrix, position);
}
});
}
static void transform_mesh(Mesh &mesh, const float4x4 &transform)
{
transform_positions(mesh.vert_positions_for_write(), transform);
mesh.tag_positions_changed();
}
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
{
if (math::is_zero(translation)) {
return;
}
std::optional<Bounds<float3>> bounds;
if (pointcloud.runtime->bounds_cache.is_cached()) {
bounds = pointcloud.runtime->bounds_cache.data();
}
bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
bke::SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", bke::AttrDomain::Point);
translate_positions(position.span, translation);
position.finish();
if (bounds) {
bounds->min += translation;
bounds->max += translation;
pointcloud.runtime->bounds_cache.ensure([&](Bounds<float3> &r_data) { r_data = *bounds; });
}
}
static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
{
bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
bke::SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", bke::AttrDomain::Point);
transform_positions(position.span, transform);
position.finish();
}
static void translate_greasepencil(GreasePencil &grease_pencil, const float3 translation)
{
using namespace blender::bke::greasepencil;
for (const int layer_index : grease_pencil.layers().index_range()) {
if (Drawing *drawing = get_eval_grease_pencil_layer_drawing_for_write(grease_pencil,
layer_index))
{
drawing->strokes_for_write().translate(translation);
}
}
}
static void transform_greasepencil(GreasePencil &grease_pencil, const float4x4 &transform)
{
using namespace blender::bke::greasepencil;
for (const int layer_index : grease_pencil.layers().index_range()) {
if (Drawing *drawing = get_eval_grease_pencil_layer_drawing_for_write(grease_pencil,
layer_index))
{
drawing->strokes_for_write().transform(transform);
}
}
}
static void translate_instances(bke::Instances &instances, const float3 translation)
{
MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
for (float4x4 &instance_transform : transforms.slice(range)) {
add_v3_v3(instance_transform.ptr()[3], translation);
}
});
}
static void transform_instances(bke::Instances &instances, const float4x4 &transform)
{
MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
for (float4x4 &instance_transform : transforms.slice(range)) {
instance_transform = transform * instance_transform;
}
});
}
static bool transform_volume(Volume &volume, const float4x4 &transform)
{
bool found_too_small_scale = false;
#ifdef WITH_OPENVDB
openvdb::Mat4s vdb_matrix;
memcpy(vdb_matrix.asPointer(), &transform, sizeof(float[4][4]));
openvdb::Mat4d vdb_matrix_d{vdb_matrix};
const int grids_num = BKE_volume_num_grids(&volume);
for (const int i : IndexRange(grids_num)) {
bke::VolumeGridData *volume_grid = BKE_volume_grid_get_for_write(&volume, i);
float4x4 grid_matrix = bke::volume_grid::get_transform_matrix(*volume_grid);
grid_matrix = transform * grid_matrix;
const float determinant = math::determinant(grid_matrix);
if (!BKE_volume_grid_determinant_valid(determinant)) {
found_too_small_scale = true;
/* Clear the tree because it is too small. */
bke::volume_grid::clear_tree(*volume_grid);
if (determinant == 0) {
/* Reset rotation and scale. */
grid_matrix.x_axis() = float3(1, 0, 0);
grid_matrix.y_axis() = float3(0, 1, 0);
grid_matrix.z_axis() = float3(0, 0, 1);
}
else {
/* Keep rotation but reset scale. */
grid_matrix.x_axis() = math::normalize(grid_matrix.x_axis());
grid_matrix.y_axis() = math::normalize(grid_matrix.y_axis());
grid_matrix.z_axis() = math::normalize(grid_matrix.z_axis());
}
}
bke::volume_grid::set_transform_matrix(*volume_grid, grid_matrix);
}
#else
UNUSED_VARS(volume, transform);
#endif
return found_too_small_scale;
}
static void translate_volume(Volume &volume, const float3 translation)
{
transform_volume(volume, math::from_location<float4x4>(translation));
}
static void transform_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float4x4 &transform)
{
if (edit_hints.positions.has_value()) {
transform_positions(*edit_hints.positions, transform);
}
float3x3 deform_mat;
copy_m3_m4(deform_mat.ptr(), transform.ptr());
if (edit_hints.deform_mats.has_value()) {
MutableSpan<float3x3> deform_mats = *edit_hints.deform_mats;
threading::parallel_for(deform_mats.index_range(), 1024, [&](const IndexRange range) {
for (const int64_t i : range) {
deform_mats[i] = deform_mat * deform_mats[i];
}
});
}
else {
edit_hints.deform_mats.emplace(edit_hints.curves_id_orig.geometry.point_num, deform_mat);
}
}
static void translate_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float3 &translation)
{
if (edit_hints.positions.has_value()) {
translate_positions(*edit_hints.positions, translation);
}
}
void translate_geometry(bke::GeometrySet &geometry, const float3 translation)
{
if (Curves *curves = geometry.get_curves_for_write()) {
curves->geometry.wrap().translate(translation);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
BKE_mesh_translate(mesh, translation, false);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
translate_pointcloud(*pointcloud, translation);
}
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
translate_greasepencil(*grease_pencil, translation);
}
if (Volume *volume = geometry.get_volume_for_write()) {
translate_volume(*volume, translation);
}
if (bke::Instances *instances = geometry.get_instances_for_write()) {
translate_instances(*instances, translation);
}
if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
translate_curve_edit_hints(*curve_edit_hints, translation);
}
}
std::optional<TransformGeometryErrors> transform_geometry(bke::GeometrySet &geometry,
const float4x4 &transform)
{
TransformGeometryErrors errors;
if (Curves *curves = geometry.get_curves_for_write()) {
curves->geometry.wrap().transform(transform);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
transform_mesh(*mesh, transform);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
transform_pointcloud(*pointcloud, transform);
}
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
transform_greasepencil(*grease_pencil, transform);
}
if (Volume *volume = geometry.get_volume_for_write()) {
errors.volume_too_small = transform_volume(*volume, transform);
}
if (bke::Instances *instances = geometry.get_instances_for_write()) {
transform_instances(*instances, transform);
}
if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
transform_curve_edit_hints(*curve_edit_hints, transform);
}
if (errors.volume_too_small) {
return errors;
}
return std::nullopt;
}
void transform_mesh(Mesh &mesh,
const float3 translation,
const math::Quaternion rotation,
const float3 scale)
{
const float4x4 matrix = math::from_loc_rot_scale<float4x4>(translation, rotation, scale);
transform_mesh(mesh, matrix);
}
} // namespace blender::geometry

View File

@@ -33,13 +33,6 @@ namespace blender::nodes {
bool check_tool_context_and_error(GeoNodeExecParams &params);
void search_link_ops_for_tool_node(GatherLinkSearchOpParams &params);
void transform_mesh(Mesh &mesh, float3 translation, math::Quaternion rotation, float3 scale);
void transform_geometry_set(GeoNodeExecParams &params,
GeometrySet &geometry,
const float4x4 &transform,
const Depsgraph &depsgraph);
/**
* Returns the parts of the geometry that are on the selection for the given domain. If the domain
* is not applicable for the component, e.g. face domain for point cloud, nothing happens to that

View File

@@ -3,6 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "GEO_mesh_primitive_cuboid.hh"
#include "GEO_transform.hh"
#include "node_geometry_util.hh"
@@ -54,7 +55,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const float3 scale = sub_bounds->max - sub_bounds->min;
const float3 center = sub_bounds->min + scale / 2.0f;
Mesh *mesh = geometry::create_cuboid_mesh(scale, 2, 2, 2, "uv_map");
transform_mesh(*mesh, center, math::Quaternion::identity(), float3(1));
geometry::transform_mesh(*mesh, center, math::Quaternion::identity(), float3(1));
sub_geometry.replace_mesh(mesh);
sub_geometry.keep_only_during_modify({GeometryComponent::Type::Mesh});
}

View File

@@ -10,6 +10,7 @@
#include "GEO_mesh_primitive_cuboid.hh"
#include "GEO_mesh_primitive_grid.hh"
#include "GEO_mesh_primitive_line.hh"
#include "GEO_transform.hh"
#include "node_geometry_util.hh"
@@ -75,13 +76,13 @@ static Mesh *create_cube_mesh(const float3 size,
}
if (verts_y == 1) { /* XZ plane. */
Mesh *mesh = geometry::create_grid_mesh(verts_x, verts_z, size.x, size.z, uv_map_id);
transform_mesh(
geometry::transform_mesh(
*mesh, float3(0), math::to_quaternion(math::EulerXYZ(M_PI_2, 0.0f, 0.0f)), float3(1));
return mesh;
}
/* YZ plane. */
Mesh *mesh = geometry::create_grid_mesh(verts_z, verts_y, size.z, size.y, uv_map_id);
transform_mesh(
geometry::transform_mesh(
*mesh, float3(0), math::to_quaternion(math::EulerXYZ(0.0f, M_PI_2, 0.0f)), float3(1));
return mesh;
}

View File

@@ -14,6 +14,8 @@
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "GEO_transform.hh"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_object_info_cc {
@@ -90,7 +92,7 @@ static void node_geo_exec(GeoNodeExecParams params)
else {
geometry_set = bke::object_get_evaluated_geometry_set(*object);
if (transform_space_relative) {
transform_geometry_set(params, geometry_set, transform, *params.depsgraph());
geometry::transform_geometry(geometry_set, transform);
}
}

View File

@@ -2,10 +2,6 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifdef WITH_OPENVDB
# include <openvdb/openvdb.h>
#endif
#include "BLI_math_matrix.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_rotation.hh"
@@ -24,9 +20,20 @@
#include "DEG_depsgraph_query.hh"
#include "GEO_transform.hh"
#include "node_geometry_util.hh"
namespace blender::nodes {
namespace blender::nodes::node_geo_transform_geometry_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Vector>("Translation").subtype(PROP_TRANSLATION);
b.add_input<decl::Rotation>("Rotation");
b.add_input<decl::Vector>("Scale").default_value({1, 1, 1}).subtype(PROP_XYZ);
b.add_output<decl::Geometry>("Geometry").propagate_all();
}
static bool use_translate(const math::Quaternion &rotation, const float3 scale)
{
@@ -41,269 +48,6 @@ static bool use_translate(const math::Quaternion &rotation, const float3 scale)
return true;
}
static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
{
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position += translation;
}
});
}
static void transform_positions(MutableSpan<float3> positions, const float4x4 &matrix)
{
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position = math::transform_point(matrix, position);
}
});
}
static void transform_mesh(Mesh &mesh, const float4x4 &transform)
{
transform_positions(mesh.vert_positions_for_write(), transform);
mesh.tag_positions_changed();
}
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
{
if (math::is_zero(translation)) {
return;
}
std::optional<Bounds<float3>> bounds;
if (pointcloud.runtime->bounds_cache.is_cached()) {
bounds = pointcloud.runtime->bounds_cache.data();
}
MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", AttrDomain::Point);
translate_positions(position.span, translation);
position.finish();
if (bounds) {
bounds->min += translation;
bounds->max += translation;
pointcloud.runtime->bounds_cache.ensure([&](Bounds<float3> &r_data) { r_data = *bounds; });
}
}
static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
{
MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", AttrDomain::Point);
transform_positions(position.span, transform);
position.finish();
}
static void translate_greasepencil(GreasePencil &grease_pencil, const float3 translation)
{
using namespace blender::bke::greasepencil;
for (const int layer_index : grease_pencil.layers().index_range()) {
if (Drawing *drawing = get_eval_grease_pencil_layer_drawing_for_write(grease_pencil,
layer_index))
{
drawing->strokes_for_write().translate(translation);
}
}
}
static void transform_greasepencil(GreasePencil &grease_pencil, const float4x4 &transform)
{
using namespace blender::bke::greasepencil;
for (const int layer_index : grease_pencil.layers().index_range()) {
if (Drawing *drawing = get_eval_grease_pencil_layer_drawing_for_write(grease_pencil,
layer_index))
{
drawing->strokes_for_write().transform(transform);
}
}
}
static void translate_instances(bke::Instances &instances, const float3 translation)
{
MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
for (float4x4 &instance_transform : transforms.slice(range)) {
add_v3_v3(instance_transform.ptr()[3], translation);
}
});
}
static void transform_instances(bke::Instances &instances, const float4x4 &transform)
{
MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
for (float4x4 &instance_transform : transforms.slice(range)) {
instance_transform = transform * instance_transform;
}
});
}
static void transform_volume(GeoNodeExecParams &params,
Volume &volume,
const float4x4 &transform,
const Depsgraph &depsgraph)
{
#ifdef WITH_OPENVDB
const Main *bmain = DEG_get_bmain(&depsgraph);
BKE_volume_load(&volume, bmain);
openvdb::Mat4s vdb_matrix;
memcpy(vdb_matrix.asPointer(), &transform, sizeof(float[4][4]));
openvdb::Mat4d vdb_matrix_d{vdb_matrix};
bool found_too_small_scale = false;
const int grids_num = BKE_volume_num_grids(&volume);
for (const int i : IndexRange(grids_num)) {
bke::VolumeGridData *volume_grid = BKE_volume_grid_get_for_write(&volume, i);
float4x4 grid_matrix = bke::volume_grid::get_transform_matrix(*volume_grid);
grid_matrix = transform * grid_matrix;
const float determinant = math::determinant(grid_matrix);
if (!BKE_volume_grid_determinant_valid(determinant)) {
found_too_small_scale = true;
/* Clear the tree because it is too small. */
bke::volume_grid::clear_tree(*volume_grid);
if (determinant == 0) {
/* Reset rotation and scale. */
grid_matrix.x_axis() = float3(1, 0, 0);
grid_matrix.y_axis() = float3(0, 1, 0);
grid_matrix.z_axis() = float3(0, 0, 1);
}
else {
/* Keep rotation but reset scale. */
grid_matrix.x_axis() = math::normalize(grid_matrix.x_axis());
grid_matrix.y_axis() = math::normalize(grid_matrix.y_axis());
grid_matrix.z_axis() = math::normalize(grid_matrix.z_axis());
}
}
bke::volume_grid::set_transform_matrix(*volume_grid, grid_matrix);
}
if (found_too_small_scale) {
params.error_message_add(NodeWarningType::Warning,
TIP_("Volume scale is lower than permitted by OpenVDB"));
}
#else
UNUSED_VARS(params, volume, transform, depsgraph);
#endif
}
static void translate_volume(GeoNodeExecParams &params,
Volume &volume,
const float3 translation,
const Depsgraph &depsgraph)
{
transform_volume(params, volume, math::from_location<float4x4>(translation), depsgraph);
}
static void transform_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float4x4 &transform)
{
if (edit_hints.positions.has_value()) {
transform_positions(*edit_hints.positions, transform);
}
float3x3 deform_mat;
copy_m3_m4(deform_mat.ptr(), transform.ptr());
if (edit_hints.deform_mats.has_value()) {
MutableSpan<float3x3> deform_mats = *edit_hints.deform_mats;
threading::parallel_for(deform_mats.index_range(), 1024, [&](const IndexRange range) {
for (const int64_t i : range) {
deform_mats[i] = deform_mat * deform_mats[i];
}
});
}
else {
edit_hints.deform_mats.emplace(edit_hints.curves_id_orig.geometry.point_num, deform_mat);
}
}
static void translate_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float3 &translation)
{
if (edit_hints.positions.has_value()) {
translate_positions(*edit_hints.positions, translation);
}
}
static void translate_geometry_set(GeoNodeExecParams &params,
GeometrySet &geometry,
const float3 translation,
const Depsgraph &depsgraph)
{
if (Curves *curves = geometry.get_curves_for_write()) {
curves->geometry.wrap().translate(translation);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
BKE_mesh_translate(mesh, translation, false);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
translate_pointcloud(*pointcloud, translation);
}
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
translate_greasepencil(*grease_pencil, translation);
}
if (Volume *volume = geometry.get_volume_for_write()) {
translate_volume(params, *volume, translation, depsgraph);
}
if (bke::Instances *instances = geometry.get_instances_for_write()) {
translate_instances(*instances, translation);
}
if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
translate_curve_edit_hints(*curve_edit_hints, translation);
}
}
void transform_geometry_set(GeoNodeExecParams &params,
GeometrySet &geometry,
const float4x4 &transform,
const Depsgraph &depsgraph)
{
if (Curves *curves = geometry.get_curves_for_write()) {
curves->geometry.wrap().transform(transform);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
transform_mesh(*mesh, transform);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
transform_pointcloud(*pointcloud, transform);
}
if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
transform_greasepencil(*grease_pencil, transform);
}
if (Volume *volume = geometry.get_volume_for_write()) {
transform_volume(params, *volume, transform, depsgraph);
}
if (bke::Instances *instances = geometry.get_instances_for_write()) {
transform_instances(*instances, transform);
}
if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
transform_curve_edit_hints(*curve_edit_hints, transform);
}
}
void transform_mesh(Mesh &mesh,
const float3 translation,
const math::Quaternion rotation,
const float3 scale)
{
const float4x4 matrix = math::from_loc_rot_scale<float4x4>(translation, rotation, scale);
transform_mesh(mesh, matrix);
}
} // namespace blender::nodes
namespace blender::nodes::node_geo_transform_geometry_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Vector>("Translation").subtype(PROP_TRANSLATION);
b.add_input<decl::Rotation>("Rotation");
b.add_input<decl::Vector>("Scale").default_value({1, 1, 1}).subtype(PROP_XYZ);
b.add_output<decl::Geometry>("Geometry").propagate_all();
}
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -313,13 +57,17 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Use only translation if rotation and scale don't apply. */
if (use_translate(rotation, scale)) {
translate_geometry_set(params, geometry_set, translation, *params.depsgraph());
geometry::translate_geometry(geometry_set, translation);
}
else {
transform_geometry_set(params,
geometry_set,
math::from_loc_rot_scale<float4x4>(translation, rotation, scale),
*params.depsgraph());
if (auto errors = geometry::transform_geometry(
geometry_set, math::from_loc_rot_scale<float4x4>(translation, rotation, scale)))
{
if (errors->volume_too_small) {
params.error_message_add(NodeWarningType::Warning,
TIP_("Volume scale is lower than permitted by OpenVDB"));
}
}
}
params.set_output("Geometry", std::move(geometry_set));