FCT
载入中...
搜索中...
未找到
Assimp_ModelLoader.cpp
浏览该文件的文档.
2namespace FCT
3{
8 {
9 switch (assimpType)
10 {
11 case aiTextureType_DIFFUSE: return ModelInfo::TextureType::diffuse;
12 case aiTextureType_SPECULAR: return ModelInfo::TextureType::specular;
13 case aiTextureType_NORMALS: return ModelInfo::TextureType::normals;
14 case aiTextureType_HEIGHT: return ModelInfo::TextureType::height;
15 case aiTextureType_EMISSIVE: return ModelInfo::TextureType::emissive;
16 case aiTextureType_SHININESS: return ModelInfo::TextureType::shininess;
17 case aiTextureType_OPACITY: return ModelInfo::TextureType::opacity;
18 case aiTextureType_DISPLACEMENT: return ModelInfo::TextureType::displacement;
19 case aiTextureType_LIGHTMAP: return ModelInfo::TextureType::lightmap;
20 case aiTextureType_REFLECTION: return ModelInfo::TextureType::reflection;
21 case aiTextureType_BASE_COLOR: return ModelInfo::TextureType::baseColor;
22 case aiTextureType_NORMAL_CAMERA: return ModelInfo::TextureType::normalCamera;
23 case aiTextureType_EMISSION_COLOR: return ModelInfo::TextureType::emissionColor;
24 case aiTextureType_METALNESS: return ModelInfo::TextureType::metalness;
25 case aiTextureType_DIFFUSE_ROUGHNESS: return ModelInfo::TextureType::diffuseRoughness;
26 case aiTextureType_AMBIENT_OCCLUSION: return ModelInfo::TextureType::ambientOcclusion;
27 case aiTextureType_SHEEN: return ModelInfo::TextureType::sheen;
28 case aiTextureType_CLEARCOAT: return ModelInfo::TextureType::clearcoat;
29 case aiTextureType_TRANSMISSION: return ModelInfo::TextureType::transmission;
30 default: return ModelInfo::TextureType::unknown;
31 }
32 }
33 std::unique_ptr<ModelData> Assimp_ModelLoader::loadModel(const std::string& path)
34 {
35 Assimp::Importer importer;
36 const auto aiScene = importer.ReadFile(path,
37 aiProcess_CalcTangentSpace |
38 aiProcess_Triangulate |
39 aiProcess_JoinIdenticalVertices |
40 aiProcess_SortByPType);
41
42 auto ret = std::make_unique<ModelData>();
43 for (unsigned int i = 0; i < aiScene->mNumMeshes; i++)
44 {
45 const auto aiMesh = aiScene->mMeshes[i];
46 auto mesh = new ModelMesh();
47 mesh->name = aiMesh->mName.C_Str();
48 mesh->material = nullptr;
49
50 mesh->vertices.resize(aiMesh->mNumVertices);
51
52 if (aiMesh->HasPositions())
53 {
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 };
57 }
58 }
59
60 if (aiMesh->HasNormals())
61 {
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 };
65 }
66 }
67
68 for (unsigned int texCoordSet = 0; texCoordSet < 8; texCoordSet++)
69 {
70 if (aiMesh->HasTextureCoords(texCoordSet))
71 {
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 };
75 }
76 }
77 }
78
79 if (aiMesh->HasTangentsAndBitangents())
80 {
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 };
86 }
87 }
88
89 for (unsigned int colorSet = 0; colorSet < 8; colorSet++)
90 {
91 if (aiMesh->HasVertexColors(colorSet))
92 {
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 };
96 }
97 }
98 }
99
100 if (aiMesh->HasFaces())
101 {
102 mesh->indices.reserve(aiMesh->mNumFaces * 3);
103 for (unsigned int j = 0; j < aiMesh->mNumFaces; j++)
104 {
105 const aiFace& face = aiMesh->mFaces[j];
106 for (unsigned int k = 0; k < face.mNumIndices; k++)
107 {
108 mesh->indices.push_back(face.mIndices[k]);
109 }
110 }
111 }
112
113 ret->meshes.push_back(mesh);
114 }
115 return ret;
116 }
118 {
120
121 Assimp::Importer importer;
122 const auto aiScene = importer.ReadFile(path,
123 aiProcess_CalcTangentSpace |
124 aiProcess_Triangulate |
125 aiProcess_JoinIdenticalVertices |
126 aiProcess_SortByPType);
127
128 if (!aiScene) {
129 return info;
130 }
131 info.name = aiScene->mName.C_Str();
132 for (unsigned int i = 0; i < aiScene->mNumMeshes; i++)
133 {
134 const auto aiMesh = aiScene->mMeshes[i];
135 ModelInfo::MeshInfo meshInfo;
136
137 meshInfo.name = aiMesh->mName.C_Str();
138 meshInfo.vertexCount = aiMesh->mNumVertices;
139 meshInfo.hasPositions = aiMesh->HasPositions();
140 meshInfo.hasNormals = aiMesh->HasNormals();
141 meshInfo.hasTangents = aiMesh->HasTangentsAndBitangents();
142 meshInfo.hasBitangents = aiMesh->HasTangentsAndBitangents();
143
144 for (unsigned int texCoordSet = 0; texCoordSet < 8; texCoordSet++) {
145 meshInfo.hasTexCoords[texCoordSet] = aiMesh->HasTextureCoords(texCoordSet);
146 }
147
148 for (unsigned int colorSet = 0; colorSet < 8; colorSet++) {
149 meshInfo.hasVertexColors[colorSet] = aiMesh->HasVertexColors(colorSet);
150 }
151
152 meshInfo.indexCount = 0;
153 meshInfo.triangleCount = 0;
154 if (aiMesh->HasFaces()) {
155 meshInfo.isIndexed = true;
156 for (unsigned int j = 0; j < aiMesh->mNumFaces; j++) {
157 const aiFace& face = aiMesh->mFaces[j];
158 meshInfo.indexCount += face.mNumIndices;
159 if (face.mNumIndices == 3) {
160 meshInfo.triangleCount++;
161 }
162 }
163 }
164
165 if (aiMesh->HasPositions()) {
166 aiVector3D min = aiMesh->mVertices[0];
167 aiVector3D max = aiMesh->mVertices[0];
168
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);
177 }
178
179 meshInfo.boundingBoxMin = Vec3(min.x, min.y, min.z);
180 meshInfo.boundingBoxMax = Vec3(max.x, max.y, max.z);
181 meshInfo.boundingBoxCenter = Vec3(
182 (min.x + max.x) * 0.5f,
183 (min.y + max.y) * 0.5f,
184 (min.z + max.z) * 0.5f
185 );
186 }
187
188 info.meshInfos.push_back(meshInfo);
189 }
190 std::map<std::string, ModelInfo::TextureInfo> textureInfoMap;
191 std::filesystem::path modelDir = std::filesystem::path(path).parent_path();
192
193 for (unsigned int i = 0; i < aiScene->mNumMaterials; i++)
194 {
195 const auto aiMaterial = aiScene->mMaterials[i];
196
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,
215 aiTextureType_SHEEN,
216 aiTextureType_CLEARCOAT,
217 aiTextureType_TRANSMISSION
218 };
219
220 for (auto textureType : textureTypes) {
221 unsigned int textureCount = aiMaterial->GetTextureCount(textureType);
222
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();
227
228 if (texturePathStr.empty()) {
229 continue;
230 }
231
232 if (textureInfoMap.find(texturePathStr) == textureInfoMap.end()) {
233 ModelInfo::TextureInfo textureInfo;
234 textureInfo.path = texturePathStr;
235 textureInfo.isInner = (texturePathStr[0] == '*');
236 textureInfo.types.insert(convertAssimpTextureType(textureType));
237
238 textureInfoMap[texturePathStr] = textureInfo;
239 } else {
240 textureInfoMap[texturePathStr].types.insert(convertAssimpTextureType(textureType));
241 }
242 }
243 }
244 }
245 }
246
247 for (const auto& [path, textureInfo] : textureInfoMap) {
248 info.textureInfos.push_back(textureInfo);
249 }
250
251 return info;
252 }
253
254 std::set<std::string> Assimp_ModelLoader::resolveTexturePaths(const std::string& modelPath) const
255 {
256 std::set<std::string> texturePaths;
257
258 Assimp::Importer importer;
259 const auto aiScene = importer.ReadFile(modelPath,
260 aiProcess_CalcTangentSpace |
261 aiProcess_Triangulate |
262 aiProcess_JoinIdenticalVertices |
263 aiProcess_SortByPType);
264
265 if (!aiScene || !aiScene->HasMaterials()) {
266 return texturePaths;
267 }
268
269 std::filesystem::path modelDir = std::filesystem::path(modelPath).parent_path();
270
271 for (unsigned int i = 0; i < aiScene->mNumMaterials; i++) {
272 const auto aiMaterial = aiScene->mMaterials[i];
273
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,
292 aiTextureType_SHEEN,
293 aiTextureType_CLEARCOAT,
294 aiTextureType_TRANSMISSION
295 };
296
297 for (auto textureType : textureTypes) {
298 unsigned int textureCount = aiMaterial->GetTextureCount(textureType);
299
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();
304
305 if (texturePathStr.empty()) {
306 continue;
307 }
308
309 if (texturePathStr[0] == '*') {
310 continue;
311 }
312
313 std::vector<std::string> candidatePaths;
314
315 candidatePaths.push_back(texturePathStr);
316
317 candidatePaths.push_back((modelDir / texturePathStr).string());
318
319 std::filesystem::path textureFileName = std::filesystem::path(texturePathStr).filename();
320 candidatePaths.push_back((modelDir / textureFileName).string());
321
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());
325 }
326
327 bool found = false;
328 for (const auto& candidatePath : candidatePaths) {
329 if (std::filesystem::exists(candidatePath)) {
330 try {
331 std::string absolutePath = std::filesystem::canonical(candidatePath).string();
332 texturePaths.insert(absolutePath);
333 found = true;
334 break;
335 } catch (const std::filesystem::filesystem_error&) {
336 try {
337 std::string absolutePath = std::filesystem::absolute(candidatePath).string();
338 texturePaths.insert(absolutePath);
339 found = true;
340 break;
341 } catch (const std::filesystem::filesystem_error&) {
342 continue;
343 }
344 }
345 }
346 }
347
348 if (!found) {
349 try {
350 std::string fallbackPath;
351 if (std::filesystem::path(texturePathStr).is_absolute()) {
352 fallbackPath = std::filesystem::absolute(texturePathStr).string();
353 } else {
354 fallbackPath = std::filesystem::absolute(modelDir / texturePathStr).string();
355 }
356 texturePaths.insert(fallbackPath);
357 } catch (const std::filesystem::filesystem_error&) {
358 texturePaths.insert(texturePathStr);
359 }
360 }
361 }
362 }
363 }
364 }
365
366 return texturePaths;
367 }
368
370 {
371 return {
372
373 };
374 }
375
376 bool Assimp_ModelLoader::getEmbeddedTextureData(const std::string& modelPath, int textureIndex,
377 std::vector<unsigned char>& outData) const
378 {
379 try {
380 Assimp::Importer importer;
381 const aiScene* scene = importer.ReadFile(modelPath, aiProcess_Triangulate);
382
383 if (!scene) {
384 std::cerr << "Failed to load model for embedded texture: " << modelPath << std::endl;
385 return false;
386 }
387
388 if (textureIndex < 0 || textureIndex >= static_cast<int>(scene->mNumTextures)) {
389 std::cerr << "Invalid texture index: " << textureIndex << ", available textures: " << scene->mNumTextures << std::endl;
390 return false;
391 }
392
393 const aiTexture* texture = scene->mTextures[textureIndex];
394 if (!texture) {
395 std::cerr << "Texture at index " << textureIndex << " is null" << std::endl;
396 return false;
397 }
398
399 size_t dataSize;
400 const unsigned char* sourceData = reinterpret_cast<const unsigned char*>(texture->pcData);
401
402 if (texture->mHeight == 0) {
403 dataSize = texture->mWidth;
404 } else {
405 dataSize = texture->mWidth * texture->mHeight * 4;
406 }
407
408 outData.resize(dataSize);
409 std::memcpy(outData.data(), sourceData, dataSize);
410
411 std::cout << "Successfully loaded embedded texture " << textureIndex << " from " << modelPath
412 << ", size: " << dataSize << " bytes" << std::endl;
413 return true;
414
415 } catch (const std::exception& e) {
416 std::cerr << "Exception while loading embedded texture: " << e.what() << std::endl;
417 return false;
418 }
419 }
420}
std::unique_ptr< ModelData > loadModel(const std::string &path) override
ModelInfo::SceneInfo loadModelInfo(const std::string &path) override
std::set< std::string > getPlatformSupportedExtensions() const override
bool getEmbeddedTextureData(const std::string &modelPath, int textureIndex, std::vector< unsigned char > &outData) const override
获取内嵌纹理数据
std::set< std::string > resolveTexturePaths(const std::string &modelPath) const override
解析模型依赖的纹理位置
TextureType
纹理类型枚举
ModelInfo::TextureType convertAssimpTextureType(aiTextureType assimpType)
将Assimp纹理类型转换为ModelInfo::TextureType
std::array< bool, 8 > hasTexCoords
std::array< bool, 8 > hasVertexColors
std::vector< TextureInfo > textureInfos
std::vector< MeshInfo > meshInfos
std::set< TextureType > types