mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-09 10:16:50 +00:00
assimp
This commit is contained in:
40
deps/Assimp/Assimp.cmake
vendored
Normal file
40
deps/Assimp/Assimp.cmake
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
if(CMAKE_VERSION VERSION_LESS 3.22)
|
||||||
|
set(_assimp_url "https://github.com/assimp/assimp/archive/refs/tags/v5.3.1.tar.gz")
|
||||||
|
set(_assimp_hash "SHA256=a07666be71afe1ad4bc008c2336b7c688aca391271188eb9108d0c6db1be53f1")
|
||||||
|
else()
|
||||||
|
set(_assimp_url "https://github.com/assimp/assimp/archive/refs/tags/v5.4.3.tar.gz")
|
||||||
|
set(_assimp_hash "SHA256=66dfbaee288f2bc43172440a55d0235dfc7bf885dda6435c038e8000e79582cb")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Assimp's bundled zlib (contrib/zlib) is too old to compile against the modern
|
||||||
|
# macOS SDK: its zutil.h takes the classic-Mac branch under TARGET_OS_MAC and
|
||||||
|
# does `#define fdopen(fd,mode) NULL`, which then clobbers the SDK's real
|
||||||
|
# `fdopen` prototype in <stdio.h> and breaks the build. On macOS use the system
|
||||||
|
# zlib (already found by find_package(ZLIB) in deps-unix-common) instead.
|
||||||
|
if(APPLE)
|
||||||
|
set(_assimp_build_zlib "-DASSIMP_BUILD_ZLIB=OFF")
|
||||||
|
else()
|
||||||
|
set(_assimp_build_zlib "-DASSIMP_BUILD_ZLIB=ON")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
orcaslicer_add_cmake_project(Assimp
|
||||||
|
URL ${_assimp_url}
|
||||||
|
URL_HASH ${_assimp_hash}
|
||||||
|
CMAKE_ARGS
|
||||||
|
-DASSIMP_BUILD_TESTS=OFF
|
||||||
|
-DASSIMP_BUILD_SAMPLES=OFF
|
||||||
|
-DASSIMP_BUILD_ASSIMP_TOOLS=OFF
|
||||||
|
-DASSIMP_INSTALL_PDB=OFF
|
||||||
|
-DASSIMP_NO_EXPORT=ON
|
||||||
|
-DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=OFF
|
||||||
|
-DASSIMP_BUILD_GLTF_IMPORTER=ON
|
||||||
|
-DASSIMP_BUILD_OBJ_IMPORTER=ON
|
||||||
|
-DASSIMP_BUILD_FBX_IMPORTER=ON
|
||||||
|
${_assimp_build_zlib}
|
||||||
|
-DASSIMP_WARNINGS_AS_ERRORS=OFF
|
||||||
|
-DBUILD_WITH_STATIC_CRT=OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
add_debug_dep(dep_Assimp)
|
||||||
|
endif ()
|
||||||
4
deps/CMakeLists.txt
vendored
4
deps/CMakeLists.txt
vendored
@@ -367,6 +367,9 @@ include(libnoise/libnoise.cmake)
|
|||||||
|
|
||||||
include(Draco/Draco.cmake)
|
include(Draco/Draco.cmake)
|
||||||
|
|
||||||
|
# Assimp: glTF/GLB/FBX import for the texture-to-color feature.
|
||||||
|
include(Assimp/Assimp.cmake)
|
||||||
|
|
||||||
|
|
||||||
# I *think* 1.1 is used for *just* md5 hashing?
|
# I *think* 1.1 is used for *just* md5 hashing?
|
||||||
# 3.1 has everything in the right place, but the md5 funcs used are deprecated
|
# 3.1 has everything in the right place, but the md5 funcs used are deprecated
|
||||||
@@ -448,6 +451,7 @@ set(_dep_list
|
|||||||
dep_libnoise
|
dep_libnoise
|
||||||
dep_python3
|
dep_python3
|
||||||
dep_wxInspector
|
dep_wxInspector
|
||||||
|
dep_Assimp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|||||||
@@ -205,6 +205,8 @@ set(lisbslic3r_sources
|
|||||||
format.hpp
|
format.hpp
|
||||||
Format/OBJ.cpp
|
Format/OBJ.cpp
|
||||||
Format/OBJ.hpp
|
Format/OBJ.hpp
|
||||||
|
Format/AssimpImport.hpp
|
||||||
|
Format/AssimpImport.cpp
|
||||||
Format/ResourcePathUtils.hpp
|
Format/ResourcePathUtils.hpp
|
||||||
Format/objparser.cpp
|
Format/objparser.cpp
|
||||||
Format/objparser.hpp
|
Format/objparser.hpp
|
||||||
@@ -521,6 +523,7 @@ cmake_policy(SET CMP0011 NEW)
|
|||||||
set(CMAKE_POLICY_DEFAULT_CMP0167 NEW)
|
set(CMAKE_POLICY_DEFAULT_CMP0167 NEW)
|
||||||
find_package(CGAL REQUIRED)
|
find_package(CGAL REQUIRED)
|
||||||
find_package(OpenCV REQUIRED core)
|
find_package(OpenCV REQUIRED core)
|
||||||
|
find_package(assimp REQUIRED)
|
||||||
unset(CMAKE_POLICY_DEFAULT_CMP0167)
|
unset(CMAKE_POLICY_DEFAULT_CMP0167)
|
||||||
cmake_policy(POP)
|
cmake_policy(POP)
|
||||||
|
|
||||||
@@ -609,6 +612,7 @@ target_link_libraries(libslic3r
|
|||||||
libnest2d
|
libnest2d
|
||||||
miniz
|
miniz
|
||||||
opencv_world
|
opencv_world
|
||||||
|
assimp::assimp
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CMAKE_DL_LIBS}
|
${CMAKE_DL_LIBS}
|
||||||
${EXPAT_LIBRARIES}
|
${EXPAT_LIBRARIES}
|
||||||
|
|||||||
327
src/libslic3r/Format/AssimpImport.cpp
Normal file
327
src/libslic3r/Format/AssimpImport.cpp
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
#include "AssimpImport.hpp"
|
||||||
|
|
||||||
|
#include "../TexturePainting.hpp"
|
||||||
|
#include "ResourcePathUtils.hpp"
|
||||||
|
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
#include <assimp/config.h>
|
||||||
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/postprocess.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <boost/nowide/fstream.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void clear_textured_mesh(TexturedMesh& out)
|
||||||
|
{
|
||||||
|
out.vertices.clear();
|
||||||
|
out.indices.clear();
|
||||||
|
out.uvs.clear();
|
||||||
|
out.uv_coords.clear();
|
||||||
|
out.uv_indices.clear();
|
||||||
|
out.textures.clear();
|
||||||
|
out.material_ids.clear();
|
||||||
|
out.material_texture_map.clear();
|
||||||
|
out.material_colors.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_error_message(std::string* error_message, const std::string& message)
|
||||||
|
{
|
||||||
|
if (error_message)
|
||||||
|
*error_message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_fbx_path(const std::string& path)
|
||||||
|
{
|
||||||
|
return boost::algorithm::iends_with(path, ".fbx");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool should_flip_uvs(const std::string& path)
|
||||||
|
{
|
||||||
|
return boost::algorithm::iends_with(path, ".fbx") ||
|
||||||
|
boost::algorithm::iends_with(path, ".glb");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int assimp_import_flags(const std::string& path)
|
||||||
|
{
|
||||||
|
unsigned int flags = aiProcess_Triangulate
|
||||||
|
| aiProcess_GenNormals
|
||||||
|
| aiProcess_PreTransformVertices
|
||||||
|
| aiProcess_SortByPType;
|
||||||
|
if (should_flip_uvs(path))
|
||||||
|
flags |= aiProcess_FlipUVs;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void configure_importer(Assimp::Importer& importer, const std::string& path, unsigned int flags)
|
||||||
|
{
|
||||||
|
importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,
|
||||||
|
aiPrimitiveType_POINT | aiPrimitiveType_LINE);
|
||||||
|
|
||||||
|
if (flags & aiProcess_PreTransformVertices)
|
||||||
|
importer.SetPropertyBool(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, true);
|
||||||
|
|
||||||
|
if (is_fbx_path(path)) {
|
||||||
|
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||||
|
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||||
|
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||||
|
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, false);
|
||||||
|
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, false);
|
||||||
|
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_external_texture_file(const boost::filesystem::path& path, TextureImage& out)
|
||||||
|
{
|
||||||
|
boost::nowide::ifstream file(path.string(), std::ios::binary | std::ios::ate);
|
||||||
|
if (!file.is_open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const std::streamoff size = file.tellg();
|
||||||
|
if (size <= 0)
|
||||||
|
return false;
|
||||||
|
if (static_cast<uintmax_t>(size) > static_cast<uintmax_t>(std::numeric_limits<size_t>::max()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
file.seekg(0);
|
||||||
|
out.width = -1;
|
||||||
|
out.height = -1;
|
||||||
|
out.channels = 0;
|
||||||
|
out.data.resize(static_cast<size_t>(size));
|
||||||
|
file.read(reinterpret_cast<char*>(out.data.data()), size);
|
||||||
|
if (!file && !file.eof()) {
|
||||||
|
out.data.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_embedded_texture(const aiTexture& texture, TextureImage& out)
|
||||||
|
{
|
||||||
|
out.data.clear();
|
||||||
|
if (texture.mHeight == 0) {
|
||||||
|
if (texture.mWidth == 0)
|
||||||
|
return false;
|
||||||
|
out.width = -1;
|
||||||
|
out.height = -1;
|
||||||
|
out.channels = 0;
|
||||||
|
out.data.assign(
|
||||||
|
reinterpret_cast<const unsigned char*>(texture.pcData),
|
||||||
|
reinterpret_cast<const unsigned char*>(texture.pcData) + texture.mWidth);
|
||||||
|
return !out.data.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture.mWidth == 0 || texture.mHeight == 0)
|
||||||
|
return false;
|
||||||
|
if (texture.mWidth > static_cast<unsigned int>(std::numeric_limits<int>::max()) ||
|
||||||
|
texture.mHeight > static_cast<unsigned int>(std::numeric_limits<int>::max())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const size_t width = static_cast<size_t>(texture.mWidth);
|
||||||
|
const size_t height = static_cast<size_t>(texture.mHeight);
|
||||||
|
if (width > std::numeric_limits<size_t>::max() / height ||
|
||||||
|
width * height > std::numeric_limits<size_t>::max() / 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.width = static_cast<int>(texture.mWidth);
|
||||||
|
out.height = static_cast<int>(texture.mHeight);
|
||||||
|
out.channels = 4;
|
||||||
|
const size_t pixel_count = width * height;
|
||||||
|
out.data.resize(pixel_count * 4);
|
||||||
|
for (size_t i = 0; i < pixel_count; ++i) {
|
||||||
|
const aiTexel& texel = texture.pcData[i];
|
||||||
|
out.data[i * 4 + 0] = texel.r;
|
||||||
|
out.data[i * 4 + 1] = texel.g;
|
||||||
|
out.data[i * 4 + 2] = texel.b;
|
||||||
|
out.data[i * 4 + 3] = texel.a;
|
||||||
|
}
|
||||||
|
return !out.data.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_material_texture(const aiMaterial& material, aiString& texture_path)
|
||||||
|
{
|
||||||
|
if (material.GetTextureCount(aiTextureType_DIFFUSE) > 0 &&
|
||||||
|
material.GetTexture(aiTextureType_DIFFUSE, 0, &texture_path) == AI_SUCCESS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (material.GetTextureCount(aiTextureType_BASE_COLOR) > 0 &&
|
||||||
|
material.GetTexture(aiTextureType_BASE_COLOR, 0, &texture_path) == AI_SUCCESS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<float, 4> get_material_color(const aiMaterial& material)
|
||||||
|
{
|
||||||
|
aiColor4D color(1.f, 1.f, 1.f, 1.f);
|
||||||
|
if (material.Get(AI_MATKEY_BASE_COLOR, color) == AI_SUCCESS)
|
||||||
|
return {color.r, color.g, color.b, color.a};
|
||||||
|
if (material.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS)
|
||||||
|
return {color.r, color.g, color.b, color.a};
|
||||||
|
return {1.f, 1.f, 1.f, 1.f};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool collect_mesh(const aiMesh& mesh, size_t& vertex_offset, TexturedMesh& out, std::string& error)
|
||||||
|
{
|
||||||
|
if (mesh.mNumVertices > static_cast<size_t>(std::numeric_limits<int>::max()) - vertex_offset) {
|
||||||
|
error = "Assimp mesh has too many vertices for TexturedMesh indices";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||||
|
const aiVector3D& v = mesh.mVertices[i];
|
||||||
|
out.vertices.push_back({v.x, v.y, v.z});
|
||||||
|
|
||||||
|
if (mesh.HasTextureCoords(0)) {
|
||||||
|
const aiVector3D& uv = mesh.mTextureCoords[0][i];
|
||||||
|
out.uvs.push_back({uv.x, uv.y});
|
||||||
|
} else {
|
||||||
|
out.uvs.push_back({0.f, 0.f});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int material_index = static_cast<int>(mesh.mMaterialIndex);
|
||||||
|
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||||
|
const aiFace& face = mesh.mFaces[i];
|
||||||
|
if (face.mNumIndices != 3)
|
||||||
|
continue;
|
||||||
|
if (face.mIndices[0] >= mesh.mNumVertices ||
|
||||||
|
face.mIndices[1] >= mesh.mNumVertices ||
|
||||||
|
face.mIndices[2] >= mesh.mNumVertices) {
|
||||||
|
error = "Assimp mesh face index is out of bounds";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out.indices.push_back({
|
||||||
|
static_cast<int>(static_cast<size_t>(face.mIndices[0]) + vertex_offset),
|
||||||
|
static_cast<int>(static_cast<size_t>(face.mIndices[1]) + vertex_offset),
|
||||||
|
static_cast<int>(static_cast<size_t>(face.mIndices[2]) + vertex_offset)});
|
||||||
|
out.material_ids.push_back(material_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex_offset += mesh.mNumVertices;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void collect_materials(const aiScene& scene, const boost::filesystem::path& base_dir, TexturedMesh& out)
|
||||||
|
{
|
||||||
|
out.material_texture_map.assign(scene.mNumMaterials, -1);
|
||||||
|
out.material_colors.assign(scene.mNumMaterials, {1.f, 1.f, 1.f, 1.f});
|
||||||
|
|
||||||
|
for (unsigned int material_index = 0; material_index < scene.mNumMaterials; ++material_index) {
|
||||||
|
const aiMaterial* material = scene.mMaterials[material_index];
|
||||||
|
if (!material)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
out.material_colors[material_index] = get_material_color(*material);
|
||||||
|
|
||||||
|
aiString texture_path;
|
||||||
|
if (!get_material_texture(*material, texture_path))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TextureImage image;
|
||||||
|
const aiTexture* embedded_texture = scene.GetEmbeddedTexture(texture_path.C_Str());
|
||||||
|
if (embedded_texture) {
|
||||||
|
if (!read_embedded_texture(*embedded_texture, image))
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
const boost::filesystem::path resolved = resource_path::resolve_external_resource_path(
|
||||||
|
base_dir, texture_path.C_Str(), "Assimp texture");
|
||||||
|
if (resolved.empty()) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "AssimpImport: texture file not found: "
|
||||||
|
<< texture_path.C_Str();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!read_external_texture_file(resolved, image)) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "AssimpImport: failed to read texture: "
|
||||||
|
<< resolved;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.material_texture_map[material_index] = static_cast<int>(out.textures.size());
|
||||||
|
out.textures.push_back(std::move(image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string scene_failure_summary(const std::string& path, const char* assimp_error)
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "Assimp failed to import " << path;
|
||||||
|
if (assimp_error && assimp_error[0] != '\0')
|
||||||
|
ss << ": " << assimp_error;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool load_assimp_textured_model(const std::string& path, TexturedMesh& out, std::string* error_message)
|
||||||
|
{
|
||||||
|
clear_textured_mesh(out);
|
||||||
|
|
||||||
|
Assimp::Importer importer;
|
||||||
|
const unsigned int flags = assimp_import_flags(path);
|
||||||
|
configure_importer(importer, path, flags);
|
||||||
|
|
||||||
|
const aiScene* scene = importer.ReadFile(path, flags);
|
||||||
|
if (!scene || (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) || !scene->mRootNode) {
|
||||||
|
const std::string message = scene_failure_summary(path, importer.GetErrorString());
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "AssimpImport: " << message;
|
||||||
|
set_error_message(error_message, message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scene->mNumMeshes == 0) {
|
||||||
|
const std::string message = "Assimp scene has no meshes: " + path;
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "AssimpImport: " << message;
|
||||||
|
set_error_message(error_message, message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t vertex_offset = 0;
|
||||||
|
for (unsigned int mesh_index = 0; mesh_index < scene->mNumMeshes; ++mesh_index) {
|
||||||
|
const aiMesh* mesh = scene->mMeshes[mesh_index];
|
||||||
|
if (!mesh || !mesh->HasPositions())
|
||||||
|
continue;
|
||||||
|
std::string mesh_error;
|
||||||
|
if (!collect_mesh(*mesh, vertex_offset, out, mesh_error)) {
|
||||||
|
const std::string message = mesh_error + ": " + path;
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "AssimpImport: " << message;
|
||||||
|
set_error_message(error_message, message);
|
||||||
|
clear_textured_mesh(out);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out.vertices.empty() || out.indices.empty()) {
|
||||||
|
const std::string message = "Assimp extracted no valid triangles: " + path;
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "AssimpImport: " << message;
|
||||||
|
set_error_message(error_message, message);
|
||||||
|
clear_textured_mesh(out);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
collect_materials(*scene, boost::filesystem::path(path).parent_path(), out);
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "AssimpImport: loaded " << out.vertices.size()
|
||||||
|
<< " vertices, " << out.indices.size()
|
||||||
|
<< " triangles, " << out.textures.size()
|
||||||
|
<< " textures from " << path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
11
src/libslic3r/Format/AssimpImport.hpp
Normal file
11
src/libslic3r/Format/AssimpImport.hpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
struct TexturedMesh;
|
||||||
|
|
||||||
|
bool load_assimp_textured_model(const std::string& path, TexturedMesh& out, std::string* error_message = nullptr);
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "BuildVolume.hpp"
|
#include "BuildVolume.hpp"
|
||||||
#include "TexturePainting.hpp"
|
#include "TexturePainting.hpp"
|
||||||
|
#include "Format/AssimpImport.hpp"
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "Exception.hpp"
|
#include "Exception.hpp"
|
||||||
#include "Model.hpp"
|
#include "Model.hpp"
|
||||||
@@ -242,6 +243,27 @@ _finished:
|
|||||||
// BBS: add part plate related logic
|
// BBS: add part plate related logic
|
||||||
// BBS: backup & restore
|
// BBS: backup & restore
|
||||||
// Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well.
|
// Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well.
|
||||||
|
// Build a plain geometry ModelObject from a textured mesh. The texture itself is carried
|
||||||
|
// separately on Model::texture_mesh and consumed by the texture import dialog.
|
||||||
|
static void add_textured_mesh_to_model(Model& model, const TexturedMesh& tex_mesh, const std::string& input_file)
|
||||||
|
{
|
||||||
|
std::string object_name = boost::filesystem::path(input_file).filename().string();
|
||||||
|
|
||||||
|
indexed_triangle_set its;
|
||||||
|
its.vertices.resize(tex_mesh.vertices.size());
|
||||||
|
for (size_t i = 0; i < tex_mesh.vertices.size(); ++i)
|
||||||
|
its.vertices[i] = Vec3f(tex_mesh.vertices[i][0], tex_mesh.vertices[i][1], tex_mesh.vertices[i][2]);
|
||||||
|
its.indices.resize(tex_mesh.indices.size());
|
||||||
|
for (size_t i = 0; i < tex_mesh.indices.size(); ++i)
|
||||||
|
its.indices[i] = Vec3i32(tex_mesh.indices[i][0], tex_mesh.indices[i][1], tex_mesh.indices[i][2]);
|
||||||
|
|
||||||
|
its_merge_vertices(its);
|
||||||
|
its_remove_degenerate_faces(its);
|
||||||
|
its_compactify_vertices(its);
|
||||||
|
|
||||||
|
model.add_object(object_name.c_str(), input_file.c_str(), std::move(TriangleMesh(std::move(its))));
|
||||||
|
}
|
||||||
|
|
||||||
Model Model::read_from_file(const std::string& input_file,
|
Model Model::read_from_file(const std::string& input_file,
|
||||||
DynamicPrintConfig* config,
|
DynamicPrintConfig* config,
|
||||||
ConfigSubstitutionContext* config_substitutions,
|
ConfigSubstitutionContext* config_substitutions,
|
||||||
@@ -325,6 +347,23 @@ Model Model::read_from_file(const std::string&
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (boost::algorithm::iends_with(input_file, ".glb") ||
|
||||||
|
boost::algorithm::iends_with(input_file, ".gltf") ||
|
||||||
|
boost::algorithm::iends_with(input_file, ".fbx")) {
|
||||||
|
// These formats always carry material/texture data, so they go through the textured
|
||||||
|
// import path: the geometry becomes a normal object and the texture is handed to the
|
||||||
|
// texture-to-color dialog via Model::texture_mesh.
|
||||||
|
auto tex_mesh = std::make_shared<TexturedMesh>();
|
||||||
|
result = load_assimp_textured_model(input_file, *tex_mesh, &message);
|
||||||
|
if (result) {
|
||||||
|
model.texture_mesh = tex_mesh;
|
||||||
|
add_textured_mesh_to_model(model, *tex_mesh, input_file);
|
||||||
|
} else if (!message.empty()) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Assimp: failed to load model: " << message
|
||||||
|
<< ", path=" << input_file;
|
||||||
|
message = _L("The file format is incompatible and cannot be parsed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (boost::algorithm::iends_with(input_file, ".svg"))
|
else if (boost::algorithm::iends_with(input_file, ".svg"))
|
||||||
result = load_svg(input_file.c_str(), &model, message);
|
result = load_svg(input_file.c_str(), &model, message);
|
||||||
//BBS: remove the old .amf.xml files
|
//BBS: remove the old .amf.xml files
|
||||||
|
|||||||
@@ -521,10 +521,10 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
|
|||||||
/* FT_GCODE */ { L("G-code files"), { ".gcode"sv} },
|
/* FT_GCODE */ { L("G-code files"), { ".gcode"sv} },
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
/* FT_MODEL */
|
/* FT_MODEL */
|
||||||
{L("Supported files"), {".3mf"sv, ".stl"sv, ".oltp"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv, ".usd"sv, ".usda"sv, ".usdc"sv, ".usdz"sv, ".abc"sv, ".ply"sv, ".drc"sv}},
|
{L("Supported files"), {".3mf"sv, ".stl"sv, ".oltp"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv, ".gltf"sv, ".glb"sv, ".fbx"sv, ".usd"sv, ".usda"sv, ".usdc"sv, ".usdz"sv, ".abc"sv, ".ply"sv, ".drc"sv}},
|
||||||
#else
|
#else
|
||||||
/* FT_MODEL */
|
/* FT_MODEL */
|
||||||
{L("Supported files"), {".3mf"sv, ".stl"sv, ".oltp"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv, ".drc"sv}},
|
{L("Supported files"), {".3mf"sv, ".stl"sv, ".oltp"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv, ".gltf"sv, ".glb"sv, ".fbx"sv, ".drc"sv}},
|
||||||
#endif
|
#endif
|
||||||
/* FT_ZIP */ { L("ZIP files"), { ".zip"sv } },
|
/* FT_ZIP */ { L("ZIP files"), { ".zip"sv } },
|
||||||
/* FT_PROJECT */ { L("Project files"), { ".3mf"sv} },
|
/* FT_PROJECT */ { L("Project files"), { ".3mf"sv} },
|
||||||
|
|||||||
Reference in New Issue
Block a user