35 Assimp::Importer importer;
36 const auto aiScene = importer.ReadFile(path,
37 aiProcess_CalcTangentSpace |
38 aiProcess_Triangulate |
39 aiProcess_JoinIdenticalVertices |
40 aiProcess_SortByPType);
42 auto ret = std::make_unique<ModelData>();
43 for (
unsigned int i = 0; i < aiScene->mNumMeshes; i++)
45 const auto aiMesh = aiScene->mMeshes[i];
47 mesh->name = aiMesh->mName.C_Str();
48 mesh->material =
nullptr;
50 mesh->vertices.resize(aiMesh->mNumVertices);
52 if (aiMesh->HasPositions())
54 for (
unsigned int j = 0; j < aiMesh->mNumVertices; j++) {
55 const auto& aiVertex = aiMesh->mVertices[j];
56 mesh->vertices[j].position = { aiVertex.x, aiVertex.y, aiVertex.z };
60 if (aiMesh->HasNormals())
62 for (
unsigned int j = 0; j < aiMesh->mNumVertices; j++) {
63 const auto& aiNormal = aiMesh->mNormals[j];
64 mesh->vertices[j].normal = { aiNormal.x, aiNormal.y, aiNormal.z };
68 for (
unsigned int texCoordSet = 0; texCoordSet < 8; texCoordSet++)
70 if (aiMesh->HasTextureCoords(texCoordSet))
72 for (
unsigned int j = 0; j < aiMesh->mNumVertices; j++) {
73 const auto& aiTexCoord = aiMesh->mTextureCoords[texCoordSet][j];
74 mesh->vertices[j].texCoords[texCoordSet] = { aiTexCoord.x, aiTexCoord.y };
79 if (aiMesh->HasTangentsAndBitangents())
81 for (
unsigned int j = 0; j < aiMesh->mNumVertices; j++) {
82 const auto& aiTangent = aiMesh->mTangents[j];
83 const auto& aiBitangent = aiMesh->mBitangents[j];
84 mesh->vertices[j].tangent = { aiTangent.x, aiTangent.y, aiTangent.z };
85 mesh->vertices[j].bitangent = { aiBitangent.x, aiBitangent.y, aiBitangent.z };
89 for (
unsigned int colorSet = 0; colorSet < 8; colorSet++)
91 if (aiMesh->HasVertexColors(colorSet))
93 for (
unsigned int j = 0; j < aiMesh->mNumVertices; j++) {
94 const auto& aiColor = aiMesh->mColors[colorSet][j];
95 mesh->vertices[j].colors[colorSet] = { aiColor.r, aiColor.g, aiColor.b, aiColor.a };
100 if (aiMesh->HasFaces())
102 mesh->indices.reserve(aiMesh->mNumFaces * 3);
103 for (
unsigned int j = 0; j < aiMesh->mNumFaces; j++)
105 const aiFace& face = aiMesh->mFaces[j];
106 for (
unsigned int k = 0; k < face.mNumIndices; k++)
108 mesh->indices.push_back(face.mIndices[k]);
113 ret->meshes.push_back(mesh);
121 Assimp::Importer importer;
122 const auto aiScene = importer.ReadFile(path,
123 aiProcess_CalcTangentSpace |
124 aiProcess_Triangulate |
125 aiProcess_JoinIdenticalVertices |
126 aiProcess_SortByPType);
131 info.
name = aiScene->mName.C_Str();
132 for (
unsigned int i = 0; i < aiScene->mNumMeshes; i++)
134 const auto aiMesh = aiScene->mMeshes[i];
137 meshInfo.
name = aiMesh->mName.C_Str();
141 meshInfo.
hasTangents = aiMesh->HasTangentsAndBitangents();
144 for (
unsigned int texCoordSet = 0; texCoordSet < 8; texCoordSet++) {
145 meshInfo.
hasTexCoords[texCoordSet] = aiMesh->HasTextureCoords(texCoordSet);
148 for (
unsigned int colorSet = 0; colorSet < 8; colorSet++) {
149 meshInfo.
hasVertexColors[colorSet] = aiMesh->HasVertexColors(colorSet);
154 if (aiMesh->HasFaces()) {
156 for (
unsigned int j = 0; j < aiMesh->mNumFaces; j++) {
157 const aiFace& face = aiMesh->mFaces[j];
159 if (face.mNumIndices == 3) {
165 if (aiMesh->HasPositions()) {
166 aiVector3D min = aiMesh->mVertices[0];
167 aiVector3D max = aiMesh->mVertices[0];
169 for (
unsigned int j = 1; j < aiMesh->mNumVertices; j++) {
170 const aiVector3D& vertex = aiMesh->mVertices[j];
171 min.x = std::min(min.x, vertex.x);
172 min.y = std::min(min.y, vertex.y);
173 min.z = std::min(min.z, vertex.z);
174 max.x = std::max(max.x, vertex.x);
175 max.y = std::max(max.y, vertex.y);
176 max.z = std::max(max.z, vertex.z);
182 (min.x + max.x) * 0.5f,
183 (min.y + max.y) * 0.5f,
184 (min.z + max.z) * 0.5f
190 std::map<std::string, ModelInfo::TextureInfo> textureInfoMap;
191 std::filesystem::path modelDir = std::filesystem::path(path).parent_path();
193 for (
unsigned int i = 0; i < aiScene->mNumMaterials; i++)
195 const auto aiMaterial = aiScene->mMaterials[i];
197 std::vector<aiTextureType> textureTypes = {
198 aiTextureType_DIFFUSE,
199 aiTextureType_SPECULAR,
200 aiTextureType_AMBIENT,
201 aiTextureType_EMISSIVE,
202 aiTextureType_HEIGHT,
203 aiTextureType_NORMALS,
204 aiTextureType_SHININESS,
205 aiTextureType_OPACITY,
206 aiTextureType_DISPLACEMENT,
207 aiTextureType_LIGHTMAP,
208 aiTextureType_REFLECTION,
209 aiTextureType_BASE_COLOR,
210 aiTextureType_NORMAL_CAMERA,
211 aiTextureType_EMISSION_COLOR,
212 aiTextureType_METALNESS,
213 aiTextureType_DIFFUSE_ROUGHNESS,
214 aiTextureType_AMBIENT_OCCLUSION,
216 aiTextureType_CLEARCOAT,
217 aiTextureType_TRANSMISSION
220 for (
auto textureType : textureTypes) {
221 unsigned int textureCount = aiMaterial->GetTextureCount(textureType);
223 for (
unsigned int j = 0; j < textureCount; j++) {
224 aiString texturePath;
225 if (aiMaterial->GetTexture(textureType, j, &texturePath) == AI_SUCCESS) {
226 std::string texturePathStr = texturePath.C_Str();
228 if (texturePathStr.empty()) {
232 if (textureInfoMap.find(texturePathStr) == textureInfoMap.end()) {
234 textureInfo.
path = texturePathStr;
235 textureInfo.
isInner = (texturePathStr[0] ==
'*');
238 textureInfoMap[texturePathStr] = textureInfo;
247 for (
const auto& [path, textureInfo] : textureInfoMap) {
256 std::set<std::string> texturePaths;
258 Assimp::Importer importer;
259 const auto aiScene = importer.ReadFile(modelPath,
260 aiProcess_CalcTangentSpace |
261 aiProcess_Triangulate |
262 aiProcess_JoinIdenticalVertices |
263 aiProcess_SortByPType);
265 if (!aiScene || !aiScene->HasMaterials()) {
269 std::filesystem::path modelDir = std::filesystem::path(modelPath).parent_path();
271 for (
unsigned int i = 0; i < aiScene->mNumMaterials; i++) {
272 const auto aiMaterial = aiScene->mMaterials[i];
274 std::vector<aiTextureType> textureTypes = {
275 aiTextureType_DIFFUSE,
276 aiTextureType_SPECULAR,
277 aiTextureType_AMBIENT,
278 aiTextureType_EMISSIVE,
279 aiTextureType_HEIGHT,
280 aiTextureType_NORMALS,
281 aiTextureType_SHININESS,
282 aiTextureType_OPACITY,
283 aiTextureType_DISPLACEMENT,
284 aiTextureType_LIGHTMAP,
285 aiTextureType_REFLECTION,
286 aiTextureType_BASE_COLOR,
287 aiTextureType_NORMAL_CAMERA,
288 aiTextureType_EMISSION_COLOR,
289 aiTextureType_METALNESS,
290 aiTextureType_DIFFUSE_ROUGHNESS,
291 aiTextureType_AMBIENT_OCCLUSION,
293 aiTextureType_CLEARCOAT,
294 aiTextureType_TRANSMISSION
297 for (
auto textureType : textureTypes) {
298 unsigned int textureCount = aiMaterial->GetTextureCount(textureType);
300 for (
unsigned int j = 0; j < textureCount; j++) {
301 aiString texturePath;
302 if (aiMaterial->GetTexture(textureType, j, &texturePath) == AI_SUCCESS) {
303 std::string texturePathStr = texturePath.C_Str();
305 if (texturePathStr.empty()) {
309 if (texturePathStr[0] ==
'*') {
313 std::vector<std::string> candidatePaths;
315 candidatePaths.push_back(texturePathStr);
317 candidatePaths.push_back((modelDir / texturePathStr).
string());
319 std::filesystem::path textureFileName = std::filesystem::path(texturePathStr).filename();
320 candidatePaths.push_back((modelDir / textureFileName).
string());
322 std::vector<std::string> commonTextureDirs = {
"textures",
"texture",
"images",
"img",
"maps"};
323 for (
const auto& texDir : commonTextureDirs) {
324 candidatePaths.push_back((modelDir / texDir / textureFileName).
string());
328 for (
const auto& candidatePath : candidatePaths) {
329 if (std::filesystem::exists(candidatePath)) {
331 std::string absolutePath = std::filesystem::canonical(candidatePath).string();
332 texturePaths.insert(absolutePath);
335 }
catch (
const std::filesystem::filesystem_error&) {
337 std::string absolutePath = std::filesystem::absolute(candidatePath).string();
338 texturePaths.insert(absolutePath);
341 }
catch (
const std::filesystem::filesystem_error&) {
350 std::string fallbackPath;
351 if (std::filesystem::path(texturePathStr).is_absolute()) {
352 fallbackPath = std::filesystem::absolute(texturePathStr).string();
354 fallbackPath = std::filesystem::absolute(modelDir / texturePathStr).string();
356 texturePaths.insert(fallbackPath);
357 }
catch (
const std::filesystem::filesystem_error&) {
358 texturePaths.insert(texturePathStr);
377 std::vector<unsigned char>& outData)
const
380 Assimp::Importer importer;
381 const aiScene* scene = importer.ReadFile(modelPath, aiProcess_Triangulate);
384 std::cerr <<
"Failed to load model for embedded texture: " << modelPath << std::endl;
388 if (textureIndex < 0 || textureIndex >=
static_cast<int>(scene->mNumTextures)) {
389 std::cerr <<
"Invalid texture index: " << textureIndex <<
", available textures: " << scene->mNumTextures << std::endl;
393 const aiTexture* texture = scene->mTextures[textureIndex];
395 std::cerr <<
"Texture at index " << textureIndex <<
" is null" << std::endl;
400 const unsigned char* sourceData =
reinterpret_cast<const unsigned char*
>(texture->pcData);
402 if (texture->mHeight == 0) {
403 dataSize = texture->mWidth;
405 dataSize = texture->mWidth * texture->mHeight * 4;
408 outData.resize(dataSize);
409 std::memcpy(outData.data(), sourceData, dataSize);
411 std::cout <<
"Successfully loaded embedded texture " << textureIndex <<
" from " << modelPath
412 <<
", size: " << dataSize <<
" bytes" << std::endl;
415 }
catch (
const std::exception& e) {
416 std::cerr <<
"Exception while loading embedded texture: " << e.what() << std::endl;