Add steep slope limiting to prevent terrain clipping

Added slope normal checking to reject surfaces too steep to walk.
Prevents character/mount from clipping through steep terrain.

Changes:
- Added MIN_WALKABLE_NORMAL threshold (0.7 = ~45° max slope)
- WMO collision: query surface normal, reject if normalZ < 0.7
- M2 collision: query surface normal, reject if normalZ < 0.7
- Updated M2Renderer::getFloorHeight to output surface normal
- M2 already had internal 0.35 check (~70°), new 0.7 is more restrictive

Steep slopes now block movement instead of allowing clipping.
This commit is contained in:
Kelsi 2026-02-10 20:45:25 -08:00
parent 7e85e0b2ef
commit 73db7768d4
3 changed files with 30 additions and 5 deletions

View file

@ -2688,9 +2688,10 @@ uint32_t M2Renderer::getTotalTriangleCount() const {
return total;
}
std::optional<float> M2Renderer::getFloorHeight(float glX, float glY, float glZ) const {
std::optional<float> M2Renderer::getFloorHeight(float glX, float glY, float glZ, float* outNormalZ) const {
QueryTimer timer(&queryTimeMs, &queryCallCount);
std::optional<float> bestFloor;
float bestNormalZ = 1.0f; // Default to flat
glm::vec3 queryMin(glX - 2.0f, glY - 2.0f, glZ - 6.0f);
glm::vec3 queryMax(glX + 2.0f, glY + 2.0f, glZ + 8.0f);
@ -2745,12 +2746,13 @@ std::optional<float> M2Renderer::getFloorHeight(float glX, float glY, float glZ)
float hitZ = rayOrigin.z - tHit;
// Walkable normal check (world space)
glm::vec3 worldN(0.0f, 0.0f, 1.0f); // Default to flat
glm::vec3 localN = glm::cross(v1 - v0, v2 - v0);
float nLen = glm::length(localN);
if (nLen > 0.001f) {
localN /= nLen;
if (localN.z < 0.0f) localN = -localN;
glm::vec3 worldN = glm::normalize(
worldN = glm::normalize(
glm::vec3(instance.modelMatrix * glm::vec4(localN, 0.0f)));
if (std::abs(worldN.z) < 0.35f) continue; // too steep (~70° max slope)
}
@ -2758,6 +2760,7 @@ std::optional<float> M2Renderer::getFloorHeight(float glX, float glY, float glZ)
if (hitZ <= localPos.z + 3.0f && hitZ > bestHitZ) {
bestHitZ = hitZ;
hitAny = true;
bestNormalZ = std::abs(worldN.z); // Store normal for output
}
}
@ -2822,6 +2825,11 @@ std::optional<float> M2Renderer::getFloorHeight(float glX, float glY, float glZ)
}
}
// Output surface normal if requested
if (outNormalZ) {
*outNormalZ = bestNormalZ;
}
return bestFloor;
}