Lagrange
Loading...
Searching...
No Matches
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/Logger.h>
17 #include <lagrange/MeshTrait.h>
18 #include <lagrange/attributes/attribute_utils.h>
19 #include <lagrange/create_mesh.h>
20 #include <lagrange/fs/file_utils.h>
21 #include <lagrange/fs/filesystem.h>
22 #include <lagrange/legacy/inline.h>
23
24 #include <assimp/material.h>
25 #include <assimp/mesh.h>
26 #include <assimp/postprocess.h>
27 #include <assimp/scene.h>
28 #include <assimp/Importer.hpp>
29
30 #include <iostream>
31 #include <string>
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 <
42 typename MeshType,
43 std::enable_if_t<lagrange::MeshTraitHelper::is_mesh<MeshType>::value>* = nullptr>
44std::vector<std::unique_ptr<MeshType>> load_mesh_assimp(const lagrange::fs::path& filename);
45template <typename MeshType>
46std::vector<std::unique_ptr<MeshType>> load_mesh_assimp_from_memory(
47 const void* buffer,
48 size_t size);
49
50template <typename MeshType>
51std::vector<std::unique_ptr<MeshType>> extract_meshes_assimp(const aiScene* scene);
52template <typename MeshType>
53std::unique_ptr<MeshType> convert_mesh_assimp(const aiMesh* mesh);
54
55inline std::unique_ptr<aiScene> load_scene_assimp(const lagrange::fs::path& filename)
56{
57 Assimp::Importer importer;
58 const aiScene* scene = importer.ReadFile(filename.string(), 0);
59 if (!scene) {
60 logger().error("Error loading scene: {}", importer.GetErrorString());
61 return nullptr;
62 }
63
64 return std::unique_ptr<aiScene>(importer.GetOrphanedScene());
65}
66
67inline std::unique_ptr<aiScene> load_scene_assimp_from_memory(const void* buffer, size_t size)
68{
69 Assimp::Importer importer;
70
71 // Note: we are asking assimp to triangulate the scene for us.
72 // Change this after we add support for n-gons.
73 const aiScene* scene = importer.ReadFileFromMemory(buffer, size, aiProcess_Triangulate);
74
75 if (!scene) {
76 logger().error("Error loading scene: {}", importer.GetErrorString());
77 return nullptr;
78 }
79
80 return std::unique_ptr<aiScene>(importer.GetOrphanedScene());
81}
82
83template <
84 typename MeshType,
85 std::enable_if_t<lagrange::MeshTraitHelper::is_mesh<MeshType>::value>* /* = nullptr */>
86std::vector<std::unique_ptr<MeshType>> load_mesh_assimp(const lagrange::fs::path& filename)
87{
88 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
89
90 std::unique_ptr<aiScene> scene = load_scene_assimp(filename);
91
92 return extract_meshes_assimp<MeshType>(scene.get());
93}
94
95template <typename MeshType>
96std::vector<std::unique_ptr<MeshType>> load_mesh_assimp_from_memory(const void* buffer, size_t size)
97{
98 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
99
100 std::unique_ptr<aiScene> scene = load_scene_assimp_from_memory(buffer, size);
101
102 return extract_meshes_assimp<MeshType>(scene.get());
103}
104
105template <typename MeshType>
106std::vector<std::unique_ptr<MeshType>> extract_meshes_assimp(const aiScene* scene)
107{
108 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
109 std::vector<std::unique_ptr<MeshType>> ret;
110 if (!scene) {
111 return ret;
112 }
113 for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
114 const aiMesh* mesh = scene->mMeshes[i];
115 ret.emplace_back(convert_mesh_assimp<MeshType>(mesh));
116 }
117 return ret;
118}
119
120template <typename MeshType>
121std::unique_ptr<MeshType> convert_mesh_assimp(const aiMesh* mesh)
122{
123 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
124
125 using VertexArray = typename MeshType::VertexArray;
126 using FacetArray = typename MeshType::FacetArray;
127
128 // Check that all facets have the same size
129 unsigned int nvpf = 0;
130 bool triangulate = false;
131 for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
132 const aiFace& face = mesh->mFaces[j];
133 if (nvpf == 0) {
134 nvpf = face.mNumIndices;
135 } else if (face.mNumIndices != nvpf) {
136 logger().warn("Facets with varying number of vertices detected, triangulating");
137 nvpf = 3;
138 triangulate = true;
139 break;
140 }
141 }
142 if (FacetArray::ColsAtCompileTime != Eigen::Dynamic && FacetArray::ColsAtCompileTime != nvpf) {
143 logger().warn(
144 "FacetArray cannot hold facets with n!={} vertex per facet, triangulating",
145 static_cast<int>(FacetArray::ColsAtCompileTime));
146 triangulate = true;
147 nvpf = 3;
148 }
149
150 // If triangulating a heterogeneous mesh, we need to count the number of facets
151 unsigned int num_output_facets = mesh->mNumFaces;
152 if (triangulate) {
153 num_output_facets = 0;
154 for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
155 const aiFace& face = mesh->mFaces[j];
156 num_output_facets += face.mNumIndices - 2;
157 }
158 }
159
160 VertexArray vertices(mesh->mNumVertices, 3); // should we support arbitrary dimension?
161 for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
162 const aiVector3D& vec = mesh->mVertices[j];
163 vertices(j, 0) = vec.x;
164 vertices(j, 1) = vec.y;
165 vertices(j, 2) = vec.z;
166 }
167
168 FacetArray faces(num_output_facets, nvpf);
169 for (unsigned int j = 0, f = 0; j < mesh->mNumFaces; ++j) {
170 const aiFace& face = mesh->mFaces[j];
171 if (triangulate) {
172 for (unsigned int k = 2; k < face.mNumIndices; ++k) {
173 faces.row(f++) << face.mIndices[0], face.mIndices[k - 1], face.mIndices[k];
174 }
175 } else {
176 for (unsigned int k = 0; k < face.mNumIndices; ++k) {
177 faces(j, k) = face.mIndices[k];
178 }
179 }
180 assert(f <= num_output_facets);
181 }
182
183 auto lagrange_mesh = create_mesh(std::move(vertices), std::move(faces));
184
185 if (mesh->HasTextureCoords(0)) {
186 typename MeshType::UVArray uvs(mesh->mNumVertices, 2);
187 typename MeshType::UVIndices uv_indices = lagrange_mesh->get_facets();
188
189 assert(mesh->GetNumUVChannels() == 1); // assume one UV channel
190 assert(mesh->mNumUVComponents[0] == 2); // assume two components (uv), not 3d uvw
191 for (unsigned int j = 0; j < mesh->mNumVertices; ++j) {
192 const aiVector3D& vec = mesh->mTextureCoords[0][j];
193 uvs(j, 0) = vec.x;
194 uvs(j, 1) = vec.y;
195 }
196
197 // uv indices are the same as facets
198
199 lagrange_mesh->initialize_uv(std::move(uvs), std::move(uv_indices));
200 map_indexed_attribute_to_corner_attribute(*lagrange_mesh, "uv");
201 }
202
203 return lagrange_mesh;
204}
205
206} // namespace legacy
207} // namespace lagrange::io
208
209#endif
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