Blender V4.5
geometry/intern/transform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#ifdef WITH_OPENVDB
6# include <openvdb/openvdb.h>
7#endif
8
9#include "GEO_transform.hh"
10
11#include "BLI_math_matrix.h"
12#include "BLI_math_matrix.hh"
13#include "BLI_math_vector.hh"
14#include "BLI_task.hh"
15
17#include "DNA_mesh_types.h"
19
20#include "BKE_attribute.hh"
21#include "BKE_curves.hh"
23#include "BKE_geometry_set.hh"
24#include "BKE_grease_pencil.hh"
25#include "BKE_instances.hh"
26#include "BKE_mesh.hh"
27#include "BKE_pointcloud.hh"
28#include "BKE_volume.hh"
29
30namespace blender::geometry {
31
32static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
33{
34 threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
35 for (float3 &position : positions.slice(range)) {
36 position += translation;
37 }
38 });
39}
40
41static void transform_positions(MutableSpan<float3> positions, const float4x4 &matrix)
42{
43 threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
44 for (float3 &position : positions.slice(range)) {
45 position = math::transform_point(matrix, position);
46 }
47 });
48}
49
50static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
51{
52 if (math::is_zero(translation)) {
53 return;
54 }
55
56 std::optional<Bounds<float3>> bounds;
57 if (pointcloud.runtime->bounds_cache.is_cached()) {
58 bounds = pointcloud.runtime->bounds_cache.data();
59 }
60
61 bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
63 "position", bke::AttrDomain::Point);
64 translate_positions(position.span, translation);
65 position.finish();
66
67 if (bounds) {
68 bounds->min += translation;
69 bounds->max += translation;
70 pointcloud.runtime->bounds_cache.ensure([&](Bounds<float3> &r_data) { r_data = *bounds; });
71 }
72}
73
74static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
75{
76 bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
78 "position", bke::AttrDomain::Point);
80 position.finish();
81}
82
83static void translate_greasepencil(GreasePencil &grease_pencil, const float3 translation)
84{
85 using namespace blender::bke::greasepencil;
86 for (const int layer_index : grease_pencil.layers().index_range()) {
87 Layer &layer = grease_pencil.layer(layer_index);
88 float4x4 local_transform = layer.local_transform();
89 local_transform.location() += translation;
90 layer.set_local_transform(local_transform);
91 }
92}
93
94static void transform_greasepencil(GreasePencil &grease_pencil, const float4x4 &transform)
95{
96 using namespace blender::bke::greasepencil;
97 for (const int layer_index : grease_pencil.layers().index_range()) {
98 Layer &layer = grease_pencil.layer(layer_index);
99 float4x4 local_transform = layer.local_transform();
100 local_transform = transform * local_transform;
101 layer.set_local_transform(local_transform);
102 }
103}
104
105static void translate_instances(bke::Instances &instances, const float3 translation)
106{
107 MutableSpan<float4x4> transforms = instances.transforms_for_write();
108 threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
109 for (float4x4 &instance_transform : transforms.slice(range)) {
110 add_v3_v3(instance_transform.ptr()[3], translation);
111 }
112 });
113}
114
116{
117 MutableSpan<float4x4> transforms = instances.transforms_for_write();
118 threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
119 for (float4x4 &instance_transform : transforms.slice(range)) {
120 instance_transform = transform * instance_transform;
121 }
122 });
123}
124
125static void transform_volume(Volume &volume,
126 const float4x4 &transform,
127 TransformGeometryErrors &r_errors)
128{
129#ifdef WITH_OPENVDB
130 openvdb::Mat4s vdb_matrix;
131 memcpy(vdb_matrix.asPointer(), &transform, sizeof(float[4][4]));
132 openvdb::Mat4d vdb_matrix_d{vdb_matrix};
133
134 const int grids_num = BKE_volume_num_grids(&volume);
135 for (const int i : IndexRange(grids_num)) {
136 bke::VolumeGridData *volume_grid = BKE_volume_grid_get_for_write(&volume, i);
137
139 grid_matrix = transform * grid_matrix;
140 const float determinant = math::determinant(grid_matrix);
142 r_errors.volume_too_small = true;
143 /* Clear the tree because it is too small. */
145 if (determinant == 0) {
146 /* Reset rotation and scale. */
147 grid_matrix.x_axis() = float3(1, 0, 0);
148 grid_matrix.y_axis() = float3(0, 1, 0);
149 grid_matrix.z_axis() = float3(0, 0, 1);
150 }
151 else {
152 /* Keep rotation but reset scale. */
153 grid_matrix.x_axis() = math::normalize(grid_matrix.x_axis());
154 grid_matrix.y_axis() = math::normalize(grid_matrix.y_axis());
155 grid_matrix.z_axis() = math::normalize(grid_matrix.z_axis());
156 }
157 }
158 try {
160 }
161 catch (...) {
162 r_errors.bad_volume_transform = true;
163 }
164 }
165
166#else
167 UNUSED_VARS(volume, transform, r_errors);
168#endif
169}
170
171static void translate_volume(Volume &volume, const float3 translation)
172{
174 transform_volume(volume, math::from_location<float4x4>(translation), errors);
175}
176
178{
179 if (const std::optional<MutableSpan<float3>> positions = edit_hints.positions_for_write()) {
180 transform_positions(*positions, transform);
181 }
182 float3x3 deform_mat;
183 copy_m3_m4(deform_mat.ptr(), transform.ptr());
184 if (edit_hints.deform_mats.has_value()) {
185 MutableSpan<float3x3> deform_mats = *edit_hints.deform_mats;
186 threading::parallel_for(deform_mats.index_range(), 1024, [&](const IndexRange range) {
187 for (const int64_t i : range) {
188 deform_mats[i] = deform_mat * deform_mats[i];
189 }
190 });
191 }
192 else {
193 edit_hints.deform_mats.emplace(edit_hints.curves_id_orig.geometry.point_num, deform_mat);
194 }
195}
196
198 const float4x4 &transform)
199{
200 if (!edit_hints.drawing_hints) {
201 return;
202 }
203
204 for (bke::GreasePencilDrawingEditHints &drawing_hints : *edit_hints.drawing_hints) {
205 if (const std::optional<MutableSpan<float3>> positions = drawing_hints.positions_for_write()) {
206 transform_positions(*positions, transform);
207 }
208 float3x3 deform_mat = transform.view<3, 3>();
209 if (drawing_hints.deform_mats.has_value()) {
210 MutableSpan<float3x3> deform_mats = *drawing_hints.deform_mats;
211 threading::parallel_for(deform_mats.index_range(), 1024, [&](const IndexRange range) {
212 for (const int64_t i : range) {
213 deform_mats[i] = deform_mat * deform_mats[i];
214 }
215 });
216 }
217 else {
218 drawing_hints.deform_mats.emplace(drawing_hints.drawing_orig->strokes().points_num(),
219 deform_mat);
220 }
221 }
222}
223
225{
226 for (float4x4 &m : edit_hints.gizmo_transforms.values()) {
227 m = transform * m;
228 }
229}
230
231static void translate_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float3 &translation)
232{
233 if (const std::optional<MutableSpan<float3>> positions = edit_hints.positions_for_write()) {
234 translate_positions(*positions, translation);
235 }
236}
237
238static void translate_gizmos_edit_hints(bke::GizmoEditHints &edit_hints, const float3 &translation)
239{
240 for (float4x4 &m : edit_hints.gizmo_transforms.values()) {
241 m.location() += translation;
242 }
243}
244
246{
247 if (math::is_zero(translation)) {
248 return;
249 }
250 if (Curves *curves = geometry.get_curves_for_write()) {
251 curves->geometry.wrap().translate(translation);
252 }
253 if (Mesh *mesh = geometry.get_mesh_for_write()) {
254 bke::mesh_translate(*mesh, translation, false);
255 }
256 if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
257 translate_pointcloud(*pointcloud, translation);
258 }
259 if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
260 translate_greasepencil(*grease_pencil, translation);
261 }
262 if (Volume *volume = geometry.get_volume_for_write()) {
263 translate_volume(*volume, translation);
264 }
265 if (bke::Instances *instances = geometry.get_instances_for_write()) {
266 translate_instances(*instances, translation);
267 }
268 if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
269 translate_curve_edit_hints(*curve_edit_hints, translation);
270 }
271 if (bke::GizmoEditHints *gizmo_edit_hints = geometry.get_gizmo_edit_hints_for_write()) {
272 translate_gizmos_edit_hints(*gizmo_edit_hints, translation);
273 }
274}
275
276std::optional<TransformGeometryErrors> transform_geometry(bke::GeometrySet &geometry,
277 const float4x4 &transform)
278{
279 if (transform == float4x4::identity()) {
280 return std::nullopt;
281 }
283 if (Curves *curves = geometry.get_curves_for_write()) {
284 curves->geometry.wrap().transform(transform);
285 }
286 if (Mesh *mesh = geometry.get_mesh_for_write()) {
288 }
289 if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
290 transform_pointcloud(*pointcloud, transform);
291 }
292 if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) {
293 transform_greasepencil(*grease_pencil, transform);
294 }
295 if (Volume *volume = geometry.get_volume_for_write()) {
296 transform_volume(*volume, transform, errors);
297 }
298 if (bke::Instances *instances = geometry.get_instances_for_write()) {
299 transform_instances(*instances, transform);
300 }
301 if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
302 transform_curve_edit_hints(*curve_edit_hints, transform);
303 }
304 if (bke::GreasePencilEditHints *grease_pencil_edit_hints =
305 geometry.get_grease_pencil_edit_hints_for_write())
306 {
307 transform_grease_pencil_edit_hints(*grease_pencil_edit_hints, transform);
308 }
309 if (bke::GizmoEditHints *gizmo_edit_hints = geometry.get_gizmo_edit_hints_for_write()) {
310 transform_gizmo_edit_hints(*gizmo_edit_hints, transform);
311 }
312
313 if (errors.volume_too_small) {
314 return errors;
315 }
316 return std::nullopt;
317}
318
320 const float3 translation,
321 const math::Quaternion rotation,
322 const float3 scale)
323{
324 const float4x4 matrix = math::from_loc_rot_scale<float4x4>(translation, rotation, scale);
325 bke::mesh_transform(mesh, matrix, false);
326}
327
328} // namespace blender::geometry
Low-level operations for curves.
Low-level operations for grease pencil.
General operations for point clouds.
Volume data-block.
int BKE_volume_num_grids(const Volume *volume)
blender::bke::VolumeGridData * BKE_volume_grid_get_for_write(Volume *volume, int grid_index)
bool BKE_volume_grid_determinant_valid(double determinant)
void copy_m3_m4(float m1[3][3], const float m2[4][4])
#define UNUSED_VARS(...)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
std::optional< MutableSpan< float3 > > positions_for_write()
std::optional< Array< float3x3 > > deform_mats
std::optional< MutableSpan< float3 > > positions_for_write()
std::optional< Array< float3x3 > > deform_mats
std::optional< Array< GreasePencilDrawingEditHints > > drawing_hints
MutableSpan< float4x4 > transforms_for_write()
Definition instances.cc:240
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
const bke::CurvesGeometry & strokes() const
void set_local_transform(const float4x4 &transform)
float determinant(MatBase< C, R >) RET
VecBase< float, 3 > float3
static void transform_positions(const Span< blender::float3 > src, const blender::float4x4 &transform, blender::MutableSpan< blender::float3 > dst)
float4x4 get_transform_matrix(const VolumeGridData &grid)
void clear_tree(VolumeGridData &grid)
void set_transform_matrix(VolumeGridData &grid, const float4x4 &matrix)
void mesh_transform(Mesh &mesh, const float4x4 &transform, bool do_shape_keys)
void mesh_translate(Mesh &mesh, const float3 &translation, bool do_shape_keys)
static void translate_positions(MutableSpan< float3 > positions, const float3 &translation)
static void translate_greasepencil(GreasePencil &grease_pencil, const float3 translation)
static void transform_instances(bke::Instances &instances, const float4x4 &transform)
void translate_geometry(bke::GeometrySet &geometry, const float3 translation)
static void transform_grease_pencil_edit_hints(bke::GreasePencilEditHints &edit_hints, const float4x4 &transform)
static void translate_gizmos_edit_hints(bke::GizmoEditHints &edit_hints, const float3 &translation)
static void translate_instances(bke::Instances &instances, const float3 translation)
static void transform_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float4x4 &transform)
static void transform_gizmo_edit_hints(bke::GizmoEditHints &edit_hints, const float4x4 &transform)
void transform_mesh(Mesh &mesh, float3 translation, math::Quaternion rotation, float3 scale)
static void translate_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float3 &translation)
static void translate_volume(Volume &volume, const float3 translation)
std::optional< TransformGeometryErrors > transform_geometry(bke::GeometrySet &geometry, const float4x4 &transform)
static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
static void transform_volume(Volume &volume, const float4x4 &transform, TransformGeometryErrors &r_errors)
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
static void transform_greasepencil(GreasePencil &grease_pencil, const float4x4 &transform)
QuaternionBase< float > Quaternion
bool is_zero(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
MatT from_location(const typename MatT::loc_type &location)
T determinant(const MatBase< T, Size, Size > &mat)
MatT from_loc_rot_scale(const typename MatT::loc_type &location, const RotationT &rotation, const VecBase< typename MatT::base_type, ScaleDim > &scale)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
MatBase< float, 4, 4 > float4x4
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
PointCloudRuntimeHandle * runtime
const c_style_mat & ptr() const
i
Definition text_draw.cc:230