scimesh 0.3.4
Headless CPU-only 3D software renderer for scientific mesh visualization
Loading...
Searching...
No Matches
ply_io.cpp
Go to the documentation of this file.
1#define TINYPLY_IMPLEMENTATION
2#include "tinyply.h"
3#include <scimesh/ply_io.h>
4#include <scimesh/types.h>
5
6#include <fstream>
7#include <stdexcept>
8#include <algorithm>
9#include <cstdint>
10#include <cstring>
11
12namespace scimesh {
13namespace ply_io {
14
15namespace {
16
21float read_alpha(const tinyply::PlyData &data, size_t i) {
22 const uint8_t *raw = data.buffer.get_const();
23 switch (data.t) {
24 case tinyply::Type::UINT8:
25 return raw[i] / 255.0f;
26 case tinyply::Type::INT8: {
27 int8_t v = 0;
28 std::memcpy(&v, raw + i, sizeof(v));
29 return std::max<int>(0, v) / 255.0f;
30 }
31 case tinyply::Type::UINT16: {
32 uint16_t v = 0;
33 std::memcpy(&v, raw + i * sizeof(v), sizeof(v));
34 return v / 65535.0f;
35 }
36 case tinyply::Type::FLOAT32: {
37 float v = 0.0f;
38 std::memcpy(&v, raw + i * sizeof(v), sizeof(v));
39 return v;
40 }
41 default:
42 return 1.0f;
43 }
44}
45
46} // anonymous namespace
47
48Mesh read_ply(const std::string &path) {
49 std::ifstream ifs(path, std::ios::binary);
50 if (!ifs.good()) {
51 throw std::runtime_error("Failed to open PLY file: " + path);
52 }
53
54 tinyply::PlyFile ply;
55 ply.parse_header(ifs);
56
57 bool has_vertex_colors = false;
58 bool has_vertex_alpha = false;
59 tinyply::Type vertex_color_type = tinyply::Type::UINT8;
60 for (const auto &el : ply.get_elements()) {
61 if (el.name == "vertex") {
62 for (const auto &prop : el.properties) {
63 if (prop.name == "red" || prop.name == "green" || prop.name == "blue") {
64 if (!has_vertex_colors) vertex_color_type = prop.propertyType;
65 has_vertex_colors = true;
66 } else if (prop.name == "alpha") {
67 has_vertex_alpha = true;
68 }
69 }
70 }
71 }
72
73 auto vertices_data = ply.request_properties_from_element("vertex", {"x", "y", "z"});
74 auto faces_data = ply.request_properties_from_element("face", {"vertex_indices"}, 3);
75 std::shared_ptr<tinyply::PlyData> colors_data;
77 colors_data = ply.request_properties_from_element("vertex", {"red", "green", "blue"});
78 }
79 std::shared_ptr<tinyply::PlyData> alpha_data;
80 if (has_vertex_alpha) {
81 // Requested separately from red/green/blue: tinyply requires all
82 // properties of one request to share the same type, and RGBA files
83 // commonly mix 8-bit color with float alpha.
84 alpha_data = ply.request_properties_from_element("vertex", {"alpha"});
85 }
86
87 ply.read(ifs);
88
89 Mesh mesh;
90 const size_t num_vertices = vertices_data->count;
91 mesh.vertices.resize(num_vertices);
92
93 const float *vptr = reinterpret_cast<const float *>(vertices_data->buffer.get_const());
94 for (size_t i = 0; i < num_vertices; ++i) {
95 mesh.vertices[i] = Vec3(vptr[i * 3], vptr[i * 3 + 1], vptr[i * 3 + 2]);
96 }
97
99 mesh.colors.resize(num_vertices);
100 if (vertex_color_type == tinyply::Type::UINT8) {
101 const uint8_t *cptr = reinterpret_cast<const uint8_t *>(colors_data->buffer.get_const());
102 for (size_t i = 0; i < num_vertices; ++i) {
103 mesh.colors[i] = Color(
104 cptr[i * 3] / 255.0f,
105 cptr[i * 3 + 1] / 255.0f,
106 cptr[i * 3 + 2] / 255.0f,
107 alpha_data ? read_alpha(*alpha_data, i) : 1.0f);
108 }
109 } else if (vertex_color_type == tinyply::Type::FLOAT32) {
110 const float *cptr = reinterpret_cast<const float *>(colors_data->buffer.get_const());
111 for (size_t i = 0; i < num_vertices; ++i) {
112 mesh.colors[i] = Color(cptr[i * 3], cptr[i * 3 + 1], cptr[i * 3 + 2],
113 alpha_data ? read_alpha(*alpha_data, i) : 1.0f);
114 }
115 } else if (alpha_data) {
116 // No usable RGB type, but the file does carry alpha: keep the
117 // transparency information rather than dropping it silently.
118 for (size_t i = 0; i < num_vertices; ++i) {
119 mesh.colors[i] = Color(1.0f, 1.0f, 1.0f, read_alpha(*alpha_data, i));
120 }
121 }
122 } else if (alpha_data) {
123 // Alpha without any color: white vertices with the file's alpha.
124 mesh.colors.resize(num_vertices);
125 for (size_t i = 0; i < num_vertices; ++i) {
126 mesh.colors[i] = Color(1.0f, 1.0f, 1.0f, read_alpha(*alpha_data, i));
127 }
128 }
129
130 const size_t num_faces = faces_data->count;
131 mesh.triangles.resize(num_faces);
132 const int32_t *fptr = reinterpret_cast<const int32_t *>(faces_data->buffer.get_const());
133 for (size_t i = 0; i < num_faces; ++i) {
134 mesh.triangles[i] = Triangle{
135 static_cast<uint32_t>(fptr[i * 3]),
136 static_cast<uint32_t>(fptr[i * 3 + 1]),
137 static_cast<uint32_t>(fptr[i * 3 + 2])};
138 }
139
140 // Keep Mesh::has_transparency in sync with the colors we just read.
141 mesh.update_transparency();
142
143 return mesh;
144}
145
146} // namespace ply_io
147} // namespace scimesh
Mesh read_ply(const std::string &path)
Load a mesh from a Stanford PLY file.
Definition ply_io.cpp:48
glm::vec3 Vec3
3-component floating-point vector (xyz).
Definition types.h:46
Read Stanford PLY files (.ply).
An RGBA color with floating-point components.
Definition types.h:88
A 3D triangle mesh using an indexed face set representation.
Definition mesh.h:76
void update_transparency()
Recompute has_transparency from the mesh's colors.
Definition mesh.h:256
std::vector< Color > colors
Per-vertex RGBA colors.
Definition mesh.h:107
std::vector< Vec3 > vertices
3D vertex positions.
Definition mesh.h:86
std::vector< Triangle > triangles
Triangle index triplets.
Definition mesh.h:94
A triangle defined by three vertex indices.
Definition types.h:127
int x
Left edge of the bitmap, in image pixels.
Definition text.cpp:223
Fundamental types used throughout the scimesh rendering engine.