Blender V4.3
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 <iostream>
7#include <random>
8
9#include "GEO_randomize.hh"
10
11#include "DNA_curves_types.h"
12#include "DNA_mesh_types.h"
14
15#include "BKE_attribute.hh"
16#include "BKE_attribute_math.hh"
17#include "BKE_curves.hh"
18#include "BKE_customdata.hh"
19#include "BKE_geometry_set.hh"
20#include "BKE_global.hh"
21#include "BKE_instances.hh"
22
23#include "BLI_array.hh"
24
25namespace blender::geometry {
26
27static Array<int> get_permutation(const int length, const int seed)
28{
29 Array<int> data(length);
30 for (const int i : IndexRange(length)) {
31 data[i] = i;
32 }
33 std::shuffle(data.begin(), data.end(), std::default_random_engine(seed));
34 return data;
35}
36
37static Array<int> invert_permutation(const Span<int> permutation)
38{
39 Array<int> data(permutation.size());
40 for (const int i : permutation.index_range()) {
41 data[permutation[i]] = i;
42 }
43 return data;
44}
45
54static int seed_from_mesh(const Mesh &mesh)
55{
56 return mesh.verts_num;
57}
58
59static int seed_from_pointcloud(const PointCloud &pointcloud)
60{
61 return pointcloud.totpoint;
62}
63
64static int seed_from_curves(const bke::CurvesGeometry &curves)
65{
66 return curves.point_num;
67}
68
69static int seed_from_instances(const bke::Instances &instances)
70{
71 return instances.instances_num();
72}
73
74static void reorder_customdata(CustomData &data, const Span<int> new_by_old_map)
75{
76 CustomData new_data;
77 CustomData_init_layout_from(&data, &new_data, CD_MASK_ALL, CD_CONSTRUCT, new_by_old_map.size());
78
79 for (const int old_i : new_by_old_map.index_range()) {
80 const int new_i = new_by_old_map[old_i];
81 CustomData_copy_data(&data, &new_data, old_i, new_i, 1);
82 }
83 CustomData_free(&data, new_by_old_map.size());
84 data = new_data;
85}
86
88{
89 if (mesh == nullptr || !use_debug_randomization()) {
90 return;
91 }
92
93 const int seed = seed_from_mesh(*mesh);
94 const Array<int> new_by_old_map = get_permutation(mesh->verts_num, seed);
95
96 reorder_customdata(mesh->vert_data, new_by_old_map);
97
98 for (int &v : mesh->edges_for_write().cast<int>()) {
99 v = new_by_old_map[v];
100 }
101 for (int &v : mesh->corner_verts_for_write()) {
102 v = new_by_old_map[v];
103 }
104
105 mesh->tag_topology_changed();
106}
107
109{
110 if (mesh == nullptr || !use_debug_randomization()) {
111 return;
112 }
113
114 const int seed = seed_from_mesh(*mesh);
115 const Array<int> new_by_old_map = get_permutation(mesh->edges_num, seed);
116
117 reorder_customdata(mesh->edge_data, new_by_old_map);
118
119 for (int &e : mesh->corner_edges_for_write()) {
120 e = new_by_old_map[e];
121 }
122
123 mesh->tag_topology_changed();
124}
125
127 const Span<int> old_by_new_map)
128{
129 Array<int> new_offsets(old_offsets.data().size());
130 new_offsets[0] = 0;
131 for (const int new_i : old_offsets.index_range()) {
132 const int old_i = old_by_new_map[new_i];
133 new_offsets[new_i + 1] = new_offsets[new_i] + old_offsets[old_i].size();
134 }
135 return new_offsets;
136}
137
139 const OffsetIndices<int> old_offsets,
140 const OffsetIndices<int> new_offsets,
141 const Span<int> new_by_old_map)
142{
143 const int elements_num = new_offsets.total_size();
144 const int groups_num = new_by_old_map.size();
145 CustomData new_data;
146 CustomData_init_layout_from(&data, &new_data, CD_MASK_ALL, CD_CONSTRUCT, elements_num);
147 for (const int old_i : IndexRange(groups_num)) {
148 const int new_i = new_by_old_map[old_i];
149 const IndexRange old_range = old_offsets[old_i];
150 const IndexRange new_range = new_offsets[new_i];
151 BLI_assert(old_range.size() == new_range.size());
152 CustomData_copy_data(&data, &new_data, old_range.start(), new_range.start(), old_range.size());
153 }
154 CustomData_free(&data, elements_num);
155 data = new_data;
156}
157
159{
160 if (mesh == nullptr || mesh->faces_num == 0 || !use_debug_randomization()) {
161 return;
162 }
163
164 const int seed = seed_from_mesh(*mesh);
165 const Array<int> new_by_old_map = get_permutation(mesh->faces_num, seed);
166 const Array<int> old_by_new_map = invert_permutation(new_by_old_map);
167
168 reorder_customdata(mesh->face_data, new_by_old_map);
169
170 const OffsetIndices old_faces = mesh->faces();
171 Array<int> new_face_offsets = make_new_offset_indices(old_faces, old_by_new_map);
172 const OffsetIndices<int> new_faces = new_face_offsets.as_span();
173
174 reorder_customdata_groups(mesh->corner_data, old_faces, new_faces, new_by_old_map);
175
176 mesh->face_offsets_for_write().copy_from(new_face_offsets);
177
178 mesh->tag_topology_changed();
179}
180
182{
183 if (pointcloud == nullptr || !use_debug_randomization()) {
184 return;
185 }
186
187 const int seed = seed_from_pointcloud(*pointcloud);
188 const Array<int> new_by_old_map = get_permutation(pointcloud->totpoint, seed);
189
190 reorder_customdata(pointcloud->pdata, new_by_old_map);
191
192 pointcloud->tag_positions_changed();
193 pointcloud->tag_radii_changed();
194}
195
197{
198 if (curves == nullptr || !use_debug_randomization()) {
199 return;
200 }
201
202 const int seed = seed_from_curves(*curves);
203 const Array<int> new_by_old_map = get_permutation(curves->curve_num, seed);
204 const Array<int> old_by_new_map = invert_permutation(new_by_old_map);
205
206 reorder_customdata(curves->curve_data, new_by_old_map);
207
208 const OffsetIndices old_points_by_curve = curves->points_by_curve();
209 Array<int> new_curve_offsets = make_new_offset_indices(old_points_by_curve, old_by_new_map);
210 const OffsetIndices<int> new_points_by_curve = new_curve_offsets.as_span();
211
213 curves->point_data, old_points_by_curve, new_points_by_curve, new_by_old_map);
214
215 curves->offsets_for_write().copy_from(new_curve_offsets);
216
217 curves->tag_topology_changed();
218}
219
221{
222 if (mesh == nullptr || !use_debug_randomization()) {
223 return;
224 }
225
229}
230
232{
233 if (instances == nullptr || !use_debug_randomization()) {
234 return;
235 }
236 const int instances_num = instances->instances_num();
237 const int seed = seed_from_instances(*instances);
238 const Array<int> new_by_old_map = get_permutation(instances_num, seed);
239 reorder_customdata(instances->custom_data_attributes(), new_by_old_map);
240}
241
243{
244 return G.randomize_geometry_element_order;
245}
246
247} // namespace blender::geometry
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
@ CD_CONSTRUCT
void CustomData_free(CustomData *data, int totelem)
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:50
#define CD_MASK_ALL
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static unsigned long seed
Definition btSoftBody.h:39
Span< T > as_span() const
Definition BLI_array.hh:232
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
#define G(x, y, z)
void debug_randomize_edge_order(Mesh *mesh)
Definition randomize.cc:108
static Array< int > invert_permutation(const Span< int > permutation)
Definition randomize.cc:37
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:138
bool use_debug_randomization()
Definition randomize.cc:242
static int seed_from_curves(const bke::CurvesGeometry &curves)
Definition randomize.cc:64
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:220
void debug_randomize_curve_order(bke::CurvesGeometry *curves)
Definition randomize.cc:196
static Array< int > make_new_offset_indices(const OffsetIndices< int > old_offsets, const Span< int > old_by_new_map)
Definition randomize.cc:126
static int seed_from_pointcloud(const PointCloud &pointcloud)
Definition randomize.cc:59
void debug_randomize_vert_order(Mesh *mesh)
Definition randomize.cc:87
static Array< int > get_permutation(const int length, const int seed)
Definition randomize.cc:27
void debug_randomize_face_order(Mesh *mesh)
Definition randomize.cc:158
static void reorder_customdata(CustomData &data, const Span< int > new_by_old_map)
Definition randomize.cc:74
void debug_randomize_point_order(PointCloud *pointcloud)
Definition randomize.cc:181
static int seed_from_mesh(const Mesh &mesh)
Definition randomize.cc:54
static int seed_from_instances(const bke::Instances &instances)
Definition randomize.cc:69
void debug_randomize_instance_order(bke::Instances *instances)
Definition randomize.cc:231
struct CustomData pdata