Raise all texture cache defaults from 1GB to 4GB to reduce rejections.
Cap cache-full warnings (texture + model) to 3 messages per renderer,
and cap update block parse errors to 5 messages.
Strip 26 chrono::now() timing calls per frame from renderer update loop,
periodic LOG_INFO/LOG_DEBUG from terrain/character/quest/heartbeat paths,
and dead m2ProfileCounter variable.
Strip per-frame/periodic logging from CharacterRenderer (batch dump,
instance count) and M2Renderer (frame timing profiler) to avoid
unnecessary string formatting and I/O in render loops.
Instead of relying on material flag 0x40 (F_CLAMP_S, not F_WINDOW) to
identify glass materials, detect windows by checking for "window" in the
texture path. This correctly applies glass to window textures while
leaving lamp posts and other geometry opaque.
Two WMO rendering fixes:
1. Glass batch merging: BatchKey didn't include isWindow, so window and
non-window batches sharing the same texture got merged together. If
the window batch was processed first, the entire merged batch (lamp
base, iron frame, etc.) rendered as transparent glass. Add isWindow
to the batch key so glass/non-glass batches stay separate.
2. LOD group culling: WMO groups named with "LOD" are distance-only
impostor geometry (e.g. cathedral tower extension, hill tower). They
should only render beyond 200 units. Store raw MOGN chunk for
offset-based name lookup, detect "lod" in group names during load,
and skip LOD groups in both main and shadow passes when camera is
within range.
F_SIDN (0x20) is the night-glow/self-illuminated flag, not a window
flag. Only F_WINDOW (0x40) should trigger transparent glass rendering.
The previous mask (0x60) caught both flags, making lamp post bases,
iron frames, and other SIDN-flagged surfaces render as transparent
glass with Fresnel reflections instead of opaque materials.
Hand-painted weapon/armor textures have baked-in lighting that produces
low-contrast gradients in the Sobel filter. Bump strength from 2.0 to
5.0 to extract visible surface detail. Also increase POM scale from
0.03 to 0.06 since character models are small with dense UVs where
the WMO-tuned 0.03 was barely perceptible.
Extends the WMO normal mapping/POM system to character M2 models with
bone-skinned tangents. Auto-generates normal/height maps from diffuse
textures using luminance→height, Sobel→normals (same algorithm as WMO).
- Expand vertex buffer from M2Vertex (48B) to CharVertexGPU (56B) with
tangent vec4 computed via Lengyel's method in setupModelBuffers()
- Tangents are bone-transformed and Gram-Schmidt orthogonalized in the
vertex shader, output as TBN for fragment shader consumption
- Fragment shader gains POM ray marching, normal map blending, and LOD
crossfade via dFdx/dFdy (identical to WMO shader)
- Descriptor set 1 extended with binding 2 for normal/height sampler
- Settings (enable, strength, POM quality) wired from game_screen.cpp
to both WMO and character renderers via shared UI controls
POM fixes: use blurred height only for ray march (keep crisp Sobel for
normals), reduce pomScale 0.03→0.012, clamp grazing angle denominator
to 0.15, hard-limit max UV offset, smooth fadeout at steep view angles.
Add Normal Map Strength slider (0.0-2.0) in Video settings for user
control over surface detail intensity. Persisted across sessions.
Generate normal+height maps from diffuse textures at load time using
luminance-to-height and Sobel 3x3 filtering. Compute per-vertex tangents
via Lengyel's method for TBN basis construction.
Fragment shader uses screen-space UV derivatives (dFdx/dFdy) for smooth
LOD crossfade and angle-adaptive POM sample counts. Flat textures
naturally produce low height variance, causing POM to self-select off.
Settings: Normal Mapping on by default, POM off by default with
Low/Medium/High quality presets. Persisted across sessions.
Dedicated Vulkan pipeline with alpha blending AND depth writes so
windows look transparent at oblique angles without see-through artifacts.
Fresnel alpha ranges from 0.4 (grazing) to 0.95 (head-on) with sun
glint, reflections, and silver-lining specular.
- Fix MLIQ vertex stride: each vertex is 8 bytes (4 flow + 4 height), not 4
- Use MLIQ tile flags to mask out tiles with no liquid (bridges, covered areas)
- Disable wave displacement on WMO water to prevent edge slosh artifacts
- Convert screen-space depth to vertical depth for shoreline foam and water
transparency, preventing false shoreline effects on occluding geometry
- Add underwater blue fog overlay and scene fog shift (terrain water only)
- Add getNearestWaterHeightAt to avoid false underwater detection from
elevated WMO water surfaces
- Tint refracted scene toward water color to mask occlusion edge artifacts
- Lower WMO water by 1 unit to match terrain water level
- Skybox now uses DBC sky colors (skyTop/skyMiddle/skyBand1/skyBand2) instead
of hardcoded C++ color curves, with 3-band gradient and Rayleigh/Mie scattering
- Clouds receive sun direction for lit edges, self-shadowing, and silver lining
- Fixed sun quad box artifact with proper edge fade in celestial shader
- Lens flare attenuated by fog, cloud density, and weather intensity
- Replaced garish green/purple lens flare ghosts with warm natural palette
- Added zone-based weather system for single-player mode with per-zone rain/snow
configuration, probability-based activation, and smooth intensity transitions
- Server SMSG_WEATHER remains authoritative when connected to a server
Water scene history textures and 1x pass resources were not recreated on
window resize/fullscreen, causing stale undersized textures that produced
directional transparency artifacts.
Player interaction ripples: vertex shader adds radial damped-sine displacement
centered on player position, fragment shader adds matching normal perturbation
for specular highlights. Player XY packed into shadowParams.zw, ripple strength
into fogParams.w. Separate 1x render pass for water when MSAA is active to
avoid MSAA-induced darkening — water renders after main pass resolves, using
the resolved swapchain image and depth resolve target. Water 1x framebuffers
rebuilt on swapchain recreate (window resize).
- Add .setMultisample() to minimap display pipeline and recreatePipelines() for MSAA changes
- Defer all swapchain recreation in window.cpp to beginFrame() via markSwapchainDirty()
to prevent mid-frame render pass destruction crashes on resolution/fullscreen change
- Move spawnPlayerCharacter() call to after loadTestTerrain() where character renderer exists
MSAA change was called mid-frame from settings UI, destroying the render pass
and framebuffers while the command buffer was still recording. Now deferred
via pendingMsaaSamples_ flag, applied in beginFrame() before any GPU state.
Also add +180° to M2 game object orientation to fix facing direction.
Replace all glGenTextures/glTexImage2D calls in UI code with Vulkan texture
uploads via new VkContext::uploadImGuiTexture() helper. This fixes segfaults
from calling OpenGL functions without a GL context (null GLEW function pointers).
- Add uploadImGuiTexture() to VkContext with staging buffer upload pattern
- Convert game_screen, inventory_screen, spellbook_screen, talent_screen
from GLuint/GL calls to VkDescriptorSet/Vulkan uploads
- Fix loading_screen clearValueCount (was 1, needs 2 or 3 for MSAA)
Render pass begin used 2 clear values but MSAA render pass has 3
attachments (MSAA color, depth, resolve). Vulkan requires clear
value count >= attachment count, causing a driver crash at 8x.
Also fix renderYawM2 reference removed in previous commit.
- Add error handling: revert to 1x if recreateSwapchain fails
- Clamp requested MSAA to device maximum before applying
- Retry MSAA color image allocation without TRANSIENT on failure
- Remove redundant vkDeviceWaitIdle from WMO/M2/Character recreatePipelines
(caller already waits once, was causing ~13 stalls instead of 1)
Skybox: replace sphere-mesh approach with a fullscreen triangle that
reconstructs the world-space ray direction analytically via inverse
projection/view matrices. Eliminates clip.w=0 degeneracy at the horizon
and correctly maps altitude to dir.z in the Z-up coordinate system.
Clouds: hemisphere mesh was storing altitude in aPos.y (Y-up convention);
the Z-up view matrix projected this sideways, making clouds appear
vertical. Store altitude in aPos.z and update the fragment shader to
read dir.z as altitude and dir.xy as the horizontal UV plane.
- renderWorld() now calls wmoRenderer, characterRenderer, m2Renderer (+smoke,
particles) in the correct opaque→transparent order; water moved after all
opaques; per-subsystem timing active in live path
- Deleted the 310-line #if 0 GL stub block and removed #include <GL/glew.h>
(last GL reference in renderer.cpp)
- Full-screen overlay pipeline (postprocess.vert + overlay.frag, alpha blend,
no depth test/write) for underwater tint; lazily initialized, renders a blue
tint when camera is meaningfully below the water surface; canal vs open-water
tint colours preserved from original design
- overlay.frag.glsl / overlay.frag.spv added
- anchor flare sun position to camera + sun direction to match celestial billboard projection
- remove world-space parallax drift that caused flare/sun misalignment while moving
- drive shadow light direction from live LightingManager directionalDir
- normalize shadow light to downward-facing convention with grazing-angle guard
- make celestial/sky sun placement robust to directionalDir convention mismatches
- keep visible sun above horizon while preserving shadow alignment
- render sun with alpha blend while keeping moon additive glow
- add dedicated always-running sun haze timer (decoupled from moon phase cycling)
- constrain sun sprite with radial alpha mask and low-alpha discard to remove square artifact
- tune sun tint warmer without over-yellowing
- replace noisy/pulsing haze with slower flow-warp turbulence and lower amplitude
- make cloud mask transition broader for less distinct cutout edges
- increase high-frequency noise contribution for grainier cloud breakup
- apply edge-band fringe modulation with stronger feathering
- lower and remap final alpha to blend cloud boundaries more naturally into the sky
- ensure player transform sync is not gated by third-person so player shadow stays consistent
- hold shadow projection center during movement and snap once on stop to remove delayed catch-up
- smooth foliage caster transitions using blended phase-shifted UV samples
- tune foliage motion frequencies/amplitudes for less popping
- increase shadow map resolution to 2048 and retune terrain PCF texel scale
- increase global shadow strength from 0.62 to 0.68 for stronger, clearer shadows
- keep shadow projection center fixed while moving to remove per-frame projection churn flicker
- replace delayed post-move catch-up with immediate stop transition and idle smoothing
- rework foliage shadow caster motion to use blended phase-shifted UV samples for continuous position transitions
- reduce high-frequency foliage threshold popping by removing threshold warping path
- sharpen terrain receive filtering with tuned 5-tap PCF weights/offset for more detailed shadows
- raise shadow map resolution to 1536 and keep light-space texel snapping for stable sampling
- set shadows enabled by default and lower global shadow strength from 0.65 to 0.62
- keep foliage animation speed consistent between moving and idle at 80%