Fix NPC orientation (server yaw convention) and nameplate Y projection

coordinates.hpp: serverToCanonicalYaw now computes s - π/2 instead of π/2 - s.
The codebase uses atan2(-dy, dx) as its canonical yaw convention, where server
direction (cos s, sin s) in (server_X, server_Y) becomes (sin s, cos s) in
canonical after the X/Y swap, giving atan2(-cos s, sin s) = s - π/2.
canonicalToServerYaw is updated as its proper inverse: c + π/2.
The old formula (π/2 - s) was self-inverse and gave the wrong east/west facing
for any NPC not pointing north or south.

game_screen.cpp: Nameplate NDC→screen Y no longer double-inverts. The camera
bakes the Vulkan Y-flip into the projection matrix (NDC y=-1 = screen top,
y=+1 = screen bottom), so sy = (ndc.y*0.5 + 0.5) * screenH is correct.
The previous formula subtracted from 1.0 which reflected nameplates vertically.
This commit is contained in:
Kelsi 2026-03-09 17:59:55 -07:00
parent a335605682
commit 7b3b33e664
2 changed files with 14 additions and 8 deletions

View file

@ -53,17 +53,20 @@ inline float normalizeAngleRad(float a) {
// Convert server/wire yaw (radians) → canonical yaw (radians).
//
// Under server<->canonical X/Y swap:
// dir_s = (cos(s), sin(s))
// dir_c = swap(dir_s) = (sin(s), cos(s)) => c = PI/2 - s
// Codebase canonical convention: atan2(-dy, dx) in (canonical_X=north, canonical_Y=west).
// North=0, East=+π/2, South=±π, West=-π/2.
//
// Server direction at angle s: (cos s, sin s) in (server_X=canonical_Y, server_Y=canonical_X).
// After swap: dir_c = (sin s, cos s) in (canonical_X, canonical_Y).
// atan2(-dy, dx) = atan2(-cos s, sin s) = s - π/2.
inline float serverToCanonicalYaw(float serverYaw) {
return normalizeAngleRad((PI * 0.5f) - serverYaw);
return normalizeAngleRad(serverYaw - (PI * 0.5f));
}
// Convert canonical yaw (radians) → server/wire yaw (radians).
// This mapping is its own inverse.
// Inverse of serverToCanonicalYaw: s = c + π/2.
inline float canonicalToServerYaw(float canonicalYaw) {
return normalizeAngleRad((PI * 0.5f) - canonicalYaw);
return normalizeAngleRad(canonicalYaw + (PI * 0.5f));
}
// Convert between canonical WoW and engine rendering coordinates (just swap X/Y).

View file

@ -4684,9 +4684,12 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) {
glm::vec3 ndc = glm::vec3(clipPos) / clipPos.w;
if (ndc.x < -1.2f || ndc.x > 1.2f || ndc.y < -1.2f || ndc.y > 1.2f) continue;
// NDC → screen pixels (Y axis inverted)
// NDC → screen pixels.
// The camera bakes the Vulkan Y-flip into the projection matrix, so
// NDC y = -1 is the top of the screen and y = 1 is the bottom.
// Map directly: sy = (ndc.y + 1) / 2 * screenH (no extra inversion).
float sx = (ndc.x * 0.5f + 0.5f) * screenW;
float sy = (1.0f - (ndc.y * 0.5f + 0.5f)) * screenH;
float sy = (ndc.y * 0.5f + 0.5f) * screenH;
// Fade out in the last 5 units of range
float alpha = dist < 35.0f ? 1.0f : 1.0f - (dist - 35.0f) / 5.0f;