Fix taxi startup/attachment and reduce taxi streaming hitches

This commit is contained in:
Kelsi 2026-02-11 19:28:15 -08:00
parent f752a4f517
commit 38cef8d9c6
11 changed files with 396 additions and 190 deletions

View file

@ -112,17 +112,12 @@ void CameraController::update(float deltaTime) {
return;
}
// During taxi flights, skip input/movement logic but still position camera
// During taxi flights, skip movement logic but keep camera orbit/zoom controls.
if (externalFollow_) {
// Mouse look (right mouse button)
if (rightMouseDown) {
int mouseDX, mouseDY;
SDL_GetRelativeMouseState(&mouseDX, &mouseDY);
yaw -= mouseDX * mouseSensitivity;
pitch -= mouseDY * mouseSensitivity;
pitch = glm::clamp(pitch, -89.0f, 89.0f);
camera->setRotation(yaw, pitch);
}
camera->setRotation(yaw, pitch);
float zoomLerp = 1.0f - std::exp(-ZOOM_SMOOTH_SPEED * deltaTime);
currentDistance += (userTargetDistance - currentDistance) * zoomLerp;
collisionDistance = currentDistance;
// Position camera behind character during taxi
if (thirdPerson && followTarget) {

View file

@ -125,12 +125,9 @@ void Celestial::shutdown() {
void Celestial::render(const Camera& camera, float timeOfDay,
const glm::vec3* sunDir, const glm::vec3* sunColor, float gameTime) {
if (!renderingEnabled || vao == 0 || !celestialShader) {
LOG_WARNING("Celestial render blocked: enabled=", renderingEnabled, " vao=", vao, " shader=", (celestialShader ? "ok" : "null"));
return;
}
LOG_INFO("Celestial render: timeOfDay=", timeOfDay, " gameTime=", gameTime);
// Update moon phases from game time if available (deterministic)
if (gameTime >= 0.0f) {
updatePhasesFromGameTime(gameTime);
@ -166,22 +163,16 @@ void Celestial::renderSun(const Camera& camera, float timeOfDay,
const glm::vec3* sunDir, const glm::vec3* sunColor) {
// Sun visible from 5:00 to 19:00
if (timeOfDay < 5.0f || timeOfDay >= 19.0f) {
LOG_INFO("Sun not visible: timeOfDay=", timeOfDay, " (visible 5:00-19:00)");
return;
}
LOG_INFO("Rendering sun: timeOfDay=", timeOfDay, " sunDir=", (sunDir ? "yes" : "no"), " sunColor=", (sunColor ? "yes" : "no"));
celestialShader->use();
// TESTING: Try X-up (final axis test)
glm::vec3 dir = glm::normalize(glm::vec3(1.0f, 0.0f, 0.0f)); // X-up test
LOG_INFO("Sun direction (TESTING X-UP): dir=(", dir.x, ",", dir.y, ",", dir.z, ")");
glm::vec3 dir = sunDir ? glm::normalize(*sunDir) : glm::vec3(0.0f, 0.0f, 1.0f);
// Place sun on sky sphere at fixed distance
const float sunDistance = 800.0f;
glm::vec3 sunPos = dir * sunDistance;
LOG_INFO("Sun position: dir * ", sunDistance, " = (", sunPos.x, ",", sunPos.y, ",", sunPos.z, ")");
// Create model matrix
glm::mat4 model = glm::mat4(1.0f);

View file

@ -957,13 +957,9 @@ void Renderer::updateCharacterAnimation() {
// Sync mount instance position and rotation
float mountBob = 0.0f;
float mountYawRad = glm::radians(characterYaw);
if (mountInstanceId_ > 0) {
characterRenderer->setInstancePosition(mountInstanceId_, characterPosition);
float yawRad = glm::radians(characterYaw);
if (taxiFlight_) {
// Taxi mounts commonly use a different model-forward axis than player rigs.
yawRad += 1.57079632679f;
}
// Procedural lean into turns (ground mounts only, optional enhancement)
if (!taxiFlight_ && moving && lastDeltaTime_ > 0.0f) {
@ -982,7 +978,7 @@ void Renderer::updateCharacterAnimation() {
}
// Apply pitch (up/down), roll (banking), and yaw for realistic flight
characterRenderer->setInstanceRotation(mountInstanceId_, glm::vec3(mountPitch_, mountRoll_, yawRad));
characterRenderer->setInstanceRotation(mountInstanceId_, glm::vec3(mountPitch_, mountRoll_, mountYawRad));
// Drive mount model animation: idle when still, run when moving
auto pickMountAnim = [&](std::initializer_list<uint32_t> candidates, uint32_t fallback) -> uint32_t {
@ -1172,7 +1168,42 @@ void Renderer::updateCharacterAnimation() {
}
}
// Use mount's attachment point for proper bone-driven rider positioning
// Use mount's attachment point for proper bone-driven rider positioning.
if (taxiFlight_) {
glm::mat4 mountSeatTransform(1.0f);
bool haveSeat = false;
static constexpr uint32_t kTaxiSeatAttachmentId = 0; // deterministic rider seat
if (mountSeatAttachmentId_ == -1) {
mountSeatAttachmentId_ = static_cast<int>(kTaxiSeatAttachmentId);
}
if (mountSeatAttachmentId_ >= 0) {
haveSeat = characterRenderer->getAttachmentTransform(
mountInstanceId_, static_cast<uint32_t>(mountSeatAttachmentId_), mountSeatTransform);
}
if (!haveSeat) {
mountSeatAttachmentId_ = -2;
}
if (haveSeat) {
glm::vec3 targetRiderPos = glm::vec3(mountSeatTransform[3]) + glm::vec3(0.0f, 0.0f, 0.02f);
// Taxi passengers should be rigidly parented to mount attachment transforms.
// Smoothing here introduces visible seat lag/drift on turns.
mountSeatSmoothingInit_ = false;
smoothedMountSeatPos_ = targetRiderPos;
characterRenderer->setInstancePosition(characterInstanceId, targetRiderPos);
} else {
mountSeatSmoothingInit_ = false;
glm::vec3 playerPos = characterPosition + glm::vec3(0.0f, 0.0f, mountHeightOffset_ + 0.10f);
characterRenderer->setInstancePosition(characterInstanceId, playerPos);
}
float riderPitch = mountPitch_ * 0.35f;
float riderRoll = mountRoll_ * 0.35f;
characterRenderer->setInstanceRotation(characterInstanceId, glm::vec3(riderPitch, riderRoll, mountYawRad));
return;
}
// Ground mounts: try a seat attachment first.
glm::mat4 mountSeatTransform;
bool haveSeat = false;
if (mountSeatAttachmentId_ >= 0) {

View file

@ -146,14 +146,11 @@ void SkySystem::render(const Camera& camera, const SkyParams& params) {
}
glm::vec3 SkySystem::getSunPosition(const SkyParams& params) const {
// TESTING: X-up test
glm::vec3 dir = glm::vec3(1.0f, 0.0f, 0.0f); // X-up
glm::vec3 pos = dir * 800.0f;
static int counter = 0;
if (counter++ % 100 == 0) {
LOG_INFO("Flare TEST X-UP dir=(", dir.x, ",", dir.y, ",", dir.z, ") pos=(", pos.x, ",", pos.y, ",", pos.z, ")");
glm::vec3 dir = glm::normalize(params.directionalDir);
if (glm::length(dir) < 0.0001f) {
dir = glm::vec3(0.0f, 0.0f, 1.0f);
}
glm::vec3 pos = dir * 800.0f;
return pos;
}

View file

@ -115,9 +115,10 @@ bool TerrainManager::initialize(pipeline::AssetManager* assets, TerrainRenderer*
return false;
}
// Set dynamic tile cache budget (use other half of recommended budget)
// Set dynamic tile cache budget.
// Keep this lower so decompressed MPQ file cache can stay very aggressive.
auto& memMonitor = core::MemoryMonitor::getInstance();
tileCacheBudgetBytes_ = memMonitor.getRecommendedCacheBudget() / 2;
tileCacheBudgetBytes_ = memMonitor.getRecommendedCacheBudget() / 4;
LOG_INFO("Terrain tile cache budget: ", tileCacheBudgetBytes_ / (1024 * 1024), " MB (dynamic)");
// Start background worker pool (dynamic: scales with available cores)
@ -222,7 +223,7 @@ bool TerrainManager::enqueueTile(int x, int y) {
{
std::lock_guard<std::mutex> lock(queueMutex);
loadQueue.push(coord);
loadQueue.push_back(coord);
pendingTiles[coord] = true;
}
queueCV.notify_all();
@ -791,7 +792,7 @@ void TerrainManager::workerLoop() {
if (!loadQueue.empty()) {
coord = loadQueue.front();
loadQueue.pop();
loadQueue.pop_front();
hasWork = true;
}
}
@ -1056,7 +1057,7 @@ void TerrainManager::unloadAll() {
// Clear queues
{
std::lock_guard<std::mutex> lock(queueMutex);
while (!loadQueue.empty()) loadQueue.pop();
while (!loadQueue.empty()) loadQueue.pop_front();
while (!readyQueue.empty()) readyQueue.pop();
}
pendingTiles.clear();
@ -1353,7 +1354,7 @@ void TerrainManager::streamTiles() {
if (pendingTiles.find(coord) != pendingTiles.end()) continue;
if (failedTiles.find(coord) != failedTiles.end()) continue;
loadQueue.push(coord);
loadQueue.push_back(coord);
pendingTiles[coord] = true;
}
}
@ -1409,7 +1410,9 @@ void TerrainManager::precacheTiles(const std::vector<std::pair<int, int>>& tiles
if (pendingTiles.find(coord) != pendingTiles.end()) continue;
if (failedTiles.find(coord) != failedTiles.end()) continue;
loadQueue.push(coord);
// Precache work is prioritized so taxi-route tiles are prepared before
// opportunistic radius streaming tiles.
loadQueue.push_front(coord);
pendingTiles[coord] = true;
}