18 #include "assimp/Importer.hpp"
19 #include "assimp/ProgressHandler.hpp"
20 #include "assimp/pbrmaterial.h"
21 #include "assimp/postprocess.h"
22 #include "assimp/scene.h"
25 #include "io/TriangleMeshIO.h"
29 #define AI_MATKEY_CLEARCOAT_THICKNESS "$mat.clearcoatthickness", 0, 0
30 #define AI_MATKEY_CLEARCOAT_ROUGHNESS "$mat.clearcoatroughness", 0, 0
31 #define AI_MATKEY_SHEEN "$mat.sheen", 0, 0
32 #define AI_MATKEY_ANISOTROPY "$mat.anisotropy", 0, 0
40 aiProcess_JoinIdenticalVertices | aiProcess_SortByPType |
41 aiProcess_PreTransformVertices;
45 aiProcess_Triangulate | aiProcess_GenUVCoords |
46 aiProcess_RemoveRedundantMaterials | aiProcess_OptimizeMeshes;
49 std::shared_ptr<geometry::Image>
albedo;
50 std::shared_ptr<geometry::Image>
normal;
51 std::shared_ptr<geometry::Image>
ao;
63 const aiMaterial* mat,
66 std::string base_path =
69 auto texture_loader = [&base_path, &scene, &mat, &
filename](
71 std::shared_ptr<geometry::Image>& img) {
72 if (mat->GetTextureCount(
type) > 0) {
77 if (
auto texture = scene->GetEmbeddedTexture(
path.C_Str())) {
78 if (texture->CheckFormat(
"png")) {
81 reinterpret_cast<const unsigned char*
>(
84 if (
image->HasData()) {
87 }
else if (texture->CheckFormat(
"jpg")) {
90 reinterpret_cast<const unsigned char*
>(
93 if (
image->HasData()) {
98 "Unsupported texture format for texture {} for "
99 "file {}: Only jpg and "
100 "png textures are supported.",
106 std::string strpath(
path.C_Str());
108 auto p_win = strpath.find(
"\\");
109 while (p_win != std::string::npos) {
110 strpath[p_win] =
'/';
111 p_win = strpath.find(
"\\", p_win + 1);
114 if (strpath.length() > 1 &&
115 (strpath[0] ==
'/' || strpath[1] ==
':')) {
120 if (
image->HasData()) {
128 if (mat->GetTextureCount(aiTextureType_BASE_COLOR) > 0) {
129 texture_loader(aiTextureType_BASE_COLOR, maps.
albedo);
131 texture_loader(aiTextureType_DIFFUSE, maps.
albedo);
133 texture_loader(aiTextureType_NORMALS, maps.
normal);
137 if (mat->GetTextureCount(aiTextureType_AMBIENT_OCCLUSION) > 0) {
138 texture_loader(aiTextureType_AMBIENT_OCCLUSION, maps.
ao);
140 texture_loader(aiTextureType_AMBIENT, maps.
ao);
142 texture_loader(aiTextureType_METALNESS, maps.
metallic);
143 if (mat->GetTextureCount(aiTextureType_DIFFUSE_ROUGHNESS) > 0) {
144 texture_loader(aiTextureType_DIFFUSE_ROUGHNESS, maps.
roughness);
145 }
else if (mat->GetTextureCount(aiTextureType_SHININESS) > 0) {
148 texture_loader(aiTextureType_SHININESS, maps.
roughness);
155 texture_loader(aiTextureType_REFLECTION, maps.
reflectance);
167 Assimp::Importer importer;
171 if (
params.enable_post_processing) {
175 const auto* scene = importer.ReadFile(
filename.c_str(), post_process_flags);
178 importer.GetErrorString());
183 if (scene->mNumMeshes > 0) {
184 const auto* assimp_mesh = scene->mMeshes[0];
187 mesh.CreateInternalCloud();
191 assimp_mesh->HasVertexColors(0),
192 assimp_mesh->HasNormals())) {
200 size_t current_vidx = 0;
202 for (
size_t midx = 0; midx < scene->mNumMeshes; ++midx) {
203 const auto* assimp_mesh = scene->mMeshes[midx];
205 if (assimp_mesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) {
207 "Skipping non-triangle primitive geometry of type: "
209 assimp_mesh->mPrimitiveTypes);
214 for (
size_t vidx = 0; vidx < assimp_mesh->mNumVertices; ++vidx) {
215 auto& vertex = assimp_mesh->mVertices[vidx];
216 mesh.
addVertice({vertex.x, vertex.y, vertex.z});
220 for (
size_t fidx = 0; fidx < assimp_mesh->mNumFaces; ++fidx) {
221 auto&
face = assimp_mesh->mFaces[fidx];
223 face.mIndices[0] +
static_cast<int>(current_vidx),
224 face.mIndices[1] +
static_cast<int>(current_vidx),
225 face.mIndices[2] +
static_cast<int>(current_vidx));
230 if (assimp_mesh->HasNormals()) {
231 for (
size_t nidx = 0; nidx < assimp_mesh->mNumVertices; ++nidx) {
232 auto&
normal = assimp_mesh->mNormals[nidx];
238 if (assimp_mesh->HasTextureCoords(0)) {
239 for (
size_t fidx = 0; fidx < assimp_mesh->mNumFaces; ++fidx) {
240 auto&
face = assimp_mesh->mFaces[fidx];
241 auto& uv1 = assimp_mesh->mTextureCoords[0][
face.mIndices[0]];
242 auto& uv2 = assimp_mesh->mTextureCoords[0][
face.mIndices[1]];
243 auto& uv3 = assimp_mesh->mTextureCoords[0][
face.mIndices[2]];
251 if (assimp_mesh->HasVertexColors(0)) {
252 for (
size_t cidx = 0; cidx < assimp_mesh->mNumVertices; ++cidx) {
253 auto& c = assimp_mesh->mColors[0][cidx];
259 current_vidx += assimp_mesh->mNumVertices;
264 for (
size_t i = 0; i < scene->mNumMaterials; ++i) {
265 auto* mat = scene->mMaterials[i];
268 auto& mesh_material = mesh.
materials_[i].second;
269 mesh.
materials_[i].first = mat->GetName().C_Str();
274 aiColor3D
color(1.f, 1.f, 1.f);
276 mat->Get(AI_MATKEY_COLOR_DIFFUSE,
color);
277 mesh_material.baseColor =
279 mat->Get(AI_MATKEY_METALLIC_FACTOR, mesh_material.baseMetallic);
280 mat->Get(AI_MATKEY_ROUGHNESS_FACTOR, mesh_material.baseRoughness);
283 mat->Get(AI_MATKEY_REFLECTIVITY, mesh_material.baseReflectance);
288 mesh_material.baseClearCoatRoughness);
294 mesh_material.albedo = maps.
albedo;
295 mesh_material.normalMap = maps.
normal;
296 mesh_material.ambientOcclusion = maps.
ao;
297 mesh_material.metallic = maps.
metallic;
298 mesh_material.roughness = maps.
roughness;
302 if (mesh_material.albedo) {
303 mesh.
textures_.emplace_back(*mesh_material.albedo->FlipVertical());
315 int64_t progress_total = 100;
316 float readfile_total = 70.0f;
317 float mesh_total = 10.0f;
318 float textures_total = 20.0f;
319 int64_t progress = 0;
322 class AssimpProgress :
public Assimp::ProgressHandler {
327 bool Update(
float percentage = -1.0f)
override {
328 if (params_.update_progress) {
329 params_.update_progress(
330 std::max(0.0f, 100.0f * scaling_ * percentage));
340 Assimp::Importer importer;
343 importer.SetProgressHandler(
344 new AssimpProgress(
params, readfile_total / progress_total));
349 importer.GetErrorString());
353 progress = int64_t(readfile_total);
354 reporter.
Update(progress);
357 for (
size_t midx = 0; midx < scene->mNumMeshes; ++midx) {
358 const auto* assimp_mesh = scene->mMeshes[midx];
360 if (!(assimp_mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) {
362 "Skipping non-triangle primitive geometry of type: "
364 assimp_mesh->mPrimitiveTypes);
369 assert(baseVertices);
370 auto mesh = std::make_shared<ccMesh>(baseVertices);
374 "[reserveThePointsTable] Not have enough memory! ");
377 if (assimp_mesh->mNormals) {
380 "[reserveTheNormsTable] Not have enough memory! ");
384 if (assimp_mesh->HasVertexColors(0)) {
387 "[reserveTheRGBTable] Not have enough memory! ");
393 for (
size_t vidx = 0; vidx < assimp_mesh->mNumVertices; ++vidx) {
394 auto& vertex = assimp_mesh->mVertices[vidx];
399 for (
size_t fidx = 0; fidx < assimp_mesh->mNumFaces; ++fidx) {
400 auto&
face = assimp_mesh->mFaces[fidx];
403 mesh->addTriangle(facet);
406 if (assimp_mesh->mNormals) {
407 for (
size_t nidx = 0; nidx < assimp_mesh->mNumVertices; ++nidx) {
408 auto&
normal = assimp_mesh->mNormals[nidx];
414 if (assimp_mesh->HasTextureCoords(0)) {
415 for (
size_t fidx = 0; fidx < assimp_mesh->mNumFaces; ++fidx) {
416 auto&
face = assimp_mesh->mFaces[fidx];
417 auto& uv1 = assimp_mesh->mTextureCoords[0][
face.mIndices[0]];
418 auto& uv2 = assimp_mesh->mTextureCoords[0][
face.mIndices[1]];
419 auto& uv3 = assimp_mesh->mTextureCoords[0][
face.mIndices[2]];
420 mesh->triangle_uvs_.push_back(Eigen::Vector2d(uv1.x, uv1.y));
421 mesh->triangle_uvs_.push_back(Eigen::Vector2d(uv2.x, uv2.y));
422 mesh->triangle_uvs_.push_back(Eigen::Vector2d(uv3.x, uv3.y));
427 if (assimp_mesh->HasVertexColors(0)) {
428 for (
size_t cidx = 0; cidx < assimp_mesh->mNumVertices; ++cidx) {
429 auto& c = assimp_mesh->mColors[0][cidx];
447 mesh->addChild(baseVertices);
450 model.
meshes_.push_back({mesh, std::string(assimp_mesh->mName.C_Str()),
451 assimp_mesh->mMaterialIndex});
454 progress = int64_t(readfile_total + mesh_total);
455 reporter.
Update(progress);
458 for (
size_t i = 0; i < scene->mNumMaterials; ++i) {
459 auto* mat = scene->mMaterials[i];
463 cv3d_mat.
name = mat->GetName().C_Str();
466 aiColor3D
color(1.f, 1.f, 1.f);
468 mat->Get(AI_MATKEY_COLOR_DIFFUSE,
color);
477 mat->Get(AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR,
480 mat->Get(AI_MATKEY_COLOR_EMISSIVE,
color);
484 mat->Get(AI_MATKEY_GLTF_ALPHAMODE, alpha_mode);
485 std::string alpha_mode_str(alpha_mode.C_Str());
486 if (alpha_mode_str ==
"BLEND" || alpha_mode_str ==
"MASK") {
502 cv3d_mat.
shader =
"defaultLitTransparency";
504 cv3d_mat.
shader =
"defaultLit";
509 progress = int64_t(readfile_total + mesh_total +
510 textures_total *
float(i + 1) /
511 float(scene->mNumMaterials));
512 reporter.
Update(progress);
515 reporter.
Update(progress_total);
std::shared_ptr< core::Tensor > image
cmdLineReadable * params[]
Array of compressed 3D normals (single index)
std::vector< int > triangle_material_ids_
List of material ids.
void addVertice(const Eigen::Vector3d &vertice)
std::vector< Eigen::Vector2d > triangle_uvs_
List of uv coordinates per triangle.
ccGenericPointCloud * getAssociatedCloud() const override
Returns the vertices cloud.
void addVertexNormal(const Eigen::Vector3d &normal)
void addTriangle(unsigned i1, unsigned i2, unsigned i3)
Adds a triangle to the mesh.
bool reserveAssociatedCloud(std::size_t n, bool init_color=false, bool init_normal=false)
std::vector< cloudViewer::geometry::Image > textures_
Textures of the image.
std::vector< std::pair< std::string, Material > > materials_
void addVertexColor(const Eigen::Vector3d &color)
virtual void setLocked(bool state)
Sets the "enabled" property.
virtual void setEnabled(bool state)
Sets the "enabled" property.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void addEigenNorm(const Eigen::Vector3d &N)
void addEigenColor(const Eigen::Vector3d &color)
bool reserveTheNormsTable()
Reserves memory to store the compressed normals.
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
void shrinkToFit()
Removes unused capacity.
bool reserveThePointsTable(unsigned _numberOfPoints)
Reserves memory to store the points coordinates.
void addEigenPoint(const Eigen::Vector3d &point)
void SetTotal(int64_t total)
bool Update(int64_t count)
std::vector< unsigned int > face
std::shared_ptr< geometry::Image > CreateImageFromMemory(const std::string &image_format, const unsigned char *image_data_ptr, size_t image_data_size)
Factory function to create an image from memory.
const unsigned int kPostProcessFlags_compulsory
bool ReadModelUsingAssimp(const std::string &filename, visualization::rendering::TriangleMeshModel &model, const ReadTriangleModelOptions ¶ms)
std::shared_ptr< geometry::Image > CreateImageFromFile(const std::string &filename)
const unsigned int kPostProcessFlags_fast
bool ReadTriangleMeshUsingASSIMP(const std::string &filename, ccMesh &mesh, const ReadTriangleMeshOptions ¶ms)
void LoadTextures(const std::string &filename, const aiScene *scene, const aiMaterial *mat, TextureImages &maps)
static const std::string path
std::string GetFileParentDirectory(const std::string &filename)
std::string GetFileNameWithoutDirectory(const std::string &filename)
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 3, 1 > Vector3i
std::shared_ptr< geometry::Image > anisotropy
std::shared_ptr< geometry::Image > clearcoat
std::shared_ptr< geometry::Image > roughness
std::shared_ptr< geometry::Image > reflectance
std::shared_ptr< geometry::Image > clearcoat_roughness
std::shared_ptr< geometry::Image > normal
std::shared_ptr< geometry::Image > metallic
std::shared_ptr< geometry::Image > albedo
std::shared_ptr< geometry::Image > gltf_rough_metal
std::shared_ptr< geometry::Image > ao
std::shared_ptr< geometry::Image > normal_img
std::shared_ptr< geometry::Image > albedo_img
std::shared_ptr< geometry::Image > ao_rough_metal_img
std::shared_ptr< geometry::Image > ao_img
float base_clearcoat_roughness
std::shared_ptr< geometry::Image > metallic_img
Eigen::Vector4f emissive_color
std::shared_ptr< geometry::Image > roughness_img
std::shared_ptr< geometry::Image > reflectance_img
Eigen::Vector4f base_color
std::vector< MeshInfo > meshes_
std::vector< visualization::rendering::MaterialRecord > materials_