gltf import: fix light import (#1158)

The importer assumed that each light was only referenced once and in
the order it appears in the KHR_lights_punctual extension.

However, glTF allows a light to be referenced by more than one node,
and in different order. This commit adds support for this.
This commit is contained in:
Dennis Brakhane
2025-07-10 17:16:37 +02:00
committed by GitHub
parent d0941c07ef
commit 4028d250e7
+38 -31
View File
@@ -127,6 +127,7 @@ struct LoaderState
tinygltf::Model gltfModel;
Scene* scene;
wi::unordered_map<int, Entity> entityMap; // node -> entity
std::unordered_multimap<int, Entity> punctualLightMap; // KHR_lights_punctual -> entities
Entity rootEntity = INVALID_ENTITY;
//Export states
@@ -238,6 +239,8 @@ void LoadNode(int nodeIndex, Entity parent, LoaderState& state)
{
// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_lights_punctual
entity = scene.Entity_CreateLight(""); // light component will be filled later
int index = ext_lights_punctual->second.Get("light").Get<int>();
state.punctualLightMap.insert({ index, entity });
}
if (entity == INVALID_ENTITY)
@@ -1785,40 +1788,44 @@ void ImportModel_GLTF(const std::string& fileName, Scene& scene)
int lightIndex = 0;
for (auto& x : state.gltfModel.lights)
{
Entity entity = scene.lights.GetEntity(lightIndex);
LightComponent& light = scene.lights[lightIndex++];
NameComponent& name = *scene.names.GetComponent(entity);
name = x.name;
if (!x.type.compare("spot"))
for (auto [it, end] = state.punctualLightMap.equal_range(lightIndex); it != end; it++)
{
light.type = LightComponent::LightType::SPOT;
}
if (!x.type.compare("point"))
{
light.type = LightComponent::LightType::POINT;
}
if (!x.type.compare("directional"))
{
light.type = LightComponent::LightType::DIRECTIONAL;
}
Entity entity = it->second;
LightComponent& light = scene.lights[lightIndex];
NameComponent& name = *scene.names.GetComponent(entity);
name = x.name;
if (!x.color.empty())
{
light.color = XMFLOAT3(float(x.color[0]), float(x.color[1]), float(x.color[2]));
if (!x.type.compare("spot"))
{
light.type = LightComponent::LightType::SPOT;
}
if (!x.type.compare("point"))
{
light.type = LightComponent::LightType::POINT;
}
if (!x.type.compare("directional"))
{
light.type = LightComponent::LightType::DIRECTIONAL;
}
if (!x.color.empty())
{
light.color = XMFLOAT3(float(x.color[0]), float(x.color[1]), float(x.color[2]));
}
light.intensity = float(x.intensity);
light.range = x.range > 0 ? float(x.range) : std::numeric_limits<float>::max();
light.outerConeAngle = float(x.spot.outerConeAngle);
light.innerConeAngle = float(x.spot.innerConeAngle);
light.SetCastShadow(true);
// In gltf, default light direction is forward, in engine, it's downwards, so apply a rotation:
TransformComponent& transform = *scene.transforms.GetComponent(entity);
transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0));
ImportMetadata(state, entity, x.extras);
}
light.intensity = float(x.intensity);
light.range = x.range > 0 ? float(x.range) : std::numeric_limits<float>::max();
light.outerConeAngle = float(x.spot.outerConeAngle);
light.innerConeAngle = float(x.spot.innerConeAngle);
light.SetCastShadow(true);
// In gltf, default light direction is forward, in engine, it's downwards, so apply a rotation:
TransformComponent& transform = *scene.transforms.GetComponent(entity);
transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0));
ImportMetadata(state, entity, x.extras);
lightIndex++;
}
int cameraIndex = 0;