Blender  V3.3
node_geo_transform.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #ifdef WITH_OPENVDB
4 # include <openvdb/openvdb.h>
5 #endif
6 
7 #include "BLI_float4x4.hh"
8 
9 #include "DNA_mesh_types.h"
10 #include "DNA_pointcloud_types.h"
11 #include "DNA_volume_types.h"
12 
13 #include "BKE_curves.hh"
14 #include "BKE_mesh.h"
15 #include "BKE_pointcloud.h"
16 #include "BKE_volume.h"
17 
18 #include "DEG_depsgraph_query.h"
19 
20 #include "node_geometry_util.hh"
21 
22 namespace blender::nodes {
23 
24 static bool use_translate(const float3 rotation, const float3 scale)
25 {
26  if (compare_ff(math::length_squared(rotation), 0.0f, 1e-9f) != 1) {
27  return false;
28  }
29  if (compare_ff(scale.x, 1.0f, 1e-9f) != 1 || compare_ff(scale.y, 1.0f, 1e-9f) != 1 ||
30  compare_ff(scale.z, 1.0f, 1e-9f) != 1) {
31  return false;
32  }
33  return true;
34 }
35 
36 static void translate_mesh(Mesh &mesh, const float3 translation)
37 {
38  if (!math::is_zero(translation)) {
39  BKE_mesh_translate(&mesh, translation, false);
40  }
41 }
42 
43 static void transform_mesh(Mesh &mesh, const float4x4 &transform)
44 {
45  BKE_mesh_transform(&mesh, transform.values, false);
46 }
47 
48 static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
49 {
52  "position", ATTR_DOMAIN_POINT);
53  for (const int i : position.span.index_range()) {
54  position.span[i] += translation;
55  }
56  position.finish();
57 }
58 
59 static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
60 {
63  "position", ATTR_DOMAIN_POINT);
64  for (const int i : position.span.index_range()) {
65  position.span[i] = transform * position.span[i];
66  }
67  position.finish();
68 }
69 
70 static void translate_instances(InstancesComponent &instances, const float3 translation)
71 {
72  MutableSpan<float4x4> transforms = instances.instance_transforms();
73  for (float4x4 &transform : transforms) {
74  add_v3_v3(transform.ptr()[3], translation);
75  }
76 }
77 
79 {
80  MutableSpan<float4x4> instance_transforms = instances.instance_transforms();
81  for (float4x4 &instance_transform : instance_transforms) {
82  instance_transform = transform * instance_transform;
83  }
84 }
85 
87  Volume &volume,
88  const float4x4 &transform,
89  const Depsgraph &depsgraph)
90 {
91 #ifdef WITH_OPENVDB
92  const Main *bmain = DEG_get_bmain(&depsgraph);
93  BKE_volume_load(&volume, bmain);
94 
95  openvdb::Mat4s vdb_matrix;
96  memcpy(vdb_matrix.asPointer(), &transform, sizeof(float[4][4]));
97  openvdb::Mat4d vdb_matrix_d{vdb_matrix};
98 
99  bool found_too_small_scale = false;
100  const int grids_num = BKE_volume_num_grids(&volume);
101  for (const int i : IndexRange(grids_num)) {
102  VolumeGrid *volume_grid = BKE_volume_grid_get_for_write(&volume, i);
103  float4x4 grid_matrix;
104  BKE_volume_grid_transform_matrix(volume_grid, grid_matrix.values);
105  mul_m4_m4_pre(grid_matrix.values, transform.values);
106  const float determinant = determinant_m4(grid_matrix.values);
108  found_too_small_scale = true;
109  /* Clear the tree because it is too small. */
110  BKE_volume_grid_clear_tree(volume, *volume_grid);
111  if (determinant == 0) {
112  /* Reset rotation and scale. */
113  copy_v3_fl3(grid_matrix.values[0], 1, 0, 0);
114  copy_v3_fl3(grid_matrix.values[1], 0, 1, 0);
115  copy_v3_fl3(grid_matrix.values[2], 0, 0, 1);
116  }
117  else {
118  /* Keep rotation but reset scale. */
119  normalize_v3(grid_matrix.values[0]);
120  normalize_v3(grid_matrix.values[1]);
121  normalize_v3(grid_matrix.values[2]);
122  }
123  }
124  BKE_volume_grid_transform_matrix_set(volume_grid, grid_matrix.values);
125  }
126  if (found_too_small_scale) {
127  params.error_message_add(NodeWarningType::Warning,
128  TIP_("Volume scale is lower than permitted by OpenVDB"));
129  }
130 #else
132 #endif
133 }
134 
136  Volume &volume,
137  const float3 translation,
138  const Depsgraph &depsgraph)
139 {
141 }
142 
144 {
145  if (edit_hints.positions.has_value()) {
146  for (float3 &pos : *edit_hints.positions) {
147  pos = transform * pos;
148  }
149  }
150  float3x3 deform_mat;
151  copy_m3_m4(deform_mat.values, transform.values);
152  if (edit_hints.deform_mats.has_value()) {
153  for (float3x3 &mat : *edit_hints.deform_mats) {
154  mat = deform_mat * mat;
155  }
156  }
157  else {
158  edit_hints.deform_mats.emplace(edit_hints.curves_id_orig.geometry.point_num, deform_mat);
159  }
160 }
161 
162 static void translate_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float3 &translation)
163 {
164  if (edit_hints.positions.has_value()) {
165  for (float3 &pos : *edit_hints.positions) {
166  pos += translation;
167  }
168  }
169 }
170 
172  GeometrySet &geometry,
173  const float3 translation,
174  const Depsgraph &depsgraph)
175 {
176  if (Curves *curves = geometry.get_curves_for_write()) {
177  bke::CurvesGeometry::wrap(curves->geometry).translate(translation);
178  }
179  if (Mesh *mesh = geometry.get_mesh_for_write()) {
180  translate_mesh(*mesh, translation);
181  }
182  if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
183  translate_pointcloud(*pointcloud, translation);
184  }
185  if (Volume *volume = geometry.get_volume_for_write()) {
186  translate_volume(params, *volume, translation, depsgraph);
187  }
188  if (geometry.has_instances()) {
190  }
191  if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
192  translate_curve_edit_hints(*curve_edit_hints, translation);
193  }
194 }
195 
197  GeometrySet &geometry,
198  const float4x4 &transform,
199  const Depsgraph &depsgraph)
200 {
201  if (Curves *curves = geometry.get_curves_for_write()) {
203  }
204  if (Mesh *mesh = geometry.get_mesh_for_write()) {
206  }
207  if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
208  transform_pointcloud(*pointcloud, transform);
209  }
210  if (Volume *volume = geometry.get_volume_for_write()) {
212  }
213  if (geometry.has_instances()) {
215  }
216  if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
217  transform_curve_edit_hints(*curve_edit_hints, transform);
218  }
219 }
220 
222  const float3 translation,
223  const float3 rotation,
224  const float3 scale)
225 {
226  const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
227  transform_mesh(mesh, matrix);
228 }
229 
230 } // namespace blender::nodes
231 
233 
235 {
236  b.add_input<decl::Geometry>(N_("Geometry"));
237  b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION);
238  b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
239  b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ);
240  b.add_output<decl::Geometry>(N_("Geometry"));
241 }
242 
244 {
245  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
246  const float3 translation = params.extract_input<float3>("Translation");
247  const float3 rotation = params.extract_input<float3>("Rotation");
248  const float3 scale = params.extract_input<float3>("Scale");
249 
250  /* Use only translation if rotation and scale don't apply. */
251  if (use_translate(rotation, scale)) {
252  translate_geometry_set(params, geometry_set, translation, *params.depsgraph());
253  }
254  else {
256  geometry_set,
257  float4x4::from_loc_eul_scale(translation, rotation, scale),
258  *params.depsgraph());
259  }
260 
261  params.set_output("Geometry", std::move(geometry_set));
262 }
263 } // namespace blender::nodes::node_geo_transform_cc
264 
266 {
267  namespace file_ns = blender::nodes::node_geo_transform_cc;
268 
269  static bNodeType ntype;
270 
274  nodeRegisterType(&ntype);
275 }
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
Low-level operations for curves.
void BKE_mesh_translate(struct Mesh *me, const float offset[3], bool do_keys)
Definition: mesh.cc:1632
void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys)
Definition: mesh.cc:1594
#define GEO_NODE_TRANSFORM
Definition: BKE_node.h:1384
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
General operations for point clouds.
Volume data-block.
VolumeGrid * BKE_volume_grid_get_for_write(struct Volume *volume, int grid_index)
Definition: volume.cc:1277
void BKE_volume_grid_transform_matrix(const struct VolumeGrid *grid, float mat[4][4])
void BKE_volume_grid_transform_matrix_set(struct VolumeGrid *volume_grid, const float mat[4][4])
Definition: volume.cc:1480
int BKE_volume_num_grids(const struct Volume *volume)
bool BKE_volume_grid_determinant_valid(double determinant)
Definition: volume.cc:1593
bool BKE_volume_load(const struct Volume *volume, const struct Main *bmain)
MINLINE int compare_ff(float a, float b, float max_diff)
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
void mul_m4_m4_pre(float R[4][4], const float A[4][4])
Definition: math_matrix.c:372
float determinant_m4(const float m[4][4])
Definition: math_matrix.c:2063
MINLINE float normalize_v3(float r[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE void add_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS(...)
#define TIP_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
struct Main * DEG_get_bmain(const Depsgraph *graph)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
@ PROP_XYZ
Definition: RNA_types.h:162
@ PROP_EULER
Definition: RNA_types.h:159
@ PROP_TRANSLATION
Definition: RNA_types.h:154
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
btScalar determinant() const
Return the determinant of the matrix.
Definition: btMatrix3x3.h:1022
blender::MutableSpan< blender::float4x4 > instance_transforms()
std::optional< Array< float3 > > positions
Definition: BKE_curves.hh:434
std::optional< Array< float3x3 > > deform_mats
Definition: BKE_curves.hh:439
void translate(const float3 &translation)
static CurvesGeometry & wrap(::CurvesGeometry &dna_struct)
Definition: BKE_curves.hh:138
void transform(const float4x4 &matrix)
GSpanAttributeWriter lookup_or_add_for_write_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefault())
const Depsgraph * depsgraph
uint pos
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud)
bool is_zero(const T &a)
T length_squared(const vec_base< T, Size > &a)
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
static void transform_volume(GeoNodeExecParams &params, Volume &volume, const float4x4 &transform, const Depsgraph &depsgraph)
static void transform_instances(InstancesComponent &instances, const float4x4 &transform)
static void translate_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float3 &translation)
static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
static void translate_geometry_set(GeoNodeExecParams &params, GeometrySet &geometry, const float3 translation, const Depsgraph &depsgraph)
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
static void translate_instances(InstancesComponent &instances, const float3 translation)
static void translate_volume(GeoNodeExecParams &params, Volume &volume, const float3 translation, const Depsgraph &depsgraph)
void transform_geometry_set(GeoNodeExecParams &params, GeometrySet &geometry, const float4x4 &transform, const Depsgraph &depsgraph)
static void translate_mesh(Mesh &mesh, const float3 translation)
void transform_mesh(Mesh &mesh, const float3 translation, const float3 rotation, const float3 scale)
static bool use_translate(const float3 rotation, const float3 scale)
static void transform_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float4x4 &transform)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
void register_node_type_geo_transform()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
CurvesGeometry geometry
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
Curves * get_curves_for_write()
PointCloud * get_pointcloud_for_write()
Mesh * get_mesh_for_write()
bool has_instances() const
blender::bke::CurvesEditHints * get_curve_edit_hints_for_write()
Volume * get_volume_for_write()
Definition: BKE_main.h:121
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
NodeDeclareFunction declare
Definition: BKE_node.h:324
float values[3][3]
Definition: BLI_float3x3.hh:18
static float4x4 from_loc_eul_scale(const float3 location, const float3 rotation, const float3 scale)
Definition: BLI_float4x4.hh:27
float values[4][4]
Definition: BLI_float4x4.hh:13
static float4x4 from_location(const float3 location)
Definition: BLI_float4x4.hh:36
#define N_(msgid)