Skip to content

Commit bbb3183

Browse files
authored
Fix loading lightmaps from gltf / glb meshes (#630)
Signed-off-by: Ian Chen <[email protected]>
1 parent 3f129c3 commit bbb3183

File tree

1 file changed

+43
-13
lines changed

1 file changed

+43
-13
lines changed

graphics/src/AssimpLoader.cc

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
*/
1717

1818
#include <cstddef>
19+
#include <memory>
1920
#include <queue>
2021
#include <string>
2122
#include <unordered_set>
23+
#include <vector>
2224

2325
#include "gz/common/graphics/Types.hh"
2426
#include "gz/common/AssimpLoader.hh"
@@ -462,22 +464,50 @@ MaterialPtr AssimpLoader::Implementation::CreateMaterial(
462464
"Roughness"));
463465
pbr.SetRoughnessMap(texName, texData);
464466
}
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)
475487
{
476-
auto [texName, texData] = this->LoadTexture(_scene, texturePath,
477-
this->GenerateTextureName(_fileBaseName, _scene, assimpMat,
478-
"Lightmap"));
479488
pbr.SetLightMap(texName, uvIdx, texData);
480489
}
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+
}
481511
}
482512
#endif
483513
ret = assimpMat->GetTexture(aiTextureType_NORMALS, 0, &texturePath);

0 commit comments

Comments
 (0)