Blender  V2.93
node_geo_transform.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #ifdef WITH_OPENVDB
18 # include <openvdb/openvdb.h>
19 #endif
20 
21 #include "BLI_float4x4.hh"
22 
23 #include "DNA_pointcloud_types.h"
24 #include "DNA_volume_types.h"
25 
26 #include "BKE_mesh.h"
27 #include "BKE_volume.h"
28 
29 #include "DEG_depsgraph_query.h"
30 
31 #include "node_geometry_util.hh"
32 
34  {SOCK_GEOMETRY, N_("Geometry")},
35  {SOCK_VECTOR, N_("Translation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
36  {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
37  {SOCK_VECTOR, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
38  {-1, ""},
39 };
40 
42  {SOCK_GEOMETRY, N_("Geometry")},
43  {-1, ""},
44 };
45 
46 namespace blender::nodes {
47 
48 static bool use_translate(const float3 rotation, const float3 scale)
49 {
50  if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) {
51  return false;
52  }
53  if (compare_ff(scale.x, 1.0f, 1e-9f) != 1 || compare_ff(scale.y, 1.0f, 1e-9f) != 1 ||
54  compare_ff(scale.z, 1.0f, 1e-9f) != 1) {
55  return false;
56  }
57  return true;
58 }
59 
61  const float3 translation,
62  const float3 rotation,
63  const float3 scale)
64 {
65  /* Use only translation if rotation and scale are zero. */
66  if (use_translate(rotation, scale)) {
67  if (!translation.is_zero()) {
68  BKE_mesh_translate(mesh, translation, false);
69  }
70  }
71  else {
72  const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
73  BKE_mesh_transform(mesh, matrix.values, false);
75  }
76 }
77 
78 static void transform_pointcloud(PointCloud *pointcloud,
79  const float3 translation,
80  const float3 rotation,
81  const float3 scale)
82 {
83  /* Use only translation if rotation and scale don't apply. */
84  if (use_translate(rotation, scale)) {
85  for (const int i : IndexRange(pointcloud->totpoint)) {
86  add_v3_v3(pointcloud->co[i], translation);
87  }
88  }
89  else {
90  const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
91  for (const int i : IndexRange(pointcloud->totpoint)) {
92  float3 &co = *(float3 *)pointcloud->co[i];
93  co = matrix * co;
94  }
95  }
96 }
97 
98 static void transform_instances(InstancesComponent &instances,
99  const float3 translation,
100  const float3 rotation,
101  const float3 scale)
102 {
103  MutableSpan<float4x4> transforms = instances.transforms();
104 
105  /* Use only translation if rotation and scale don't apply. */
106  if (use_translate(rotation, scale)) {
107  for (float4x4 &transform : transforms) {
108  add_v3_v3(transform.ptr()[3], translation);
109  }
110  }
111  else {
112  const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
113  for (float4x4 &transform : transforms) {
114  transform = matrix * transform;
115  }
116  }
117 }
118 
119 static void transform_volume(Volume *volume,
120  const float3 translation,
121  const float3 rotation,
122  const float3 scale,
124 {
125 #ifdef WITH_OPENVDB
126  /* Scaling an axis to zero is not supported for volumes. */
127  const float3 limited_scale = {
128  (scale.x == 0.0f) ? FLT_EPSILON : scale.x,
129  (scale.y == 0.0f) ? FLT_EPSILON : scale.y,
130  (scale.z == 0.0f) ? FLT_EPSILON : scale.z,
131  };
132 
133  const Main *bmain = DEG_get_bmain(params.depsgraph());
134  BKE_volume_load(volume, bmain);
135 
136  const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, limited_scale);
137 
138  openvdb::Mat4s vdb_matrix;
139  memcpy(vdb_matrix.asPointer(), matrix, sizeof(float[4][4]));
140  openvdb::Mat4d vdb_matrix_d{vdb_matrix};
141 
142  const int num_grids = BKE_volume_num_grids(volume);
143  for (const int i : IndexRange(num_grids)) {
144  VolumeGrid *volume_grid = BKE_volume_grid_get_for_write(volume, i);
145 
146  openvdb::GridBase::Ptr grid = BKE_volume_grid_openvdb_for_write(volume, volume_grid, false);
147  openvdb::math::Transform &grid_transform = grid->transform();
148  grid_transform.postMult(vdb_matrix_d);
149  }
150 #else
151  UNUSED_VARS(volume, translation, rotation, scale, params);
152 #endif
153 }
154 
156 {
157  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
158  const float3 translation = params.extract_input<float3>("Translation");
159  const float3 rotation = params.extract_input<float3>("Rotation");
160  const float3 scale = params.extract_input<float3>("Scale");
161 
162  if (geometry_set.has_mesh()) {
163  Mesh *mesh = geometry_set.get_mesh_for_write();
164  transform_mesh(mesh, translation, rotation, scale);
165  }
166 
167  if (geometry_set.has_pointcloud()) {
168  PointCloud *pointcloud = geometry_set.get_pointcloud_for_write();
169  transform_pointcloud(pointcloud, translation, rotation, scale);
170  }
171 
172  if (geometry_set.has_instances()) {
174  transform_instances(instances, translation, rotation, scale);
175  }
176 
177  if (geometry_set.has_volume()) {
178  Volume *volume = geometry_set.get_volume_for_write();
179  transform_volume(volume, translation, rotation, scale, params);
180  }
181 
182  params.set_output("Geometry", std::move(geometry_set));
183 }
184 } // namespace blender::nodes
185 
187 {
188  static bNodeType ntype;
189 
193  nodeRegisterType(&ntype);
194 }
void BKE_mesh_calc_normals(struct Mesh *me)
void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys)
Definition: mesh.c:1485
void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys)
Definition: mesh.c:1522
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
#define GEO_NODE_TRANSFORM
Definition: BKE_node.h:1378
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
Volume datablock.
VolumeGrid * BKE_volume_grid_get_for_write(struct Volume *volume, int grid_index)
Definition: volume.cc:1183
int BKE_volume_num_grids(const struct Volume *volume)
bool BKE_volume_load(const struct Volume *volume, const struct Main *bmain)
MINLINE int compare_ff(float a, float b, const float max_diff)
MINLINE void add_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS(...)
#define N_(msgid)
struct Main * DEG_get_bmain(const Depsgraph *graph)
@ SOCK_VECTOR
@ SOCK_GEOMETRY
@ PROP_XYZ
Definition: RNA_types.h:148
@ PROP_EULER
Definition: RNA_types.h:145
@ PROP_TRANSLATION
Definition: RNA_types.h:140
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
blender::Span< blender::float4x4 > transforms() const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void transform_mesh(Mesh *mesh, const float3 translation, const float3 rotation, const float3 scale)
static void transform_instances(InstancesComponent &instances, const float3 translation, const float3 rotation, const float3 scale)
static void geo_node_transform_exec(GeoNodeExecParams params)
static void transform_pointcloud(PointCloud *pointcloud, const float3 translation, const float3 rotation, const float3 scale)
static void transform_volume(Volume *volume, const float3 translation, const float3 rotation, const float3 scale, GeoNodeExecParams &params)
static bool use_translate(const float3 rotation, const float3 scale)
static bNodeSocketTemplate geo_node_transform_in[]
void register_node_type_geo_transform()
static bNodeSocketTemplate geo_node_transform_out[]
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
bool has_volume() const
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
PointCloud * get_pointcloud_for_write()
Mesh * get_mesh_for_write()
bool has_instances() const
bool has_mesh() const
Volume * get_volume_for_write()
bool has_pointcloud() const
Definition: BKE_main.h:116
float(* co)[3]
Compact definition of a node socket.
Definition: BKE_node.h:95
Defines a node type.
Definition: BKE_node.h:221
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:327
float length_squared() const
Definition: BLI_float3.hh:172
bool is_zero() const
Definition: BLI_float3.hh:177
static float4x4 from_loc_eul_scale(const float3 location, const float3 rotation, const float3 scale)
Definition: BLI_float4x4.hh:39
float values[4][4]
Definition: BLI_float4x4.hh:25
CCL_NAMESPACE_BEGIN struct Transform Transform