Lagrange
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Modules Pages
load_mesh_assimp.h
1/*
2 * Copyright 2021 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#ifdef LAGRANGE_WITH_ASSIMP
15
16#include <lagrange/fs/filesystem.h>
17#include <lagrange/create_mesh.h>
18#include <lagrange/attributes/attribute_utils.h>
19#include <lagrange/MeshTrait.h>
20#include <lagrange/Logger.h>
21#include <lagrange/fs/file_utils.h>
22#include <lagrange/legacy/inline.h>
23
24#include <assimp/Importer.hpp>
25#include <assimp/scene.h>
26#include <assimp/mesh.h>
27#include <assimp/material.h>
28#include <assimp/postprocess.h>
29
30#include <string>
31#include <iostream>
32
33namespace lagrange::io {
34LAGRANGE_LEGACY_INLINE
35namespace legacy {
36
37// ==== Declarations ====
38std::unique_ptr<aiScene> load_scene_assimp(const lagrange::fs::path& filename);
39std::unique_ptr<aiScene> load_scene_assimp_from_memory(const void* buffer, size_t size);
40
41template <typename MeshType,
42 std::enable_if_t<lagrange::MeshTraitHelper::is_mesh<MeshType>::value>* = nullptr>
43std::vector<std::unique_ptr<MeshType>> load_mesh_assimp(const lagrange::fs::path& filename);
44template <typename MeshType>
45std::vector<std::unique_ptr<MeshType>> load_mesh_assimp_from_memory(
46 const void* buffer,
47 size_t size);
48
49template <typename MeshType>
50std::vector<std::unique_ptr<MeshType>> extract_meshes_assimp(const aiScene* scene);
51template <typename MeshType>
52std::unique_ptr<MeshType> convert_mesh_assimp(const aiMesh* mesh);
53
54inline std::unique_ptr<aiScene> load_scene_assimp(const lagrange::fs::path& filename)
55{
56 Assimp::Importer importer;
57 const aiScene* scene = importer.ReadFile(filename.string(), 0);
58 if (!scene) {
59 logger().error("Error loading scene: {}", importer.GetErrorString());
60 return nullptr;
61 }
62
63 return std::unique_ptr<aiScene>(importer.GetOrphanedScene());
64}
65
66inline std::unique_ptr<aiScene> load_scene_assimp_from_memory(const void* buffer, size_t size)
67{
68 Assimp::Importer importer;
69
70 // Note: we are asking assimp to triangulate the scene for us.
71 // Change this after we add support for n-gons.
72 const aiScene* scene = importer.ReadFileFromMemory(buffer, size, aiProcess_Triangulate);
73
74 if (!scene) {
75 logger().error("Error loading scene: {}", importer.GetErrorString());
76 return nullptr;
77 }
78
79 return std::unique_ptr<aiScene>(importer.GetOrphanedScene());
80}
81
82template <typename MeshType,
83 std::enable_if_t<lagrange::MeshTraitHelper::is_mesh<MeshType>::value>* /* = nullptr */>
84std::vector<std::unique_ptr<MeshType>> load_mesh_assimp(const lagrange::fs::path& filename)
85{
86 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
87
88 std::unique_ptr<aiScene> scene = load_scene_assimp(filename);
89
90 return extract_meshes_assimp<MeshType>(scene.get());
91}
92
93template <typename MeshType>
94std::vector<std::unique_ptr<MeshType>> load_mesh_assimp_from_memory(const void* buffer, size_t size)
95{
96 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
97
98 std::unique_ptr<aiScene> scene = load_scene_assimp_from_memory(buffer, size);
99
100 return extract_meshes_assimp<MeshType>(scene.get());
101}
102
103template <typename MeshType>
104std::vector<std::unique_ptr<MeshType>> extract_meshes_assimp(const aiScene* scene)
105{
106 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
107 std::vector<std::unique_ptr<MeshType>> ret;
108 if (!scene) {
109 return ret;
110 }
111 for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
112 const aiMesh* mesh = scene->mMeshes[i];
113 ret.emplace_back(convert_mesh_assimp<MeshType>(mesh));
114 }
115 return ret;
116}
117
118template <typename MeshType>
119std::unique_ptr<MeshType> convert_mesh_assimp(const aiMesh* mesh)
120{
121 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
122
123 using VertexArray = typename MeshType::VertexArray;
124 using FacetArray = typename MeshType::FacetArray;
125
126 // Check that all facets have the same size
127 unsigned int nvpf = 0;
128 bool triangulate = false;
129 for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
130 const aiFace& face = mesh->mFaces[j];
131 if (nvpf == 0) {
132 nvpf = face.mNumIndices;
133 } else if (face.mNumIndices != nvpf) {
134 logger().warn("Facets with varying number of vertices detected, triangulating");
135 nvpf = 3;
136 triangulate = true;
137 break;
138 }
139 }
140 if (FacetArray::ColsAtCompileTime != Eigen::Dynamic && FacetArray::ColsAtCompileTime != nvpf) {
141 logger().warn(
142 "FacetArray cannot hold facets with n!={} vertex per facet, triangulating",
143 static_cast<int>(FacetArray::ColsAtCompileTime));
144 triangulate = true;
145 nvpf = 3;
146 }
147
148 // If triangulating a heterogeneous mesh, we need to count the number of facets
149 unsigned int num_output_facets = mesh->mNumFaces;
150 if (triangulate) {
151 num_output_facets = 0;
152 for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
153 const aiFace& face = mesh->mFaces[j];
154 num_output_facets += face.mNumIndices - 2;
155 }
156 }
157
158 VertexArray vertices(mesh->mNumVertices, 3); // should we support arbitrary dimension?
159 for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
160 const aiVector3D& vec = mesh->mVertices[j];
161 vertices(j, 0) = vec.x;
162 vertices(j, 1) = vec.y;
163 vertices(j, 2) = vec.z;
164 }
165
166 FacetArray faces(num_output_facets, nvpf);
167 for (unsigned int j = 0, f = 0; j < mesh->mNumFaces; ++j) {
168 const aiFace& face = mesh->mFaces[j];
169 if (triangulate) {
170 for (unsigned int k = 2; k < face.mNumIndices; ++k) {
171 faces.row(f++) << face.mIndices[0], face.mIndices[k - 1], face.mIndices[k];
172 }
173 } else {
174 for (unsigned int k = 0; k < face.mNumIndices; ++k) {
175 faces(j, k) = face.mIndices[k];
176 }
177 }
178 assert(f <= num_output_facets);
179 }
180
181 auto lagrange_mesh = create_mesh(std::move(vertices), std::move(faces));
182
183 if (mesh->HasTextureCoords(0)) {
184 typename MeshType::UVArray uvs(mesh->mNumVertices, 2);
185 typename MeshType::UVIndices uv_indices = lagrange_mesh->get_facets();
186
187 assert(mesh->GetNumUVChannels() == 1); // assume one UV channel
188 assert(mesh->mNumUVComponents[0] == 2); // assume two components (uv), not 3d uvw
189 for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
190 const aiVector3D& vec = mesh->mTextureCoords[0][j];
191 uvs(j, 0) = vec.x;
192 uvs(j, 1) = vec.y;
193 }
194
195 // uv indices are the same as facets
196
197 lagrange_mesh->initialize_uv(std::move(uvs), std::move(uv_indices));
198 map_indexed_attribute_to_corner_attribute(*lagrange_mesh, "uv");
199 }
200
201 return lagrange_mesh;
202}
203
204} // namespace legacy
205} // namespace lagrange::io
206
207#endif
Definition: Mesh.h:48
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:40
Mesh input/output.
Definition: detect_file_format.h:18
auto create_mesh(const Eigen::MatrixBase< DerivedV > &vertices, const Eigen::MatrixBase< DerivedF > &facets)
This function create a new mesh given the vertex and facet arrays by copying data into the Mesh objec...
Definition: create_mesh.h:39