Blender V5.0
randomize.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <algorithm>
6#include <random>
7
8#include "GEO_randomize.hh"
9
10#include "DNA_curves_types.h"
11#include "DNA_mesh_types.h"
13
15#include "BKE_curves.hh"
16#include "BKE_customdata.hh"
17#include "BKE_geometry_set.hh"
18#include "BKE_global.hh"
19#include "BKE_instances.hh"
20
21#include "BLI_array.hh"
22
23namespace blender::geometry {
24
25static Array<int> get_permutation(const int length, const int seed)
26{
28 for (const int i : IndexRange(length)) {
29 data[i] = i;
30 }
31 std::shuffle(data.begin(), data.end(), std::default_random_engine(seed));
32 return data;
33}
34
35static Array<int> invert_permutation(const Span<int> permutation)
36{
37 Array<int> data(permutation.size());
38 for (const int i : permutation.index_range()) {
39 data[permutation[i]] = i;
40 }
41 return data;
42}
43
52static int seed_from_mesh(const Mesh &mesh)
53{
54 return mesh.verts_num;
55}
56
57static int seed_from_pointcloud(const PointCloud &pointcloud)
58{
59 return pointcloud.totpoint;
60}
61
62static int seed_from_curves(const bke::CurvesGeometry &curves)
63{
64 return curves.point_num;
65}
66
67static int seed_from_instances(const bke::Instances &instances)
68{
69 return instances.instances_num();
70}
71
72static void reorder_customdata(CustomData &data, const Span<int> new_by_old_map)
73{
74 CustomData new_data;
75 CustomData_init_layout_from(&data, &new_data, CD_MASK_ALL, CD_CONSTRUCT, new_by_old_map.size());
76
77 for (const int old_i : new_by_old_map.index_range()) {
78 const int new_i = new_by_old_map[old_i];
79 CustomData_copy_data(&data, &new_data, old_i, new_i, 1);
80 }
82 data = new_data;
83}
84
86 const bke::AttrDomain domain,
87 const Span<int> new_by_old_map)
88{
89 data.foreach([&](bke::Attribute &attr) {
90 if (attr.domain() != domain) {
91 return;
92 }
94 switch (attr.storage_type()) {
96 const auto &data = std::get<bke::Attribute::ArrayData>(attr.data());
97 auto new_data = bke::Attribute::ArrayData::from_constructed(type, new_by_old_map.size());
99 new_by_old_map,
100 GMutableSpan(type, new_data.data, new_data.size));
101 attr.assign_data(std::move(new_data));
102 }
104 return;
105 }
106 }
107 });
108}
109
111{
112 if (mesh == nullptr || !use_debug_randomization()) {
113 return;
114 }
115
116 const int seed = seed_from_mesh(*mesh);
117 const Array<int> new_by_old_map = get_permutation(mesh->verts_num, seed);
118
119 reorder_customdata(mesh->vert_data, new_by_old_map);
120
121 for (int &v : mesh->edges_for_write().cast<int>()) {
122 v = new_by_old_map[v];
123 }
124 for (int &v : mesh->corner_verts_for_write()) {
125 v = new_by_old_map[v];
126 }
127
128 mesh->tag_topology_changed();
129}
130
132{
133 if (mesh == nullptr || !use_debug_randomization()) {
134 return;
135 }
136
137 const int seed = seed_from_mesh(*mesh);
138 const Array<int> new_by_old_map = get_permutation(mesh->edges_num, seed);
139
140 reorder_customdata(mesh->edge_data, new_by_old_map);
141
142 for (int &e : mesh->corner_edges_for_write()) {
143 e = new_by_old_map[e];
144 }
145
146 mesh->tag_topology_changed();
147}
148
150 const Span<int> old_by_new_map)
151{
152 Array<int> new_offsets(old_offsets.data().size());
153 new_offsets[0] = 0;
154 for (const int new_i : old_offsets.index_range()) {
155 const int old_i = old_by_new_map[new_i];
156 new_offsets[new_i + 1] = new_offsets[new_i] + old_offsets[old_i].size();
157 }
158 return new_offsets;
159}
160
162 const OffsetIndices<int> old_offsets,
163 const OffsetIndices<int> new_offsets,
164 const Span<int> new_by_old_map)
165{
166 const int elements_num = new_offsets.total_size();
167 const int groups_num = new_by_old_map.size();
168 CustomData new_data;
169 CustomData_init_layout_from(&data, &new_data, CD_MASK_ALL, CD_CONSTRUCT, elements_num);
170 for (const int old_i : IndexRange(groups_num)) {
171 const int new_i = new_by_old_map[old_i];
172 const IndexRange old_range = old_offsets[old_i];
173 const IndexRange new_range = new_offsets[new_i];
174 BLI_assert(old_range.size() == new_range.size());
175 CustomData_copy_data(&data, &new_data, old_range.start(), new_range.start(), old_range.size());
176 }
178 data = new_data;
179}
180
182 const bke::AttrDomain domain,
183 const OffsetIndices<int> old_offsets,
184 const OffsetIndices<int> new_offsets,
185 const Span<int> new_by_old_map)
186{
187 const int groups_num = new_by_old_map.size();
188 storage.foreach([&](bke::Attribute &attr) {
189 if (attr.domain() != domain) {
190 return;
191 }
193 switch (attr.storage_type()) {
195 const auto &data = std::get<bke::Attribute::ArrayData>(attr.data());
196
197 auto new_data = bke::Attribute::ArrayData::from_uninitialized(type, new_by_old_map.size());
198 threading::parallel_for(IndexRange(groups_num), 1024, [&](const IndexRange range) {
199 for (const int old_i : range) {
200 const int new_i = new_by_old_map[old_i];
201 const IndexRange old_range = old_offsets[old_i];
202 const IndexRange new_range = new_offsets[new_i];
203 BLI_assert(old_range.size() == new_range.size());
204 type.copy_construct_n(POINTER_OFFSET(data.data, old_range.start() * type.size),
205 POINTER_OFFSET(new_data.data, new_range.start() * type.size),
206 old_range.size());
207 }
208 });
209
210 attr.assign_data(std::move(new_data));
211 }
213 return;
214 }
215 }
216 });
217}
218
220{
221 if (mesh == nullptr || mesh->faces_num == 0 || !use_debug_randomization()) {
222 return;
223 }
224
225 const int seed = seed_from_mesh(*mesh);
226 const Array<int> new_by_old_map = get_permutation(mesh->faces_num, seed);
227 const Array<int> old_by_new_map = invert_permutation(new_by_old_map);
228
229 reorder_customdata(mesh->face_data, new_by_old_map);
230
231 const OffsetIndices old_faces = mesh->faces();
232 Array<int> new_face_offsets = make_new_offset_indices(old_faces, old_by_new_map);
233 const OffsetIndices<int> new_faces = new_face_offsets.as_span();
234
235 reorder_customdata_groups(mesh->corner_data, old_faces, new_faces, new_by_old_map);
236
237 mesh->face_offsets_for_write().copy_from(new_face_offsets);
238
239 mesh->tag_topology_changed();
240}
241
243{
244 if (pointcloud == nullptr || !use_debug_randomization()) {
245 return;
246 }
247
248 const int seed = seed_from_pointcloud(*pointcloud);
249 const Array<int> new_by_old_map = get_permutation(pointcloud->totpoint, seed);
251 pointcloud->attribute_storage.wrap(), bke::AttrDomain::Point, new_by_old_map);
252
253 pointcloud->tag_positions_changed();
254 pointcloud->tag_radii_changed();
255}
256
258{
259 if (curves == nullptr || !use_debug_randomization()) {
260 return;
261 }
262
263 const int seed = seed_from_curves(*curves);
264 const Array<int> new_by_old_map = get_permutation(curves->curve_num, seed);
265 const Array<int> old_by_new_map = invert_permutation(new_by_old_map);
266
267 bke::AttributeStorage &attributes = curves->attribute_storage.wrap();
268
269 reorder_attribute_domain(attributes, bke::AttrDomain::Curve, new_by_old_map);
270
271 const OffsetIndices old_points_by_curve = curves->points_by_curve();
272 Array<int> new_curve_offsets = make_new_offset_indices(old_points_by_curve, old_by_new_map);
273 const OffsetIndices<int> new_points_by_curve = new_curve_offsets.as_span();
274
276 curves->point_data, old_points_by_curve, new_points_by_curve, new_by_old_map);
277 reorder_attribute_groups(attributes,
279 old_points_by_curve,
280 new_points_by_curve,
281 new_by_old_map);
282
283 curves->offsets_for_write().copy_from(new_curve_offsets);
284
285 curves->tag_topology_changed();
286}
287
289{
290 if (mesh == nullptr || !use_debug_randomization()) {
291 return;
292 }
293
297}
298
300{
301 if (instances == nullptr || !use_debug_randomization()) {
302 return;
303 }
304 const int instances_num = instances->instances_num();
305 const int seed = seed_from_instances(*instances);
306 const Array<int> new_by_old_map = get_permutation(instances_num, seed);
308 instances->attribute_storage(), bke::AttrDomain::Instance, new_by_old_map);
309}
310
312{
313 return G.randomize_geometry_element_order;
314}
315
316} // namespace blender::geometry
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
@ CD_CONSTRUCT
void CustomData_free(CustomData *data)
void CustomData_init_layout_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define POINTER_OFFSET(v, ofs)
#define CD_MASK_ALL
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static unsigned long seed
Definition btSoftBody.h:39
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
Span< T > as_span() const
Definition BLI_array.hh:243
void copy_construct_n(const void *src, void *dst, int64_t n) const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
void foreach(FunctionRef< void(Attribute &)> fn)
AttrStorageType storage_type() const
const DataVariant & data() const
void assign_data(DataVariant &&data)
OffsetIndices< int > points_by_curve() const
MutableSpan< int > offsets_for_write()
int instances_num() const
Definition instances.cc:393
bke::AttributeStorage & attribute_storage()
float length(VecOp< float, D >) RET
#define G(x, y, z)
void gather(GSpan src, Span< int > map, GMutableSpan dst)
const CPPType & attribute_type_to_cpp_type(AttrType type)
void debug_randomize_edge_order(Mesh *mesh)
Definition randomize.cc:131
static Array< int > invert_permutation(const Span< int > permutation)
Definition randomize.cc:35
static void reorder_attribute_domain(bke::AttributeStorage &data, const bke::AttrDomain domain, const Span< int > new_by_old_map)
Definition randomize.cc:85
static void reorder_customdata_groups(CustomData &data, const OffsetIndices< int > old_offsets, const OffsetIndices< int > new_offsets, const Span< int > new_by_old_map)
Definition randomize.cc:161
bool use_debug_randomization()
Definition randomize.cc:311
static int seed_from_curves(const bke::CurvesGeometry &curves)
Definition randomize.cc:62
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:288
void debug_randomize_curve_order(bke::CurvesGeometry *curves)
Definition randomize.cc:257
static void reorder_attribute_groups(bke::AttributeStorage &storage, const bke::AttrDomain domain, const OffsetIndices< int > old_offsets, const OffsetIndices< int > new_offsets, const Span< int > new_by_old_map)
Definition randomize.cc:181
static Array< int > make_new_offset_indices(const OffsetIndices< int > old_offsets, const Span< int > old_by_new_map)
Definition randomize.cc:149
static int seed_from_pointcloud(const PointCloud &pointcloud)
Definition randomize.cc:57
void debug_randomize_vert_order(Mesh *mesh)
Definition randomize.cc:110
static Array< int > get_permutation(const int length, const int seed)
Definition randomize.cc:25
void debug_randomize_face_order(Mesh *mesh)
Definition randomize.cc:219
static void reorder_customdata(CustomData &data, const Span< int > new_by_old_map)
Definition randomize.cc:72
void debug_randomize_point_order(PointCloud *pointcloud)
Definition randomize.cc:242
static int seed_from_mesh(const Mesh &mesh)
Definition randomize.cc:52
static int seed_from_instances(const bke::Instances &instances)
Definition randomize.cc:67
void debug_randomize_instance_order(bke::Instances *instances)
Definition randomize.cc:299
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
CustomData point_data
struct AttributeStorage attribute_storage
CustomData edge_data
int edges_num
CustomData corner_data
CustomData face_data
CustomData vert_data
int faces_num
int verts_num
struct AttributeStorage attribute_storage
static ArrayData from_uninitialized(const CPPType &type, int64_t domain_size)
static ArrayData from_constructed(const CPPType &type, int64_t domain_size)
i
Definition text_draw.cc:230