2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-06 08:42:35 +00:00

feat: Loading sun data through GLTF

This commit is contained in:
LJW-Dev
2026-04-22 19:22:45 +08:00
committed by Jan Laupetin
parent 855825c6de
commit d0ae3ecdb5
5 changed files with 198 additions and 259 deletions
+81 -90
View File
@@ -359,32 +359,85 @@ namespace
return vertexOffset;
}
bool addLightNode(const gltf::JsonNode& node, Eigen::Matrix4f& nodeMatrix)
bool addLightNode(const JsonRoot& jRoot, const gltf::JsonNode& node, Eigen::Matrix4f& nodeMatrix)
{
assert(m_is_world_gfx);
if (!m_is_world_gfx || !jRoot.extensions || !jRoot.extensions->KHR_lights_punctual || !jRoot.extensions->KHR_lights_punctual->lights)
return false;
assert(node.extensions);
assert(node.extensions->KHR_lights_punctual);
int lightIndex = node.extensions->KHR_lights_punctual->light;
const JsonPunctualLight& jsLight = jRoot.extensions->KHR_lights_punctual->lights->at(lightIndex);
BSPLight light{};
assert(lightIndex >= 0);
if (m_bsp->lights[lightIndex].hasPosBeenSet == true)
con::warn("Internal error, multiple nodes reference the same light. Light positions/rotations are likely incorrect.");
light.outerConeAngle = std::numbers::pi_v<float> / 4.0f; /// spec of 45 degrees
light.innerConeAngle = 0.0f;
if (jsLight.type == JsonPunctualLightType::DIRECTIONAL)
{
if (m_bsp->hasSunlightBeenSet)
con::warn("WARNING: multiple sunlight nodes found, only one will be used as the sun.");
light.type = LIGHT_TYPE_DIRECTIONAL;
m_bsp->hasSunlightBeenSet = true;
}
else if (jsLight.type == JsonPunctualLightType::POINT)
{
con::warn("Ignoring point light as BO2 does not support point lights.");
return false;
}
else // JsonPunctualLightType::SPOT
{
light.type = LIGHT_TYPE_SPOT;
assert(jsLight.spot);
if (jsLight.spot->innerConeAngle)
light.innerConeAngle = *jsLight.spot->innerConeAngle;
if (jsLight.spot->outerConeAngle)
light.outerConeAngle = *jsLight.spot->outerConeAngle;
}
if (!jsLight.color)
{
light.colour.x = 1.0f;
light.colour.y = 1.0f;
light.colour.z = 1.0f;
}
else
{
light.colour.x = (*jsLight.color)[0];
light.colour.y = (*jsLight.color)[1];
light.colour.z = (*jsLight.color)[2];
}
if (!jsLight.intensity)
light.intensity = 1000.0f; // adjusted from spec to better match BO2
else
light.intensity = *jsLight.intensity;
if (!jsLight.range)
light.range = 1000.0f; // adjusted from spec to better match BO2
else
light.range = *jsLight.range;
Eigen::Vector4f position(0, 0, 0, 1.0f);
Eigen::Vector4f transformedPosition = nodeMatrix * position;
m_bsp->lights[lightIndex].pos = vec3_t{transformedPosition.x(), transformedPosition.y(), transformedPosition.z()};
RhcToLhcCoordinates(m_bsp->lights[lightIndex].pos.v);
light.pos = vec3_t{transformedPosition.x(), transformedPosition.y(), transformedPosition.z()};
RhcToLhcCoordinates(light.pos.v);
// GLTF spec uses +Y up and the default light direction is straight down
Eigen::Vector3f defaultDirection(0.0f, -1.0f, 0.0f);
Eigen::Vector3f defaultDirection(0.0f, 0.0f, 1.0f); // lights use this value for the forward angle instead in BO2
Eigen::Affine3f affineTransform(nodeMatrix);
Eigen::Matrix3f rotationMatrix = affineTransform.rotation();
Eigen::Vector3f outputDirection = rotationMatrix * defaultDirection;
outputDirection.normalize();
m_bsp->lights[lightIndex].direction = vec3_t{outputDirection.x(), outputDirection.y(), outputDirection.z()};
light.direction.x = outputDirection.x();
light.direction.y = outputDirection.y();
light.direction.z = outputDirection.z();
RhcToLhcCoordinates(light.direction.v);
m_bsp->lights[lightIndex].hasPosBeenSet = true;
if (jsLight.type == JsonPunctualLightType::DIRECTIONAL)
m_bsp->sunlight = light;
else
m_bsp->lights.emplace_back(light);
return true;
}
@@ -588,7 +641,6 @@ namespace
xmodel.rotationQuaternion.w = rotationQuat.w();
RhcToLhcQuaternion(xmodel.rotationQuaternion.v);
con::warn("XModels don't support scale currently, keep it at 1 in your editor");
xmodel.scale = 1.0f;
calculateXmodelBounds(xmodel, node.mesh, nodeMatrix, jRoot);
@@ -904,7 +956,7 @@ namespace
bool addNodeToBSP(const JsonRoot& jRoot, const gltf::JsonNode& node, Eigen::Matrix4f& nodeMatrix)
{
if (m_is_world_gfx && node.extensions && node.extensions->KHR_lights_punctual)
return addLightNode(node, nodeMatrix);
return addLightNode(jRoot, node, nodeMatrix);
if (node.extras)
{
@@ -1040,80 +1092,6 @@ namespace
m_curr_bsp_world->materials.emplace_back(emptyMaterial);
}
void LoadLights(const JsonRoot& jRoot)
{
if (!m_is_world_gfx)
return;
if (!jRoot.extensions)
return;
if (!jRoot.extensions->KHR_lights_punctual)
return;
if (!jRoot.extensions->KHR_lights_punctual->lights)
return;
const std::vector<JsonPunctualLight>& jsLightArray = jRoot.extensions->KHR_lights_punctual->lights.value();
m_bsp->lights.reserve(jsLightArray.size());
for (const JsonPunctualLight& jsLight : jsLightArray)
{
if (jsLight.type == JsonPunctualLightType::POINT)
con::error("Any point lights will be converted to a spotlight as point lights are unsupported right now.");
BSPLight light{};
// position and direction data will be set during node traversal
light.hasPosBeenSet = false;
if (!jsLight.color)
{
light.colour.x = 1.0f;
light.colour.y = 1.0f;
light.colour.z = 1.0f;
}
else
{
light.colour.x = (*jsLight.color)[0];
light.colour.y = (*jsLight.color)[1];
light.colour.z = (*jsLight.color)[2];
}
if (!jsLight.intensity)
light.intensity = 100000.0f; // adjusted from spec to better match BO2
else
light.intensity = *jsLight.intensity;
if (!jsLight.range)
light.range = 1000.0f; // adjusted from spec to better match BO2
else
light.range = *jsLight.range;
if (jsLight.type == JsonPunctualLightType::DIRECTIONAL)
{
light.type = LIGHT_TYPE_DIRECTIONAL;
}
else if (jsLight.type == JsonPunctualLightType::POINT)
{
light.type = LIGHT_TYPE_POINT;
}
else // JsonPunctualLightType::SPOT
{
light.type = LIGHT_TYPE_SPOT;
assert(jsLight.spot);
if (!jsLight.spot->innerConeAngle)
light.innerConeAngle = 0.0f;
else
light.innerConeAngle = *jsLight.spot->innerConeAngle;
if (!jsLight.spot->outerConeAngle)
light.outerConeAngle = 3.14159265359f / 4.0f; /// spec of 45 degrees
else
light.outerConeAngle = *jsLight.spot->outerConeAngle;
}
m_bsp->lights.emplace_back(light);
}
}
void TraverseNodes(const JsonRoot& jRoot)
{
// Make sure there are any nodes to traverse
@@ -1266,9 +1244,6 @@ namespace
CreateBufferViews(jRoot);
CreateAccessors(jRoot);
if (isGfxWorld) // lights aren't needed in collision data
LoadLights(jRoot);
LoadMaterials(jRoot);
TraverseNodes(jRoot); // requires materials and lights
}
@@ -1330,6 +1305,9 @@ namespace BSP
bsp->name = mapName;
bsp->bspName = "maps/mp/" + mapName + ".d3dbsp";
bsp->isZombiesMap = isZombiesMap;
bsp->hasSunlightBeenSet = false;
con::warn("XModels don't support scale currently, keep it at 1 in your editor");
BSPLoader loader(bsp.get());
if (isGfxFileGltf)
@@ -1375,6 +1353,19 @@ namespace BSP
}
}
if (!bsp->hasSunlightBeenSet)
{
con::info("Writing default sun values");
bsp->sunlight.type = LIGHT_TYPE_DIRECTIONAL;
bsp->sunlight.colour = {1.0f, 1.0f, 1.0f};
bsp->sunlight.range = 1000.0f;
bsp->sunlight.intensity = 1000.0f;
bsp->sunlight.pos = {0.0f, 0.0f, 0.0f};
bsp->sunlight.direction = {0.0f, -1.0f, 0.0f};
bsp->sunlight.innerConeAngle = 0.0f;
bsp->sunlight.outerConeAngle = 0.0f;
}
return bsp;
}
} // namespace BSP