Blender V4.3
ply_export_load_plydata.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
8
10#include "IO_ply.hh"
11#include "ply_data.hh"
12
13#include "BKE_attribute.hh"
14#include "BKE_lib_id.hh"
15#include "BKE_mesh.hh"
16#include "BKE_mesh_wrapper.hh"
17#include "BKE_object.hh"
18#include "BLI_color.hh"
19#include "BLI_hash.hh"
20#include "BLI_math_matrix.h"
22#include "BLI_math_rotation.h"
23#include "BLI_math_vector.h"
24#include "BLI_vector.hh"
25
27
29#include "DNA_layer_types.h"
30
31#include "bmesh.hh"
33
34namespace blender::io::ply {
35
36static Mesh *do_triangulation(const Mesh *mesh, bool force_triangulation)
37{
38 const BMeshCreateParams bm_create_params = {false};
39 BMeshFromMeshParams bm_convert_params{};
40 bm_convert_params.calc_face_normal = true;
41 bm_convert_params.calc_vert_normal = true;
42 const int triangulation_threshold = force_triangulation ? 4 : 255;
43
44 BMesh *bmesh = BKE_mesh_to_bmesh_ex(mesh, &bm_create_params, &bm_convert_params);
45 BM_mesh_triangulate(bmesh, 0, 3, triangulation_threshold, false, nullptr, nullptr, nullptr);
46 Mesh *temp_mesh = BKE_mesh_from_bmesh_for_eval_nomain(bmesh, nullptr, mesh);
47 BM_mesh_free(bmesh);
48 return temp_mesh;
49}
50
51static void set_world_axes_transform(const Object &object,
52 const eIOAxis forward,
53 const eIOAxis up,
54 float r_world_and_axes_transform[4][4],
55 float r_world_and_axes_normal_transform[3][3])
56{
57 float axes_transform[3][3];
58 unit_m3(axes_transform);
59 /* +Y-forward and +Z-up are the default Blender axis settings. */
60 mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
61 mul_m4_m3m4(r_world_and_axes_transform, axes_transform, object.object_to_world().ptr());
62 /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
63 mul_v3_m3v3(r_world_and_axes_transform[3], axes_transform, object.object_to_world().location());
64 r_world_and_axes_transform[3][3] = object.object_to_world()[3][3];
65
66 /* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */
67 float normal_matrix[3][3];
68 copy_m3_m4(normal_matrix, r_world_and_axes_transform);
69 invert_m3_m3(r_world_and_axes_normal_transform, normal_matrix);
70 transpose_m3(r_world_and_axes_normal_transform);
71}
72
76
77 bool operator==(const uv_vertex_key &r) const
78 {
79 return (uv == r.uv && vertex_index == r.vertex_index);
80 }
81
82 uint64_t hash() const
83 {
84 return get_default_hash(uv.x, uv.y, vertex_index);
85 }
86};
87
88static void generate_vertex_map(const Mesh *mesh,
89 const PLYExportParams &export_params,
90 Vector<int> &r_ply_to_vertex,
91 Vector<int> &r_vertex_to_ply,
92 Vector<int> &r_loop_to_ply,
93 Vector<float2> &r_uvs)
94{
95 bool export_uv = false;
96 VArraySpan<float2> uv_map;
97 if (export_params.export_uv) {
99 if (!uv_name.is_empty()) {
100 const bke::AttributeAccessor attributes = mesh->attributes();
101 uv_map = *attributes.lookup<float2>(uv_name, bke::AttrDomain::Corner);
102 export_uv = !uv_map.is_empty();
103 }
104 }
105
106 const Span<int> corner_verts = mesh->corner_verts();
107 r_vertex_to_ply.resize(mesh->verts_num, -1);
108 r_loop_to_ply.resize(mesh->corners_num, -1);
109
110 /* If we do not export or have UVs, then mapping of vertex indices is simple. */
111 if (!export_uv) {
112 r_ply_to_vertex.resize(mesh->verts_num);
113 for (int index = 0; index < mesh->verts_num; index++) {
114 r_vertex_to_ply[index] = index;
115 r_ply_to_vertex[index] = index;
116 }
117 for (int index = 0; index < mesh->corners_num; index++) {
118 r_loop_to_ply[index] = corner_verts[index];
119 }
120 return;
121 }
122
123 /* We are exporting UVs. Need to build mappings of what
124 * any unique (vertex, UV) values will map into the PLY data. */
125 Map<uv_vertex_key, int> vertex_map;
126 vertex_map.reserve(mesh->verts_num);
127 r_ply_to_vertex.reserve(mesh->verts_num);
128 r_uvs.reserve(mesh->verts_num);
129
130 for (int loop_index = 0; loop_index < int(corner_verts.size()); loop_index++) {
131 int vertex_index = corner_verts[loop_index];
132 uv_vertex_key key{uv_map[loop_index], vertex_index};
133 int ply_index = vertex_map.lookup_or_add(key, int(vertex_map.size()));
134 r_vertex_to_ply[vertex_index] = ply_index;
135 r_loop_to_ply[loop_index] = ply_index;
136 while (r_uvs.size() <= ply_index) {
137 r_uvs.append(key.uv);
138 r_ply_to_vertex.append(key.vertex_index);
139 }
140 }
141
142 /* Add zero UVs for any loose vertices. */
143 for (int vertex_index = 0; vertex_index < mesh->verts_num; vertex_index++) {
144 if (r_vertex_to_ply[vertex_index] != -1) {
145 continue;
146 }
147 int ply_index = int(r_uvs.size());
148 r_vertex_to_ply[vertex_index] = ply_index;
149 r_uvs.append({0, 0});
150 r_ply_to_vertex.append(vertex_index);
151 }
152}
153
154static float *find_or_add_attribute(const StringRef name,
156 uint32_t vertex_offset,
157 Vector<PlyCustomAttribute> &r_attributes)
158{
159 /* Do we have this attribute from some other object already? */
160 for (PlyCustomAttribute &attr : r_attributes) {
161 if (attr.name == name) {
162 BLI_assert(attr.data.size() == vertex_offset);
163 attr.data.resize(attr.data.size() + size, 0.0f);
164 return attr.data.data() + vertex_offset;
165 }
166 }
167 /* We don't have it yet, create and fill with zero data for previous objects. */
168 r_attributes.append(PlyCustomAttribute(name, vertex_offset + size));
169 return r_attributes.last().data.data() + vertex_offset;
170}
171
172static void load_custom_attributes(const Mesh *mesh,
173 const Span<int> ply_to_vertex,
174 uint32_t vertex_offset,
175 Vector<PlyCustomAttribute> &r_attributes)
176{
177 const bke::AttributeAccessor attributes = mesh->attributes();
178 const StringRef color_name = mesh->active_color_attribute;
180 const int64_t size = ply_to_vertex.size();
181
182 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
183 /* Skip internal, standard and non-vertex domain attributes. */
184 if (iter.domain != bke::AttrDomain::Point || iter.name[0] == '.' ||
186 ELEM(iter.name, "position", color_name, uv_name))
187 {
188 return;
189 }
190
191 const GVArraySpan attribute = *iter.get();
192 if (attribute.is_empty()) {
193 return;
194 }
195 switch (iter.data_type) {
196 case CD_PROP_FLOAT: {
197 float *attr = find_or_add_attribute(iter.name, size, vertex_offset, r_attributes);
198 auto typed = attribute.typed<float>();
199 for (const int64_t i : ply_to_vertex.index_range()) {
200 attr[i] = typed[ply_to_vertex[i]];
201 }
202 break;
203 }
204 case CD_PROP_INT8: {
205 float *attr = find_or_add_attribute(iter.name, size, vertex_offset, r_attributes);
206 auto typed = attribute.typed<int8_t>();
207 for (const int64_t i : ply_to_vertex.index_range()) {
208 attr[i] = typed[ply_to_vertex[i]];
209 }
210 break;
211 }
212 case CD_PROP_INT32: {
213 float *attr = find_or_add_attribute(iter.name, size, vertex_offset, r_attributes);
214 auto typed = attribute.typed<int32_t>();
215 for (const int64_t i : ply_to_vertex.index_range()) {
216 attr[i] = typed[ply_to_vertex[i]];
217 }
218 break;
219 }
220 case CD_PROP_INT32_2D: {
221 float *attr_x = find_or_add_attribute(iter.name + "_x", size, vertex_offset, r_attributes);
222 float *attr_y = find_or_add_attribute(iter.name + "_y", size, vertex_offset, r_attributes);
223 auto typed = attribute.typed<int2>();
224 for (const int64_t i : ply_to_vertex.index_range()) {
225 int j = ply_to_vertex[i];
226 attr_x[i] = typed[j].x;
227 attr_y[i] = typed[j].y;
228 }
229 break;
230 }
231 case CD_PROP_FLOAT2: {
232 float *attr_x = find_or_add_attribute(iter.name + "_x", size, vertex_offset, r_attributes);
233 float *attr_y = find_or_add_attribute(iter.name + "_y", size, vertex_offset, r_attributes);
234 auto typed = attribute.typed<float2>();
235 for (const int64_t i : ply_to_vertex.index_range()) {
236 int j = ply_to_vertex[i];
237 attr_x[i] = typed[j].x;
238 attr_y[i] = typed[j].y;
239 }
240 break;
241 }
242 case CD_PROP_FLOAT3: {
243 float *attr_x = find_or_add_attribute(iter.name + "_x", size, vertex_offset, r_attributes);
244 float *attr_y = find_or_add_attribute(iter.name + "_y", size, vertex_offset, r_attributes);
245 float *attr_z = find_or_add_attribute(iter.name + "_z", size, vertex_offset, r_attributes);
246 auto typed = attribute.typed<float3>();
247 for (const int64_t i : ply_to_vertex.index_range()) {
248 int j = ply_to_vertex[i];
249 attr_x[i] = typed[j].x;
250 attr_y[i] = typed[j].y;
251 attr_z[i] = typed[j].z;
252 }
253 break;
254 }
255 case CD_PROP_BYTE_COLOR: {
256 float *attr_r = find_or_add_attribute(iter.name + "_r", size, vertex_offset, r_attributes);
257 float *attr_g = find_or_add_attribute(iter.name + "_g", size, vertex_offset, r_attributes);
258 float *attr_b = find_or_add_attribute(iter.name + "_b", size, vertex_offset, r_attributes);
259 float *attr_a = find_or_add_attribute(iter.name + "_a", size, vertex_offset, r_attributes);
260 auto typed = attribute.typed<ColorGeometry4b>();
261 for (const int64_t i : ply_to_vertex.index_range()) {
262 ColorGeometry4f col = typed[ply_to_vertex[i]].decode();
263 attr_r[i] = col.r;
264 attr_g[i] = col.g;
265 attr_b[i] = col.b;
266 attr_a[i] = col.a;
267 }
268 break;
269 }
270 case CD_PROP_COLOR: {
271 float *attr_r = find_or_add_attribute(iter.name + "_r", size, vertex_offset, r_attributes);
272 float *attr_g = find_or_add_attribute(iter.name + "_g", size, vertex_offset, r_attributes);
273 float *attr_b = find_or_add_attribute(iter.name + "_b", size, vertex_offset, r_attributes);
274 float *attr_a = find_or_add_attribute(iter.name + "_a", size, vertex_offset, r_attributes);
275 auto typed = attribute.typed<ColorGeometry4f>();
276 for (const int64_t i : ply_to_vertex.index_range()) {
277 ColorGeometry4f col = typed[ply_to_vertex[i]];
278 attr_r[i] = col.r;
279 attr_g[i] = col.g;
280 attr_b[i] = col.b;
281 attr_a[i] = col.a;
282 }
283 break;
284 }
285 case CD_PROP_BOOL: {
286 float *attr = find_or_add_attribute(iter.name, size, vertex_offset, r_attributes);
287 auto typed = attribute.typed<bool>();
288 for (const int64_t i : ply_to_vertex.index_range()) {
289 attr[i] = typed[ply_to_vertex[i]] ? 1.0f : 0.0f;
290 }
291 break;
292 }
293 case CD_PROP_QUATERNION: {
294 float *attr_x = find_or_add_attribute(iter.name + "_x", size, vertex_offset, r_attributes);
295 float *attr_y = find_or_add_attribute(iter.name + "_y", size, vertex_offset, r_attributes);
296 float *attr_z = find_or_add_attribute(iter.name + "_z", size, vertex_offset, r_attributes);
297 float *attr_w = find_or_add_attribute(iter.name + "_w", size, vertex_offset, r_attributes);
298 auto typed = attribute.typed<math::Quaternion>();
299 for (const int64_t i : ply_to_vertex.index_range()) {
300 int j = ply_to_vertex[i];
301 attr_x[i] = typed[j].x;
302 attr_y[i] = typed[j].y;
303 attr_z[i] = typed[j].z;
304 attr_w[i] = typed[j].w;
305 }
306 break;
307 }
308 default:
309 BLI_assert_msg(0, "Unsupported attribute type for PLY export.");
310 }
311 });
312}
313
314void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams &export_params)
315{
316 DEGObjectIterSettings deg_iter_settings{};
317 deg_iter_settings.depsgraph = depsgraph;
318 deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
321
322 /* When exporting multiple objects, vertex indices have to be offset. */
323 uint32_t vertex_offset = 0;
324
325 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, object) {
326 if (object->type != OB_MESH) {
327 continue;
328 }
329
330 if (export_params.export_selected_objects && !(object->base_flag & BASE_SELECTED)) {
331 continue;
332 }
333
334 Object *obj_eval = DEG_get_evaluated_object(depsgraph, object);
335 Mesh *mesh = export_params.apply_modifiers ? BKE_object_get_evaluated_mesh(obj_eval) :
337
338 /* Ensure data exists if currently in edit mode. */
340
341 bool force_triangulation = false;
342 OffsetIndices faces = mesh->faces();
343 for (const int i : faces.index_range()) {
344 if (faces[i].size() > 255) {
345 force_triangulation = true;
346 break;
347 }
348 }
349
350 /* Triangulate */
351 bool manually_free_mesh = false;
352 if (export_params.export_triangulated_mesh || force_triangulation) {
353 mesh = do_triangulation(mesh, export_params.export_triangulated_mesh);
354 faces = mesh->faces();
355 manually_free_mesh = true;
356 }
357
358 Vector<int> ply_to_vertex, vertex_to_ply, loop_to_ply;
359 Vector<float2> uvs;
360 generate_vertex_map(mesh, export_params, ply_to_vertex, vertex_to_ply, loop_to_ply, uvs);
361
362 float world_and_axes_transform[4][4];
363 float world_and_axes_normal_transform[3][3];
364 set_world_axes_transform(*obj_eval,
365 export_params.forward_axis,
366 export_params.up_axis,
367 world_and_axes_transform,
368 world_and_axes_normal_transform);
369
370 /* Face data. */
371 plyData.face_vertices.reserve(plyData.face_vertices.size() + mesh->corners_num);
372 for (const int corner : IndexRange(mesh->corners_num)) {
373 int ply_index = loop_to_ply[corner];
374 BLI_assert(ply_index >= 0 && ply_index < ply_to_vertex.size());
375 plyData.face_vertices.append_unchecked(ply_index + vertex_offset);
376 }
377
378 plyData.face_sizes.reserve(plyData.face_sizes.size() + mesh->faces_num);
379 for (const int i : faces.index_range()) {
380 const IndexRange face = faces[i];
381 plyData.face_sizes.append_unchecked(face.size());
382 }
383
384 /* Vertices */
385 plyData.vertices.reserve(plyData.vertices.size() + ply_to_vertex.size());
386 Span<float3> vert_positions = mesh->vert_positions();
387 for (int vertex_index : ply_to_vertex) {
388 float3 pos = vert_positions[vertex_index];
389 mul_m4_v3(world_and_axes_transform, pos);
390 mul_v3_fl(pos, export_params.global_scale);
391 plyData.vertices.append_unchecked(pos);
392 }
393
394 /* UV's */
395 if (uvs.is_empty()) {
396 uvs.append_n_times(float2(0), ply_to_vertex.size());
397 }
398 else {
399 BLI_assert(uvs.size() == ply_to_vertex.size());
400 plyData.uv_coordinates.extend(uvs);
401 }
402
403 /* Normals */
404 if (export_params.export_normals) {
405 plyData.vertex_normals.reserve(plyData.vertex_normals.size() + ply_to_vertex.size());
406 const Span<float3> vert_normals = mesh->vert_normals();
407 for (int vertex_index : ply_to_vertex) {
408 float3 normal = vert_normals[vertex_index];
409 mul_m3_v3(world_and_axes_normal_transform, normal);
410 normalize_v3(normal);
411 plyData.vertex_normals.append(normal);
412 }
413 }
414
415 /* Colors */
416 if (export_params.vertex_colors != PLY_VERTEX_COLOR_NONE) {
417 const StringRef name = mesh->active_color_attribute;
418 if (!name.is_empty()) {
419 const bke::AttributeAccessor attributes = mesh->attributes();
420 const VArray color_attribute = *attributes.lookup_or_default<ColorGeometry4f>(
421 name, bke::AttrDomain::Point, {0.0f, 0.0f, 0.0f, 0.0f});
422 if (!color_attribute.is_empty()) {
423 if (plyData.vertex_colors.size() != vertex_offset) {
424 plyData.vertex_colors.resize(vertex_offset, float4(0));
425 }
426
427 plyData.vertex_colors.reserve(vertex_offset + ply_to_vertex.size());
428 for (int vertex_index : ply_to_vertex) {
429 float4 color = float4(color_attribute[vertex_index]);
430 if (export_params.vertex_colors == PLY_VERTEX_COLOR_SRGB) {
432 }
433 plyData.vertex_colors.append(color);
434 }
435 }
436 }
437 }
438
439 /* Custom attributes */
440 if (export_params.export_attributes) {
441 load_custom_attributes(mesh, ply_to_vertex, vertex_offset, plyData.vertex_custom_attr);
442 }
443
444 /* Loose edges */
445 const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
446 if (loose_edges.count > 0) {
447 Span<int2> edges = mesh->edges();
448 for (int i = 0; i < edges.size(); ++i) {
449 if (loose_edges.is_loose_bits[i]) {
450 plyData.edges.append({vertex_to_ply[edges[i][0]], vertex_to_ply[edges[i][1]]});
451 }
452 }
453 }
454
455 vertex_offset = int(plyData.vertices.size());
456 if (manually_free_mesh) {
457 BKE_id_free(nullptr, mesh);
458 }
459 }
460
462
463 /* Make sure color and attribute arrays are encompassing all input objects */
464 if (!plyData.vertex_colors.is_empty()) {
465 BLI_assert(plyData.vertex_colors.size() <= vertex_offset);
466 plyData.vertex_colors.resize(vertex_offset, float4(0));
467 }
468 for (PlyCustomAttribute &attr : plyData.vertex_custom_attr) {
469 BLI_assert(attr.data.size() <= vertex_offset);
470 attr.data.resize(vertex_offset, 0.0f);
471 }
472}
473
474} // namespace blender::io::ply
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
void BKE_id_free(Main *bmain, void *idv)
Mesh * BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings)
BMesh * BKE_mesh_to_bmesh_ex(const Mesh *mesh, const BMeshCreateParams *create_params, const BMeshFromMeshParams *convert_params)
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
Mesh * BKE_object_get_pre_modified_mesh(const Object *object)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4])
void mul_m3_v3(const float M[3][3], float r[3])
void unit_m3(float m[3][3])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void mul_m4_v3(const float M[4][4], float r[3])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
void transpose_m3(float R[3][3])
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4])
bool mat3_from_axis_conversion(int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE float normalize_v3(float n[3])
#define ELEM(...)
#define DEG_OBJECT_ITER_BEGIN(settings_, instance_)
#define DEG_OBJECT_ITER_END
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY
@ DEG_ITER_OBJECT_FLAG_VISIBLE
@ DEG_ITER_OBJECT_FLAG_DUPLI
@ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_PROP_COLOR
@ CD_PROP_QUATERNION
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ OB_MESH
#define BASE_SELECTED(v3d, base)
eIOAxis
@ IO_AXIS_Y
@ IO_AXIS_Z
@ PLY_VERTEX_COLOR_NONE
Definition IO_ply.hh:22
@ PLY_VERTEX_COLOR_SRGB
Definition IO_ply.hh:23
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method, const int min_vertices, const bool tag_only, BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_facemap_double_out)
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
AttributeSet attributes
int64_t size() const
void append(const T &value)
void resize(const int64_t new_size)
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
constexpr int64_t size() const
int64_t size() const
Definition BLI_map.hh:927
void reserve(int64_t n)
Definition BLI_map.hh:979
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:551
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
constexpr bool is_empty() const
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
void resize(const int64_t new_size)
void reserve(const int64_t min_capacity)
void append_n_times(const T &value, const int64_t n)
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
GAttributeReader get() const
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
static char faces[256]
bool attribute_name_is_anonymous(const StringRef name)
static void load_custom_attributes(const Mesh *mesh, const Span< int > ply_to_vertex, uint32_t vertex_offset, Vector< PlyCustomAttribute > &r_attributes)
void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams &export_params)
static void generate_vertex_map(const Mesh *mesh, const PLYExportParams &export_params, Vector< int > &r_ply_to_vertex, Vector< int > &r_vertex_to_ply, Vector< int > &r_loop_to_ply, Vector< float2 > &r_uvs)
static void set_world_axes_transform(const Object &object, const eIOAxis forward, const eIOAxis up, float r_world_and_axes_transform[4][4], float r_world_and_axes_normal_transform[3][3])
static Mesh * do_triangulation(const Mesh *mesh, bool force_triangulation)
static float * find_or_add_attribute(const StringRef name, int64_t size, uint32_t vertex_offset, Vector< PlyCustomAttribute > &r_attributes)
QuaternionBase< float > Quaternion
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
uint64_t get_default_hash(const T &v)
Definition BLI_hash.hh:219
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
VecBase< float, 3 > float3
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
Definition BLI_color.hh:338
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
signed int int32_t
Definition stdint.h:77
unsigned __int64 uint64_t
Definition stdint.h:90
signed char int8_t
Definition stdint.h:75
int corners_num
CustomData corner_data
int faces_num
int verts_num
char * active_color_attribute
eIOAxis forward_axis
Definition IO_ply.hh:40
bool apply_modifiers
Definition IO_ply.hh:46
bool export_attributes
Definition IO_ply.hh:50
eIOAxis up_axis
Definition IO_ply.hh:41
ePLYVertexColorMode vertex_colors
Definition IO_ply.hh:49
float global_scale
Definition IO_ply.hh:42
bool export_triangulated_mesh
Definition IO_ply.hh:51
bool export_selected_objects
Definition IO_ply.hh:45
bool export_normals
Definition IO_ply.hh:48
blender::BitVector is_loose_bits
Vector< float3 > vertices
Definition ply_data.hh:29
Vector< uint32_t > face_vertices
Definition ply_data.hh:34
Vector< float4 > vertex_colors
Definition ply_data.hh:31
Vector< float3 > vertex_normals
Definition ply_data.hh:30
Vector< std::pair< int, int > > edges
Definition ply_data.hh:33
Vector< PlyCustomAttribute > vertex_custom_attr
Definition ply_data.hh:32
Vector< float2 > uv_coordinates
Definition ply_data.hh:36
Vector< uint32_t > face_sizes
Definition ply_data.hh:35
bool operator==(const uv_vertex_key &r) const
PointerRNA * ptr
Definition wm_files.cc:4126