Lagrange
io_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#include <lagrange/create_mesh.h>
15#include <lagrange/ui/api.h>
16#include <lagrange/ui/Entity.h>
17#include <lagrange/ui/components/MeshData.h>
18#include <lagrange/ui/types/Texture.h>
19#include <lagrange/ui/utils/mesh.h>
20
21#ifdef LAGRANGE_WITH_ASSIMP
22
23#include <assimp/material.h>
24#include <assimp/mesh.h>
25#include <assimp/postprocess.h>
26#include <assimp/scene.h>
27#include <assimp/Importer.hpp>
28
29
30namespace lagrange {
31namespace ui {
32
33namespace detail {
34
35// TODO move to IO module
36template <typename MeshType>
37std::vector<Entity> load_meshes(Registry& r, const aiScene* scene)
38{
39 using VertexArray = typename MeshType::VertexArray;
40 using FacetArray = typename MeshType::FacetArray;
41 using AttribArray = typename MeshType::AttributeArray;
42
43 std::vector<Entity> meshes;
44
45 for (unsigned int i = 0; i < scene->mNumMeshes; i++) {
46 const auto* amesh = scene->mMeshes[i];
47
48 if (amesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) {
49 VertexArray vertices(amesh->mNumVertices, 3); // Triangulated input
50 FacetArray faces(amesh->mNumFaces, 3);
51
52 for (unsigned int j = 0; j < amesh->mNumVertices; ++j) {
53 const aiVector3D& vec = amesh->mVertices[j];
54 vertices(j, 0) = vec.x;
55 vertices(j, 1) = vec.y;
56 vertices(j, 2) = vec.z;
57 }
58 for (unsigned int j = 0; j < amesh->mNumFaces; ++j) {
59 const aiFace& face = amesh->mFaces[j];
60 assert(face.mNumIndices == 3);
61 for (unsigned int k = 0; k < face.mNumIndices; ++k) {
62 faces(j, k) = face.mIndices[k];
63 }
64 }
65
66 auto lgmesh = lagrange::create_mesh(std::move(vertices), std::move(faces));
67
68 if (amesh->HasTextureCoords(0)) {
69 typename MeshType::UVArray uvs(amesh->mNumVertices, 2);
70 typename MeshType::UVIndices uv_indices = lgmesh->get_facets();
71
72 assert(amesh->GetNumUVChannels() == 1); // assume one UV channel
73 //assert(amesh->mNumUVComponents[0] == 2); // assume two components (uv), not 3d uvw
74 for (unsigned int j = 0; j < amesh->mNumVertices; ++j) {
75 const aiVector3D& vec = amesh->mTextureCoords[0][j];
76 uvs(j, 0) = vec.x;
77 uvs(j, 1) = vec.y;
78 }
79
80 // uv indices are the same as facets
81 lgmesh->initialize_uv(std::move(uvs), std::move(uv_indices));
82 map_indexed_attribute_to_corner_attribute(*lgmesh, "uv");
83 }
84
85
86 // TODO bones
87 if (amesh->HasBones()) {
88 }
89
90 if (amesh->HasTangentsAndBitangents()) {
91 AttribArray tangents(amesh->mNumVertices, 3);
92 AttribArray bitangents(amesh->mNumVertices, 3);
93
94 for (unsigned int j = 0; j < amesh->mNumVertices; ++j) {
95 const aiVector3D& t = amesh->mTangents[j];
96 tangents(j, 0) = t.x;
97 tangents(j, 1) = t.y;
98 tangents(j, 2) = t.z;
99
100 const aiVector3D& bt = amesh->mBitangents[j];
101 bitangents(j, 0) = bt.x;
102 bitangents(j, 1) = bt.y;
103 bitangents(j, 2) = bt.z;
104 }
105
106 lgmesh->add_vertex_attribute("tangent");
107 lgmesh->add_vertex_attribute("bitangent");
108 lgmesh->import_vertex_attribute("tangent", tangents);
109 lgmesh->import_vertex_attribute("bitangent", bitangents);
110 }
111
112 if (amesh->HasNormals()) {
113 AttribArray normals(amesh->mNumVertices, 3);
114 for (unsigned int j = 0; j < amesh->mNumVertices; ++j) {
115 const aiVector3D& t = amesh->mNormals[j];
116 normals(j, 0) = t.x;
117 normals(j, 1) = t.y;
118 normals(j, 2) = t.z;
119 }
120 lgmesh->add_vertex_attribute("normal");
121 lgmesh->import_vertex_attribute("normal", normals);
122 }
123 meshes.push_back(register_mesh(r, std::move(lgmesh)));
124 } else if (amesh->mPrimitiveTypes & aiPrimitiveType_POINT) {
125 lagrange::logger().error("Point clouds not supported yet!");
126 meshes.push_back(NullEntity);
127 }
128 }
129
130 return meshes;
131}
132
133Entity load_scene_impl(
134 Registry& r,
135 const aiScene* scene,
136 const fs::path& parent_path,
137 const std::vector<Entity>& meshes);
138
139} // namespace detail
140
141
142template <typename MeshType>
143Entity load_scene(
144 Registry& r,
145 const fs::path& path,
146 unsigned int assimp_flags = aiProcess_JoinIdenticalVertices | aiProcess_CalcTangentSpace |
147 aiProcess_Triangulate | aiProcess_GenUVCoords)
148{
149 Assimp::Importer importer;
150
151 try {
152 const aiScene* scene = importer.ReadFile(
153 path.string(),
154 assimp_flags | aiProcess_Triangulate // Always triangulate
155 );
156
157 if (!scene) {
158 logger().error("Error loading scene: {}", importer.GetErrorString());
159 return NullEntity;
160 }
161
162 } catch (const std::exception& ex) {
163 lagrange::logger().error("Exception in load_scene: {}", ex.what());
164 return NullEntity;
165 }
166
167 std::unique_ptr<aiScene> ptr(importer.GetOrphanedScene());
168
169 return detail::load_scene_impl(r, ptr.get(), path, detail::load_meshes<MeshType>(r, ptr.get()));
170}
171
172
173} // namespace ui
174} // namespace lagrange
175
176#endif
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:40
SceneType load_scene(const fs::path &filename, const LoadOptions &options={})
Load a scene.
Definition: load_scene.cpp:33
Lagrange UI Viewer and mini 3D engine.
Definition: AcceleratedPicking.h:22
Main namespace for Lagrange.
Definition: AABBIGL.h:30
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