Add transport system, fix NPC spawning, and improve water rendering

Transport System (Phases 1-7):
- Implement TransportManager with Catmull-Rom spline path interpolation
- Add WMO dynamic transforms for moving transport instances
- Implement player attachment via world position composition
- Add test transport with circular path around Stormwind harbor
- Add /transport board and /transport leave console commands
- Reuse taxi flight spline system and external follow camera mode

NPC Spawn Fixes:
- Add smart ocean spawn filter: blocks land creatures at high altitude over water (Z>50)
- Allow legitimate water creatures at sea level (Z≤50) to spawn correctly
- Fixes Elder Grey Bears, Highland Striders, and Plainscreepers spawning over ocean
- Snap online creatures to terrain height when valid ground exists

NpcManager Removal:
- Remove deprecated NpcManager (offline mode no longer supported)
- Delete npc_manager.hpp and npc_manager.cpp
- Simplify NPC animation callbacks to use only creatureInstances_ map
- Move NPC callbacks to game initialization in application.cpp

Water Rendering:
- Fix tile seam gaps caused by per-vertex wave randomization
- Add distance-based blending: seamless waves up close (<150u), grid effect far away (>400u)
- Smooth transition between seamless and grid modes (150-400 unit range)
- Preserves aesthetic grid pattern at horizon while eliminating gaps when swimming
This commit is contained in:
Kelsi 2026-02-10 21:29:10 -08:00
parent c91e0bb916
commit 2e923311d0
13 changed files with 711 additions and 1079 deletions

View file

@ -39,6 +39,7 @@ bool WaterRenderer::initialize() {
uniform float waveAmp;
uniform float waveFreq;
uniform float waveSpeed;
uniform vec3 viewPos;
out vec3 FragPos;
out vec3 Normal;
@ -48,19 +49,30 @@ bool WaterRenderer::initialize() {
void main() {
vec3 pos = aPos;
// Pseudo-random phase offsets to break up regular pattern
// Distance from camera for LOD blending
float dist = length(viewPos - aPos);
float gridBlend = smoothstep(150.0, 400.0, dist); // 0=close (seamless), 1=far (grid effect)
// Seamless waves (continuous across tiles)
float w1_seamless = sin((aPos.x + time * waveSpeed) * waveFreq) * waveAmp;
float w2_seamless = cos((aPos.y - time * (waveSpeed * 0.78)) * (waveFreq * 0.82)) * (waveAmp * 0.72);
float w3_seamless = sin((aPos.x * 1.7 - time * waveSpeed * 1.3 + aPos.y * 0.3) * waveFreq * 2.1) * (waveAmp * 0.35);
float w4_seamless = cos((aPos.y * 1.4 + time * waveSpeed * 0.9 + aPos.x * 0.2) * waveFreq * 1.8) * (waveAmp * 0.28);
// Grid effect waves (per-vertex randomization for distance view)
float hash1 = fract(sin(dot(aPos.xy, vec2(12.9898, 78.233))) * 43758.5453);
float hash2 = fract(sin(dot(aPos.xy, vec2(93.9898, 67.345))) * 27153.5328);
float w1_grid = sin((aPos.x + time * waveSpeed + hash1 * 6.28) * waveFreq) * waveAmp;
float w2_grid = cos((aPos.y - time * (waveSpeed * 0.78) + hash2 * 6.28) * (waveFreq * 0.82)) * (waveAmp * 0.72);
float w3_grid = sin((aPos.x * 1.7 - time * waveSpeed * 1.3 + hash1 * 3.14) * waveFreq * 2.1) * (waveAmp * 0.35);
float w4_grid = cos((aPos.y * 1.4 + time * waveSpeed * 0.9 + hash2 * 3.14) * waveFreq * 1.8) * (waveAmp * 0.28);
// Multiple wave octaves with randomized phases for natural variation
float w1 = sin((aPos.x + time * waveSpeed + hash1 * 6.28) * waveFreq) * waveAmp;
float w2 = cos((aPos.y - time * (waveSpeed * 0.78) + hash2 * 6.28) * (waveFreq * 0.82)) * (waveAmp * 0.72);
// Add higher frequency detail waves (smaller amplitude)
float w3 = sin((aPos.x * 1.7 - time * waveSpeed * 1.3 + hash1 * 3.14) * waveFreq * 2.1) * (waveAmp * 0.35);
float w4 = cos((aPos.y * 1.4 + time * waveSpeed * 0.9 + hash2 * 3.14) * waveFreq * 1.8) * (waveAmp * 0.28);
float wave = w1 + w2 + w3 + w4;
// Blend between seamless (close) and grid (far)
float wave = mix(
w1_seamless + w2_seamless + w3_seamless + w4_seamless,
w1_grid + w2_grid + w3_grid + w4_grid,
gridBlend
);
pos.z += wave;
FragPos = vec3(model * vec4(pos, 1.0));