|
16 | 16 | */
|
17 | 17 |
|
18 | 18 | #include <cstddef>
|
| 19 | +#include <memory> |
19 | 20 | #include <queue>
|
20 | 21 | #include <string>
|
21 | 22 | #include <unordered_set>
|
| 23 | +#include <vector> |
22 | 24 |
|
23 | 25 | #include "gz/common/graphics/Types.hh"
|
24 | 26 | #include "gz/common/AssimpLoader.hh"
|
@@ -462,22 +464,50 @@ MaterialPtr AssimpLoader::Implementation::CreateMaterial(
|
462 | 464 | "Roughness"));
|
463 | 465 | pbr.SetRoughnessMap(texName, texData);
|
464 | 466 | }
|
465 |
| - // Load lightmap only if it is not a glb/glTF mesh that contains a |
466 |
| - // MetallicRoughness texture |
467 |
| - // It was found that lightmap field just stores the entire MetallicRoughness |
468 |
| - // texture. Issues were also reported in assimp: |
469 |
| - // https://github.com/assimp/assimp/issues/3120 |
470 |
| - // https://github.com/assimp/assimp/issues/4637 |
471 |
| - unsigned int uvIdx = 0; |
472 |
| - ret = assimpMat->GetTexture( |
473 |
| - aiTextureType_LIGHTMAP, 0, &texturePath, NULL, &uvIdx); |
474 |
| - if (ret == AI_SUCCESS) |
| 467 | + } |
| 468 | + |
| 469 | + // The lightmap / ambient occlusion texture may be the same texture as the |
| 470 | + // metallicRoughness texture but it can also be a separate texture using a |
| 471 | + // different uv index. In the former case, we expect the occlusion |
| 472 | + // data to be packed in the R channel of the metallicRoughness texture, |
| 473 | + // so load the occlusion data in the same ways as we do in the |
| 474 | + // SplitMetallicRoughnessMap function. |
| 475 | + // In the latter case (separate texture), no extra processing is |
| 476 | + // required. |
| 477 | + unsigned int uvIdx = 0; |
| 478 | + ret = assimpMat->GetTexture( |
| 479 | + aiTextureType_LIGHTMAP, 0, &texturePath, NULL, &uvIdx); |
| 480 | + if (ret == AI_SUCCESS) |
| 481 | + { |
| 482 | + auto [texName, texData] = this->LoadTexture(_scene, texturePath, |
| 483 | + this->GenerateTextureName(_fileBaseName, _scene, assimpMat, |
| 484 | + "Lightmap")); |
| 485 | + // Separate uv set so treat it as a separate texture |
| 486 | + if (uvIdx > 0) |
475 | 487 | {
|
476 |
| - auto [texName, texData] = this->LoadTexture(_scene, texturePath, |
477 |
| - this->GenerateTextureName(_fileBaseName, _scene, assimpMat, |
478 |
| - "Lightmap")); |
479 | 488 | pbr.SetLightMap(texName, uvIdx, texData);
|
480 | 489 | }
|
| 490 | + // else split the occlusion data from the metallicRoughness texture |
| 491 | + else |
| 492 | + { |
| 493 | + // R channel contains the occlusion data |
| 494 | + // Note we are still creating an RGBA texture which seems watesful |
| 495 | + // but that's what gz-rendering expects |
| 496 | + auto origRGBAData = texData->RGBAData(); |
| 497 | + std::vector<unsigned char> texRData(origRGBAData.size()); |
| 498 | + for (unsigned int i = 0; i < origRGBAData.size(); i+=4) |
| 499 | + { |
| 500 | + auto r = origRGBAData.at(i); |
| 501 | + texRData[i] = r; |
| 502 | + texRData[i + 1] = r; |
| 503 | + texRData[i + 2] = r; |
| 504 | + texRData[i + 3] = 255; |
| 505 | + } |
| 506 | + auto tex = std::make_shared<Image>(); |
| 507 | + tex->SetFromData(&texRData[0], texData->Width(), texData->Height(), |
| 508 | + Image::RGBA_INT8); |
| 509 | + pbr.SetLightMap(texName, uvIdx, tex); |
| 510 | + } |
481 | 511 | }
|
482 | 512 | #endif
|
483 | 513 | ret = assimpMat->GetTexture(aiTextureType_NORMALS, 0, &texturePath);
|
|
0 commit comments