-
Notifications
You must be signed in to change notification settings - Fork 0
Graphics
Home · World · Configuration · Technical-Overview
The main game builds a Three.js scene imperatively inside App.tsx, with React used for UI and application state. The project declares React Three Fiber and Drei dependencies, but the live game scene is created and updated through the native Three.js renderer path.
Rendering features include shadow-mapped lighting, procedural sky/haze shaders, map-aware terrain materials, HDR environment lighting, particles, full first-person viewmodels, enemy LOD, and a custom post-processing stack.
- Continuous day/dawn/day/dusk/twilight/night interpolation with a moving sun/moon arc.
- Per-map directional/ambient/fog settings and render profiles.
- Environment reflections from Poly Haven HDRIs when the active quality path allows it; lower performance paths use a cheaper local fallback.
- Custom sky dome with drifting cloud, sun/moon, star, and haze behavior.
- Weather particle fields for climate events such as rain, snow, ash, sandstorms, spores, and wisps.
When post-processing is enabled, the pipeline includes render pass, Unreal Bloom, cinematic grading, and quality-dependent anti-aliasing. The custom grade shader supports:
- ACES filmic tonemapping and exposure.
- Volumetric-style sun shafts / god rays.
- Chromatic aberration, film halation, vignette, grain, scanline, and split tone.
- Highlight recovery/desaturation for bright snow and sand maps.
- Aerial perspective, vibrance, shadow lift/deepening, local clarity, lens dirt, and optional anamorphic streaks.
- CAS adaptive sharpening as the final pass.
Ultra quality enables the most expensive optical effects; low and ultra-low disable shadows and post-processing.
Weapons are custom constructed first-person models with gloved hands. They animate idle sway, walk/run bob, ADS, recoil, reloads, inspection, strafe lean, jumps/landings, class abilities, and Phantom fading. The Subverter has its own animated code screen, chip bay, emitter, and reload animation.
Every weapon material is generated at runtime from canvas-baked detail maps — the project ships no image texture assets at all. The pipeline has three parts:
- Normal maps. Each surface finish bakes a real tangent-space normal map by Sobel-filtering its height canvas, replacing the earlier bump map. Bump derives a normal from a height gradient per pixel, which produces noise rather than features and barely responds to image-based lighting — and with environment intensity at 1.25 under an HDRI, IBL is most of what lights the viewmodel, so most of that detail was invisible in the lighting the game actually uses. The original height is retained in the map's alpha channel.
- Per-weapon finishes. Six finishes (machined metal, worn metal, blued metal, polymer, coarse polymer, and wood) replace the three that every weapon previously shared. The pistol and sniper read as cared-for blued steel, the shotgun and minigun as beaten service hardware, the launcher as coarse moulded composite. This costs zero additional shader programs — only the texture contents differ.
- Constant texel density. The rig mixes three geometry sources with three incompatible UV conventions, so a single tiling value previously meant three different scales across one weapon and smeared along long barrels. Every part now passes through a per-vertex triplanar UV rewrite keyed to world size, so a 0.3-unit rail and a 6-unit barrel finally agree, and all finish textures sit at a 1:1 repeat.
Contact darkening in crevices is provided by a shared cavity term injected into the standard material, sampling the height already stored in the normal map's alpha. A depth-based ambient-occlusion pass was rejected: it needs a prepass in a chain that is disabled entirely on low presets, and the viewmodel sits at a wildly different depth scale from the world, so a radius tuned for a weapon at arm's length haloes the scenery behind it. Because the injection is a single shared function with a constant program cache key, it adds exactly one shader program rather than one per material.
Enemies have detailed low-poly shells, glow components, arm/leg movement, hit reactions, head tracking, death behavior, and high/medium/low LOD. Remote players are full-body low-poly models with weapon poses, crouch, aim, walk, death, nameplate, and health-bar animation.
Combat visuals include muzzle flashes, tracers, smoke, shell casings, impact sparks, blood/robot hit feedback, explosions, craters, shockwaves, lightning, hack beams, freezes, nuke clouds, damage flashes, and screen shake.
The muzzle flash is anchored to an empty marker placed at each weapon's actual bore exit and parented into the weapon rig, so it inherits recoil, sway, ADS, and reload poses automatically. It previously spawned at the viewmodel root — which is not the muzzle of any weapon — putting the flash and its smoke roughly 1.7 units behind the sniper's barrel tip. The flash texture is a seven-point irregular star with a tight near-white core rather than a plain radial gradient, and each shot randomizes its roll and size so sustained fire does not read as one repeated stamp.
Bullets are modelled as tracer rounds rather than glowing spheres: a small near-white capsule head, a cone tail tapering backward along the flight axis from amber to deep orange, and a faint sleeve for the bloom pass to catch. The colour gradient is that of something burning rather than one flat yellow. Each round is aimed along its velocity at spawn — an earlier elongated projectile was reverted for appearing to curve in flight, which was an orientation bug rather than a shape problem, since the geometry pointed a fixed direction while the round travelled elsewhere.
With ragdolls enabled, solo enemy corpses use a lazy-loaded Rapier rigid-body world. It caps active bodies at 20 and falls back to a lightweight custom launcher if Rapier is not ready or in multiplayer.
- Graphics settings drive resolution scale, shadow size, MSAA, post-processing, particle density, draw distance, terrain density, and enemy cap.
- Terrain chunks and static props are streamed/instanced.
- Enemy meshes are pooled with shared geometry/materials and LOD at 45/70/100 units.
- Dynamic pickup/explosion lighting uses preallocated light pools to avoid shader recompilation during combat.
- Shader warmup precompiles major visual paths before gameplay begins.
Implementation references: src/App.tsx, src/utils/PostProcessing.ts, src/utils/Shaders.ts, src/utils/TerrainSystem.ts, src/utils/HDRIEnvironment.ts, src/utils/SmartEnemyManager.ts, src/utils/RagdollSystem.ts, src/utils/GunModel.ts.