9 #include <assimp/GltfMaterial.h>
10 #include <assimp/material.h>
11 #include <assimp/postprocess.h>
12 #include <assimp/scene.h>
14 #include <assimp/Exporter.hpp>
15 #include <assimp/Importer.hpp>
16 #include <assimp/ProgressHandler.hpp>
17 #include <unordered_map>
25 #define AI_MATKEY_CLEARCOAT_THICKNESS "$mat.clearcoatthickness", 0, 0
26 #define AI_MATKEY_CLEARCOAT_ROUGHNESS "$mat.clearcoatroughness", 0, 0
27 #define AI_MATKEY_SHEEN "$mat.sheen", 0, 0
28 #define AI_MATKEY_ANISOTROPY "$mat.anisotropy", 0, 0
38 aiProcess_JoinIdenticalVertices | aiProcess_Triangulate |
39 aiProcess_SortByPType | aiProcess_PreTransformVertices;
43 aiProcess_GenUVCoords | aiProcess_RemoveRedundantMaterials |
44 aiProcess_OptimizeMeshes;
50 Assimp::Importer importer;
54 if (
params.enable_post_processing) {
58 const auto* scene = importer.ReadFile(
filename.c_str(), post_process_flags);
61 importer.GetErrorString());
65 std::vector<core::Tensor> mesh_vertices;
66 std::vector<core::Tensor> mesh_vertex_normals;
67 std::vector<core::Tensor> mesh_faces;
68 std::vector<core::Tensor> mesh_vertex_colors;
69 std::vector<core::Tensor> mesh_uvs;
71 size_t current_vidx = 0;
72 size_t count_mesh_with_normals = 0;
73 size_t count_mesh_with_colors = 0;
74 size_t count_mesh_with_uvs = 0;
77 for (
size_t midx = 0; midx < scene->mNumMeshes; ++midx) {
78 const auto* assimp_mesh = scene->mMeshes[midx];
82 auto vertices_ptr = vertices.
GetDataPtr<
float>();
83 std::memcpy(vertices_ptr, assimp_mesh->mVertices,
84 3 * assimp_mesh->mNumVertices *
sizeof(
float));
85 mesh_vertices.push_back(vertices);
90 if (assimp_mesh->mNormals) {
94 auto vertex_normals_ptr = vertex_normals.
GetDataPtr<
float>();
95 std::memcpy(vertex_normals_ptr, assimp_mesh->mNormals,
96 3 * assimp_mesh->mNumVertices *
sizeof(
float));
97 mesh_vertex_normals.push_back(vertex_normals);
98 count_mesh_with_normals++;
101 if (assimp_mesh->HasVertexColors(0)) {
104 auto vertex_colors_ptr = vertex_colors.
GetDataPtr<
float>();
105 for (
unsigned int i = 0; i < assimp_mesh->mNumVertices; ++i) {
106 *vertex_colors_ptr++ = assimp_mesh->mColors[0][i].r;
107 *vertex_colors_ptr++ = assimp_mesh->mColors[0][i].g;
108 *vertex_colors_ptr++ = assimp_mesh->mColors[0][i].b;
110 mesh_vertex_colors.push_back(vertex_colors);
111 count_mesh_with_colors++;
120 const auto& face = assimp_mesh->mFaces[fidx];
121 faces_ptr[3 * fidx] = face.mIndices[0] + current_vidx;
122 faces_ptr[3 * fidx + 1] = face.mIndices[1] + current_vidx;
123 faces_ptr[3 * fidx + 2] = face.mIndices[2] + current_vidx;
126 mesh_faces.push_back(faces);
128 if (assimp_mesh->HasTextureCoords(0)) {
131 auto uvs_ptr = vertex_uvs.
GetDataPtr<
float>();
134 for (
int i = 0; i < (int)assimp_mesh->mNumVertices; ++i) {
135 *uvs_ptr++ = assimp_mesh->mTextureCoords[0][i].x;
136 *uvs_ptr++ = assimp_mesh->mTextureCoords[0][i].y;
138 triangle_uvs = vertex_uvs.
IndexGet({faces});
139 mesh_uvs.push_back(triangle_uvs);
140 count_mesh_with_uvs++;
143 current_vidx +=
static_cast<int>(assimp_mesh->mNumVertices);
147 if (scene->mNumMeshes > 1) {
154 if (count_mesh_with_normals == scene->mNumMeshes) {
157 if (count_mesh_with_colors == scene->mNumMeshes) {
160 if (count_mesh_with_uvs == scene->mNumMeshes) {
166 if (count_mesh_with_normals > 0) {
169 if (count_mesh_with_colors > 0) {
172 if (count_mesh_with_uvs > 0) {
186 std::vector<uint8_t> img_buffer;
190 auto tex = scene->mTextures[texture_idx];
191 std::string tex_id(
"*");
193 tex->mFilename = tex_id.c_str();
195 tex->mWidth = img_buffer.size();
198 uint8_t* img_data =
new uint8_t[img_buffer.size()];
199 memcpy(img_data, img_buffer.data(), img_buffer.size());
200 tex->pcData =
reinterpret_cast<aiTexel*
>(img_data);
201 strcpy(tex->achFormatHint,
"png");
202 aiString uri(tex_id);
203 const int uv_index = 0;
204 const aiTextureMapMode mode = aiTextureMapMode_Wrap;
205 mat->AddProperty(&uri, AI_MATKEY_TEXTURE(tt, 0));
206 mat->AddProperty(&uv_index, 1, AI_MATKEY_UVWSRC(tt, 0));
207 mat->AddProperty(&mode, 1, AI_MATKEY_MAPPINGMODE_U(tt, 0));
208 mat->AddProperty(&mode, 1, AI_MATKEY_MAPPINGMODE_V(tt, 0));
214 size_t operator()(
const std::tuple<int64_t, float, float>& t)
const {
215 auto h1 = std::hash<int64_t>{}(std::get<0>(t));
216 auto h2 = std::hash<float>{}(std::get<1>(t));
217 auto h3 = std::hash<float>{}(std::get<2>(t));
218 return h1 ^ (h2 << 1) ^ (h3 << 2);
232 bool update_triangle_uvs) {
233 if (!mesh.HasTriangleAttr(
"texture_uvs")) {
236 auto vertices = mesh.GetVertexPositions().Contiguous();
237 auto indices = mesh.GetTriangleIndices().Contiguous();
239 mesh.GetTriangleAttr(
"texture_uvs").To(
core::Float32).Contiguous();
245 normals = mesh.GetVertexNormals().Contiguous();
248 colors = mesh.GetVertexColors().Contiguous();
251 core::Tensor new_vertices, new_faces, new_normals, new_colors, vertex_uvs;
252 bool need_updates =
true;
255 scalar_int_t next_vertex_idx = 0;
257 std::unordered_map<std::tuple<scalar_int_t, float, float>, scalar_int_t,
259 vertex_uv_to_new_idx;
261 auto p_indices = indices.GetDataPtr<scalar_int_t>();
262 auto p_uvs = triangle_uvs.GetDataPtr<float>();
263 for (int64_t i = 0; i < indices.GetShape(0); i++) {
264 for (int j = 0; j < 3; j++) {
265 auto orig_vertex_idx = *p_indices++;
268 auto key = std::make_tuple(orig_vertex_idx, u, v);
269 if (vertex_uv_to_new_idx.find(key) ==
270 vertex_uv_to_new_idx.end()) {
271 vertex_uv_to_new_idx[key] = next_vertex_idx++;
276 int64_t num_new_vertices = next_vertex_idx;
277 if (num_new_vertices == vertices.GetShape(0)) {
278 need_updates = false;
289 int color_dims =
colors.GetShape(1);
296 for (
const auto& entry : vertex_uv_to_new_idx) {
297 auto [orig_vertex_idx, u, v] = entry.first;
298 auto new_vertex_idx = entry.second;
300 new_vertices[new_vertex_idx] = vertices[orig_vertex_idx];
302 new_normals[new_vertex_idx] =
normals[orig_vertex_idx];
305 new_colors[new_vertex_idx] =
colors[orig_vertex_idx];
308 vertex_uvs[new_vertex_idx][0] = u;
309 vertex_uvs[new_vertex_idx][1] = v;
315 auto faces_ptr = indices.GetDataPtr<scalar_int_t>();
316 auto new_faces_ptr = new_faces.GetDataPtr<scalar_int_t>();
317 auto triangle_uvs_ptr = triangle_uvs.GetDataPtr<
float>();
318 for (int64_t i = 0; i < indices.GetShape(0); i++) {
319 for (
int j = 0; j < 3; j++) {
320 auto idx = *faces_ptr++;
321 auto u = *triangle_uvs_ptr++;
322 auto v = *triangle_uvs_ptr++;
323 *new_faces_ptr++ = vertex_uv_to_new_idx[{idx, u, v}];
331 new_mesh.SetVertexPositions(new_vertices);
332 new_mesh.SetTriangleIndices(new_faces);
334 new_mesh.SetVertexNormals(new_normals);
337 new_mesh.SetVertexColors(new_colors);
339 new_mesh.SetVertexAttr(
"texture_uvs", vertex_uvs);
343 if (update_triangle_uvs) {
344 auto new_triangle_uvs =
347 scalar_int_t vertex_idx;
348 auto new_faces_ptr = new_faces.GetDataPtr<scalar_int_t>();
349 auto new_triangle_uvs_ptr = new_triangle_uvs.GetDataPtr<float>();
350 auto vertex_uvs_ptr = vertex_uvs.GetDataPtr<float>();
351 for (int64_t i = 0; i < indices.GetShape(0); i++) {
352 for (int j = 0; j < 3; j++) {
353 vertex_idx = *new_faces_ptr++;
354 *new_triangle_uvs_ptr++ = vertex_uvs_ptr[2 * vertex_idx];
355 *new_triangle_uvs_ptr++ =
356 vertex_uvs_ptr[2 * vertex_idx + 1];
360 new_mesh.SetTriangleAttr(
"texture_uvs", new_triangle_uvs);
363 if (mesh.HasMaterial()) {
364 new_mesh.SetMaterial(mesh.GetMaterial());
375 const bool write_vertex_normals,
376 const bool write_vertex_colors,
377 const bool write_triangle_uvs,
378 const bool print_progress) {
382 "TriangleMesh can't be saved in ASCII format as .glb");
387 "TriangleMesh can't be saved in compressed format as .glb");
392 "TriangleMesh has no vertex positions and can't be saved as "
399 "Exporting triangle normals is not supported. Please convert "
400 "to vertex normals or export to a format that supports it.");
404 "Exporting triangle colors is not supported. Please convert to "
405 "vertex colors or export to a format that supports it.");
416 w_mesh = MakeVertexUVsUnique(w_mesh,
false);
419 Assimp::Exporter exporter;
420 auto ai_scene = std::unique_ptr<aiScene>(
new aiScene);
423 ai_scene->mNumMeshes = 1;
424 ai_scene->mMeshes =
new aiMesh*[1];
425 auto ai_mesh =
new aiMesh;
426 ai_mesh->mName.Set(
"Object1");
427 ai_mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
432 ai_mesh->mNumVertices = vertices.
GetShape(0);
433 ai_mesh->mVertices =
new aiVector3D[ai_mesh->mNumVertices];
434 memcpy(&ai_mesh->mVertices->x, vertices.GetDataPtr(),
435 sizeof(
float) * ai_mesh->mNumVertices * 3);
436 ai_mesh->mNumFaces = indices.GetShape(0);
437 ai_mesh->mFaces =
new aiFace[ai_mesh->mNumFaces];
438 for (
unsigned int i = 0; i < ai_mesh->mNumFaces; ++i) {
439 ai_mesh->mFaces[i].mNumIndices = 3;
446 ai_mesh->mFaces[i].mIndices =
new unsigned int[3];
447 ai_mesh->mFaces[i].mIndices[0] = indices[i][0].Item<
unsigned int>();
448 ai_mesh->mFaces[i].mIndices[1] = indices[i][1].Item<
unsigned int>();
449 ai_mesh->mFaces[i].mIndices[2] = indices[i][2].Item<
unsigned int>();
454 auto m_normals =
normals.GetShape(0);
455 ai_mesh->mNormals =
new aiVector3D[m_normals];
456 memcpy(&ai_mesh->mNormals->x,
normals.GetDataPtr(),
457 sizeof(
float) * m_normals * 3);
462 auto m_colors =
colors.GetShape(0);
463 ai_mesh->mColors[0] =
new aiColor4D[m_colors];
464 if (
colors.GetShape(1) == 4) {
465 memcpy(&ai_mesh->mColors[0][0].r,
colors.GetDataPtr(),
466 sizeof(
float) * m_colors * 4);
468 auto color_ptr =
reinterpret_cast<float*
>(
colors.GetDataPtr());
469 for (
unsigned int i = 0; i < m_colors; ++i) {
470 ai_mesh->mColors[0][i].r = *color_ptr++;
471 ai_mesh->mColors[0][i].g = *color_ptr++;
472 ai_mesh->mColors[0][i].b = *color_ptr++;
473 ai_mesh->mColors[0][i].a = 1.0f;
478 if (write_triangle_uvs &&
482 auto uv_ptr = vertex_uvs.GetDataPtr<
float>();
483 auto n_uvs = vertex_uvs.GetShape(0);
484 ai_mesh->mNumUVComponents[0] = 2;
485 ai_mesh->mTextureCoords[0] =
new aiVector3D[n_uvs];
486 for (
unsigned int i = 0; i < n_uvs; ++i) {
487 ai_mesh->mTextureCoords[0][i].x = *uv_ptr++;
488 ai_mesh->mTextureCoords[0][i].y = *uv_ptr++;
490 }
else if (write_triangle_uvs && w_mesh.
HasTriangleAttr(
"texture_uvs")) {
494 auto n_uvs = ai_mesh->mNumVertices;
495 for (int64_t i = 0; i < indices.GetShape(0); i++) {
496 vertex_uvs[indices[i][0].Item<uint32_t>()] = triangle_uvs[i][0];
497 vertex_uvs[indices[i][1].Item<uint32_t>()] = triangle_uvs[i][1];
498 vertex_uvs[indices[i][2].Item<uint32_t>()] = triangle_uvs[i][2];
500 ai_mesh->mTextureCoords[0] =
new aiVector3D[n_uvs];
501 auto uv_ptr =
reinterpret_cast<float*
>(vertex_uvs.GetDataPtr());
502 for (
unsigned int i = 0; i < n_uvs; ++i) {
503 ai_mesh->mTextureCoords[0][i].x = *uv_ptr++;
504 ai_mesh->mTextureCoords[0][i].y = *uv_ptr++;
506 ai_mesh->mNumUVComponents[0] = 2;
508 ai_scene->mMeshes[0] = ai_mesh;
511 ai_scene->mNumMaterials = 1;
512 ai_scene->mMaterials =
new aiMaterial*[ai_scene->mNumMaterials];
513 auto ai_mat =
new aiMaterial;
515 ai_mat->GetName().Set(
"mat1");
516 auto shading_mode = aiShadingMode_PBR_BRDF;
517 ai_mat->AddProperty(&shading_mode, 1, AI_MATKEY_SHADING_MODEL);
524 auto ac = aiColor4D(c.x(), c.y(), c.z(), c.w());
525 ai_mat->AddProperty(&ac, 1, AI_MATKEY_COLOR_DIFFUSE);
526 ai_mat->AddProperty(&ac, 1, AI_MATKEY_BASE_COLOR);
530 ai_mat->AddProperty(&r, 1, AI_MATKEY_ROUGHNESS_FACTOR);
534 ai_mat->AddProperty(&m, 1, AI_MATKEY_METALLIC_FACTOR);
538 ai_mat->AddProperty(&c, 1, AI_MATKEY_CLEARCOAT_FACTOR);
542 ai_mat->AddProperty(&r, 1, AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR);
546 auto ac = aiColor4D(c.x(), c.y(), c.z(), c.w());
547 ai_mat->AddProperty(&ac, 1, AI_MATKEY_COLOR_EMISSIVE);
567 if (n_textures > 0) {
568 ai_scene->mTextures =
new aiTexture*[n_textures];
569 for (
int i = 0; i < n_textures; ++i) {
570 ai_scene->mTextures[i] =
new aiTexture();
572 ai_scene->mNumTextures = n_textures;
580 aiTextureType_DIFFUSE, img);
582 aiTextureType_BASE_COLOR, img);
588 aiTextureType_UNKNOWN, img);
595 auto cols = rough.GetCols();
598 rough_metal.AsTensor() =
602 auto metal_channel = metal.AsTensor().
GetItem(
606 auto rough_channel = rough.AsTensor().
GetItem(
610 rough_metal.AsTensor().
SetItem(
615 rough_metal.AsTensor().
SetItem(
621 aiTextureType_UNKNOWN, rough_metal);
627 aiTextureType_UNKNOWN, img);
633 aiTextureType_UNKNOWN, img);
640 aiTextureType_NORMALS, img);
644 ai_scene->mMaterials[0] = ai_mat;
646 auto root_node =
new aiNode;
647 root_node->mName.Set(
"root");
648 root_node->mNumMeshes = 1;
649 root_node->mMeshes =
new unsigned int[root_node->mNumMeshes];
650 root_node->mMeshes[0] = 0;
651 ai_scene->mRootNode = root_node;
654 if (exporter.Export(ai_scene.get(),
"glb2",
filename.c_str()) ==
657 "Got error: ({}) while writing TriangleMesh to file {}.",
658 exporter.GetErrorString(),
filename);
#define DISPATCH_INT_DTYPE_PREFIX_TO_TEMPLATE(DTYPE, PREFIX,...)
cmdLineReadable * params[]
static const Dtype Float32
static const Dtype UInt32
static TensorKey Index(int64_t index)
static TensorKey Slice(utility::optional< int64_t > start, utility::optional< int64_t > stop, utility::optional< int64_t > step)
Tensor Contiguous() const
Tensor GetItem(const TensorKey &tk) const
Tensor SetItem(const Tensor &value)
Set all items. Equivalent to tensor[:] = value in Python.
Tensor IndexGet(const std::vector< Tensor > &index_tensors) const
Advanced indexing getter. This will always allocate a new Tensor.
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
static Tensor Ones(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with ones.
SizeVector GetShape() const
Tensor To(Dtype dtype, bool copy=false) const
bool HasMaterial() const
Check if a material has been applied to this Geometry with SetMaterial.
visualization::rendering::Material & GetMaterial()
Get material associated with this Geometry.
The Image class stores image with customizable rows, cols, channels, dtype and device.
int64_t GetRows() const
Get the number of rows of the image.
TensorMap Contiguous() const
A triangle mesh contains vertices and triangles.
bool HasTriangleNormals() const
core::Tensor & GetTriangleIndices()
core::Tensor & GetVertexNormals()
TriangleMesh & Clear() override
Clear all data in the trianglemesh.
const TensorMap & GetVertexAttr() const
Getter for vertex_attr_ TensorMap. Used in Pybind.
bool HasVertexNormals() const
bool HasVertexPositions() const
core::Tensor & GetVertexPositions()
bool HasTriangleColors() const
core::Tensor & GetVertexColors()
void SetVertexPositions(const core::Tensor &value)
void SetTriangleIndices(const core::Tensor &value)
Set the value of the "indices" attribute in triangle_attr_.
void SetVertexNormals(const core::Tensor &value)
bool HasVertexAttr(const std::string &key) const
void RemoveVertexAttr(const std::string &key)
bool HasVertexColors() const
bool HasTriangleAttr(const std::string &key) const
void SetVertexColors(const core::Tensor &value)
void SetTriangleAttr(const std::string &key, const core::Tensor &value)
const TensorMap & GetTriangleAttr() const
Getter for triangle_attr_ TensorMap. Used in Pybind.
const t::geometry::Image & GetMetallicMap() const
bool HasNormalMap() const
Eigen::Vector4f GetBaseColor() const
bool HasRoughnessMap() const
bool HasMetallicMap() const
float GetBaseClearcoatRoughness() const
bool HasAlbedoMap() const
const t::geometry::Image & GetRoughnessMap() const
bool HasBaseRoughness() const
bool HasEmissiveColor() const
Eigen::Vector4f GetEmissiveColor() const
float GetBaseClearcoat() const
const t::geometry::Image & GetNormalMap() const
bool HasBaseColor() const
bool HasBaseClearcoatRoughness() const
float GetBaseRoughness() const
bool HasBaseClearcoat() const
float GetBaseMetallic() const
bool HasBaseMetallic() const
bool HasAORoughnessMetalMap() const
const t::geometry::Image & GetAORoughnessMetalMap() const
const t::geometry::Image & GetAlbedoMap() const
void ParallelFor(const Device &device, int64_t n, const func_t &func)
Tensor Concatenate(const std::vector< Tensor > &tensors, const utility::optional< int64_t > &axis)
Concatenates the list of tensors in their order, along the given axis into a new tensor....
constexpr utility::nullopt_t None
bool WriteImageToPNGInMemory(std::vector< uint8_t > &buffer, const t::geometry::Image &image, int quality)
const unsigned int kPostProcessFlags_fast
static void SetTextureMaterialProperty(aiMaterial *mat, aiScene *scene, int texture_idx, aiTextureType tt, t::geometry::Image &img)
const unsigned int kPostProcessFlags_compulsory
bool WriteTriangleMeshUsingASSIMP(const std::string &filename, const geometry::TriangleMesh &mesh, const bool write_ascii, const bool compressed, const bool write_vertex_normals, const bool write_vertex_colors, const bool write_triangle_uvs, const bool print_progress)
bool ReadTriangleMeshUsingASSIMP(const std::string &filename, geometry::TriangleMesh &mesh, const cloudViewer::io::ReadTriangleMeshOptions ¶ms)
Generic file read and write utility for python interface.
std::string to_string(const T &n)