@@ -215,7 +215,7 @@ bool ModelLoader::ParseGLTF(const std::string& filename, Model* model) {
215215 gltfMaterial.emissiveFactor [0 ],
216216 gltfMaterial.emissiveFactor [1 ],
217217 gltfMaterial.emissiveFactor [2 ]
218- ) * light_scale ;
218+ );
219219 }
220220
221221 // Parse KHR_materials_emissive_strength extension
@@ -1327,21 +1327,46 @@ std::vector<ExtractedLight> ModelLoader::GetExtractedLights(const std::string& m
13271327 avgNormal = glm::vec3 (0 .0f , -1 .0f , 0 .0f ); // Default downward direction
13281328 }
13291329
1330- // Create an emissive light source
1331- ExtractedLight emissiveLight;
1332- emissiveLight.type = ExtractedLight::Type::Emissive;
1333- emissiveLight.position = center;
1334- emissiveLight.color = material->emissive ;
1335- emissiveLight.intensity = material->emissiveStrength ;
1336- emissiveLight.range = 1 .0f ; // Default range for emissive lights
1337- emissiveLight.sourceMaterial = material->GetName ();
1338- emissiveLight.direction = avgNormal;
1339-
1340- lights.push_back (emissiveLight);
1341-
1342- std::cout << " Created emissive light from material '" << material->GetName ()
1343- << " ' at position (" << center.x << " , " << center.y << " , " << center.z
1344- << " ) with intensity " << emissiveIntensity << std::endl;
1330+ // Create emissive light(s) transformed by each instance's model matrix
1331+ if (!materialMesh.instances .empty ()) {
1332+ for (const auto & inst : materialMesh.instances ) {
1333+ glm::mat4 M = inst.getModelMatrix ();
1334+ glm::vec3 worldCenter = glm::vec3 (M * glm::vec4 (center, 1 .0f ));
1335+ glm::mat3 normalMat = glm::transpose (glm::inverse (glm::mat3 (M)));
1336+ glm::vec3 worldNormal = glm::normalize (normalMat * avgNormal);
1337+
1338+ ExtractedLight emissiveLight;
1339+ emissiveLight.type = ExtractedLight::Type::Emissive;
1340+ emissiveLight.position = worldCenter;
1341+ emissiveLight.color = material->emissive ;
1342+ emissiveLight.intensity = material->emissiveStrength ;
1343+ emissiveLight.range = 1 .0f ; // Default range for emissive lights
1344+ emissiveLight.sourceMaterial = material->GetName ();
1345+ emissiveLight.direction = worldNormal;
1346+
1347+ lights.push_back (emissiveLight);
1348+
1349+ std::cout << " Created emissive light from material '" << material->GetName ()
1350+ << " ' at world position (" << worldCenter.x << " , " << worldCenter.y << " , " << worldCenter.z
1351+ << " ) with intensity " << emissiveIntensity << std::endl;
1352+ }
1353+ } else {
1354+ // No explicit instances; use identity transform
1355+ ExtractedLight emissiveLight;
1356+ emissiveLight.type = ExtractedLight::Type::Emissive;
1357+ emissiveLight.position = center;
1358+ emissiveLight.color = material->emissive ;
1359+ emissiveLight.intensity = material->emissiveStrength ;
1360+ emissiveLight.range = 1 .0f ; // Default range for emissive lights
1361+ emissiveLight.sourceMaterial = material->GetName ();
1362+ emissiveLight.direction = avgNormal;
1363+
1364+ lights.push_back (emissiveLight);
1365+
1366+ std::cout << " Created emissive light from material '" << material->GetName ()
1367+ << " ' at position (" << center.x << " , " << center.y << " , " << center.z
1368+ << " ) with intensity " << emissiveIntensity << std::endl;
1369+ }
13451370 }
13461371 }
13471372 }
@@ -1446,35 +1471,90 @@ bool ModelLoader::ExtractPunctualLights(const tinygltf::Model& gltfModel, const
14461471 std::cout << " No KHR_lights_punctual extension found" << std::endl;
14471472 }
14481473
1449- // Now find light nodes in the scene to get positions and directions
1450- for (const auto & node : gltfModel.nodes ) {
1474+ // Compute world transforms for all nodes in the default scene
1475+ std::vector<glm::mat4> nodeWorldTransforms (gltfModel.nodes .size (), glm::mat4 (1 .0f ));
1476+
1477+ auto calcLocal = [](const tinygltf::Node& n) -> glm::mat4 {
1478+ // If matrix is provided, use it
1479+ if (n.matrix .size () == 16 ) {
1480+ glm::mat4 m (1 .0f );
1481+ for (int r = 0 ; r < 4 ; ++r) {
1482+ for (int c = 0 ; c < 4 ; ++c) {
1483+ m[c][r] = static_cast <float >(n.matrix [r * 4 + c]);
1484+ }
1485+ }
1486+ return m;
1487+ }
1488+ // Otherwise compose TRS
1489+ glm::mat4 T (1 .0f ), R (1 .0f ), S (1 .0f );
1490+ if (n.translation .size () == 3 ) {
1491+ T = glm::translate (glm::mat4 (1 .0f ), glm::vec3 (
1492+ static_cast <float >(n.translation [0 ]),
1493+ static_cast <float >(n.translation [1 ]),
1494+ static_cast <float >(n.translation [2 ])));
1495+ }
1496+ if (n.rotation .size () == 4 ) {
1497+ glm::quat q (
1498+ static_cast <float >(n.rotation [3 ]),
1499+ static_cast <float >(n.rotation [0 ]),
1500+ static_cast <float >(n.rotation [1 ]),
1501+ static_cast <float >(n.rotation [2 ]));
1502+ R = glm::mat4_cast (q);
1503+ }
1504+ if (n.scale .size () == 3 ) {
1505+ S = glm::scale (glm::mat4 (1 .0f ), glm::vec3 (
1506+ static_cast <float >(n.scale [0 ]),
1507+ static_cast <float >(n.scale [1 ]),
1508+ static_cast <float >(n.scale [2 ])));
1509+ }
1510+ return T * R * S;
1511+ };
1512+
1513+ std::function<void (int , const glm::mat4&)> traverseNode = [&](int nodeIndex, const glm::mat4& parent) {
1514+ if (nodeIndex < 0 || nodeIndex >= static_cast <int >(gltfModel.nodes .size ())) return ;
1515+ const tinygltf::Node& n = gltfModel.nodes [nodeIndex];
1516+ glm::mat4 local = calcLocal (n);
1517+ glm::mat4 world = parent * local;
1518+ nodeWorldTransforms[nodeIndex] = world;
1519+ for (int child : n.children ) {
1520+ traverseNode (child, world);
1521+ }
1522+ };
1523+
1524+ if (!gltfModel.scenes .empty ()) {
1525+ int sceneIndex = gltfModel.defaultScene >= 0 ? gltfModel.defaultScene : 0 ;
1526+ if (sceneIndex < static_cast <int >(gltfModel.scenes .size ())) {
1527+ const tinygltf::Scene& scene = gltfModel.scenes [sceneIndex];
1528+ for (int root : scene.nodes ) {
1529+ traverseNode (root, glm::mat4 (1 .0f ));
1530+ }
1531+ }
1532+ } else {
1533+ // Fallback: traverse all nodes as roots
1534+ for (int i = 0 ; i < static_cast <int >(gltfModel.nodes .size ()); ++i) {
1535+ traverseNode (i, glm::mat4 (1 .0f ));
1536+ }
1537+ }
1538+
1539+ // Now assign positions and directions using world transforms
1540+ for (size_t nodeIndex = 0 ; nodeIndex < gltfModel.nodes .size (); ++nodeIndex) {
1541+ const auto & node = gltfModel.nodes [nodeIndex];
14511542 if (node.extensions .contains (" KHR_lights_punctual" )) {
14521543 const tinygltf::Value& nodeExtension = node.extensions .at (" KHR_lights_punctual" );
14531544 if (nodeExtension.Has (" light" ) && nodeExtension.Get (" light" ).IsInt ()) {
14541545 int lightIndex = nodeExtension.Get (" light" ).Get <int >();
14551546 if (lightIndex >= 0 && lightIndex < static_cast <int >(lights.size ())) {
1456- // Extract position from node transform
1457- if (node.translation .size () >= 3 ) {
1458- lights[lightIndex].position = glm::vec3 (
1459- static_cast <float >(node.translation [0 ]),
1460- static_cast <float >(node.translation [1 ]),
1461- static_cast <float >(node.translation [2 ])
1462- );
1463- }
1464-
1465- // Extract direction from node rotation (for directional and spotlights)
1466- if (node.rotation .size () >= 4 &&
1467- (lights[lightIndex].type == ExtractedLight::Type::Directional ||
1468- lights[lightIndex].type == ExtractedLight::Type::Spot)) {
1469- // Convert quaternion to a direction vector
1470- glm::quat rotation (
1471- static_cast <float >(node.rotation [3 ]), // w
1472- static_cast <float >(node.rotation [0 ]), // x
1473- static_cast <float >(node.rotation [1 ]), // y
1474- static_cast <float >(node.rotation [2 ]) // z
1475- );
1476- // Default forward direction in glTF is -Z
1477- lights[lightIndex].direction = rotation * glm::vec3 (0 .0f , 0 .0f , -1 .0f );
1547+ const glm::mat4& W = nodeWorldTransforms[nodeIndex];
1548+ // Position from world transform origin
1549+ glm::vec3 pos = glm::vec3 (W * glm::vec4 (0 , 0 , 0 , 1 ));
1550+ lights[lightIndex].position = pos;
1551+
1552+ // Direction for directional/spot: transform -Z
1553+ if (lights[lightIndex].type == ExtractedLight::Type::Directional ||
1554+ lights[lightIndex].type == ExtractedLight::Type::Spot) {
1555+ glm::mat3 rot = glm::mat3 (W);
1556+ glm::vec3 dir = glm::normalize (rot * glm::vec3 (0 .0f , 0 .0f , -1 .0f ));
1557+ lights[lightIndex].direction = dir;
14781558 }
14791559
14801560 std::cout << " Light " << lightIndex << " positioned at ("
0 commit comments