Path tracing toggle: F9 cycle, CLI overrides, render scale 0.75 - #11
Conversation
…H-046) Every alien and the player rendered with a base colour texture and NOTHING else: no normal map, no roughness map, flat roughness 0.9 / metallic 0. They read as matte toys standing on a terrain that has triplanar PBR and a detail normal. It was the weakest surface in frame. The Unvanquished source ships authored _n (normal) and _s (specular) maps for every single character. convert-aliens-anim.ts only ever read the diffuse. It now reads all three, so this cost nothing but the reading of it. _s -> metallicRoughness is NOT a swap, and getting it wrong is what the tuning in here is about. A Quake-lineage spec map stores specular INTENSITY; glTF wants ROUGHNESS in green and METALNESS in blue. Mapping intensity straight to gloss — my first attempt — drove bright texels to roughness ~0 and the battlesuit came out looking wet. The mapping is now conservative: roughness spans 1.0 -> 0.35, never a mirror. The point is surface VARIATION, which there was none of; it is not to make anything glossy. The battlesuit alone takes metalness from the spec map. It is armour plate, and a dielectric with a tight white highlight reads as wet plastic — metalness is what makes it read as metal, because the reflection is tinted by the base colour rather than staying white. The aliens stay dielectric: metallic chitin looks like tinfoil. The _adv upgrade skins ship no _n/_s of their own (they are recolours of the base on the same mesh and UVs), so they borrow the base skin's maps. Also lands docs/asset-sourcing.md — where better free animated models can actually come from. The headline finding is uncomfortable and worth keeping: our five DISTINCT NON-HUMANOID creatures with full animation sets are precisely the asset class that does not exist for free. The free ecosystem is rich in humanoid animation libraries and stylized low-poly monsters, and thin in exactly what we already have. Also: D3 freed us on licence but NOT on redistribution — a git repo IS redistribution, which rules Mixamo out as repo content no matter the licence. Verified by screenshot at 4K, cropped: plate definition and edge wear where there was flat matte, and no wet look after the retune. ~0.5 MB per model. Claude-Session: https://claude.ai/code/session_01V3MihNxaRwMR8GjMPvMkRb
…SH-036 / A4) Six real tracks in, mastered, and the game streams them. SH-036 is closed. Suno ignored two things. LENGTH, comprehensively: asked for 60-90 s beds and 2-4 s stingers; got 162/73/195 s beds and 9/24/49 s "stingers". tools/music-master.ts handles it. Note the victory sting's swell does not LAND until 0:29 — "take the first 4 seconds" would have shipped an intro. The stinger windows are read off the rendered waveforms (tools/music-inspect.ts), not guessed. KEY: asked for D minor, got A# minor — and it does not matter, for exactly the reason the rule existed. The beds are keyed to EACH OTHER, which is the only thing the crossfade cares about. That is VERIFIED, not assumed: estimateKey() runs a chroma + Krumhansl-Schmuckler estimate and calm, combat and menu all agree. Had they disagreed the crossfade would have been unfixable and they'd need regenerating — which is why the tool checks rather than trusting the prompt. The loop point is SEARCHED, not assumed. Candidate (start, length) pairs are scored by how similar the music actually sounds at `start` and at `start + length`, which is what makes a crossfade inaudible, and which self-corrects tempo error. That last part matters: at hop 512 the autocorrelation bins around 120 BPM are 119.7 and 122.3, so calm and combat — both 120 — landed in DIFFERENT BINS and appeared to disagree by 2%. I nearly time-stretched a track that did not need it. Parabolic interpolation now resolves that, and the search does not depend on it anyway. Also: candidates step by the BAR (a seam anywhere else is mid-bar and no crossfade saves it); loops containing the intro/outro fade are rejected (they would get quieter every wrap); and among acceptable seams the LONGEST loop wins — I first wrote a scoring function that traded a 63 s loop for a 31 s one to buy a 1 dB seam improvement nobody could hear. A short loop is a cost the player notices. Result: calm 63.1 s, combat 47.8 s, menu 55.9 s, all seams verified (wrap-jump vs p99 sample delta, and level either side of the join within 3 dB). Stingers 4-5 s, all ending in true silence. bun tools/music-loopcheck.ts writes each loop played TWICE with the join at the midpoint — the only test that really counts is whether a human can hear it, so the tool exists to let one try. Raw renders kept in assets/music/src/; mastering is re-runnable and never touches them. assets/music/*.wav is build output — edit the tool, not the files. Claude-Session: https://claude.ai/code/session_01V3MihNxaRwMR8GjMPvMkRb
… with the floor Reported as "the animation is not there, the player just slides". The animation was playing the entire time. The thresholds were wrong. The clip was picked by crossing a speed threshold: run above 7.0 m/s, else walk. But MOVE_SPEED is 6.0, so normal movement ALWAYS took the walk clip — and the walk clip is authored for ~2.6 m/s. Covering 6 m/s of ground with it meant playing it at the 2.2x clamp, and even at the clamp the stride only covers ~5.7 m/s. So the feet could never keep up with the ground. That is the slide: a walk cycle at double speed, permanently behind the floor. Sprint (9.0 target, ~7.4 measured) only just cleared 7.0, so the run clip flickered at the boundary instead of being a state you could feel. Hence "shift doesn't run". Fixed twice, and the second one is the real fix: 1. The clip follows what the player is DOING — isSprinting() runs, moving walks, standing idles. No threshold to sit on. (isSprinting() was exported by player.ts and imported by nobody. That was the clue.) 2. MOVE_SPEED 6.0 -> 4.5. Six metres per second is a RUN speed wearing a walk animation, and no amount of clip selection fixes that. SPRINT_MUL 1.5 -> 2.0 absorbs it, so TOP SPEED IS STILL 9.0 m/s — nothing about outrunning a dragoon pounce or a mantis dart has changed. Only the cruise is slower, and now holding shift is the difference between a walk and a run. The clamp is the canary: playback rate is (actual speed / authored clip speed), and if that ratio ever REACHES the clamp then the movement speed and the clip no longer belong together — the fix is the speed constant, not a wider clamp. Measured after the change: walk ~1.4x, sprint ~1.1x, both well inside it. Diagnosed by making the game auto-start and walk itself on rails, then logging playerSpeed() from the loop — playerSpeed() was returning 4.8-5.3 the whole time, which killed the obvious theory (a Perry miscompile of a one-line getter) before I could waste a day on it. Claude-Session: https://claude.ai/code/session_01V3MihNxaRwMR8GjMPvMkRb
TEX_MAX was 512. The Unvanquished source is 2048² (player) and 4096² (aliens). We have been shipping every character at a fraction of its authored detail, on models the camera is rarely more than a few metres from. Now 1024 for the aliens, 2048 for the player — it is on screen 100% of the time and earns more. 4x the texels on the aliens, 16x on the player. Cost: none that matters. 53 fps before, 53 fps after. This was never fill-bound, it was texture-starved. Models grew 28 MB -> 65 MB on disk. Between this and the normal/spec maps that landed earlier today, the characters now carry roughly 64x the surface information they did this morning, and not one byte of it was downloaded — it was all sitting in vendor/. SH-046 part 2 (replace the player character) is closed as WON'T-DO, and this time on evidence rather than a guess: searched Sketchfab authenticated via the Download API, across cc0/by/by-sa, downloadable+animated, ten queries, 43 candidates. The realistic ones ship 3-5 animations. The well-animated ones are low-poly stylized. The one high-poly well-animated hit is a Black Myth: Wukong rip — someone else's IP whatever the licence label says. The battlesuit has 34 purpose-built clips (idle, walk, run, 4 strafes, 5 crouch states, jump, land, pain, die, attack, per-weapon pose deltas). Trading that for a 4-animation astronaut is trading a complete locomotion set for a prettier T-pose. Claude-Session: https://claude.ai/code/session_01V3MihNxaRwMR8GjMPvMkRb
Joins the F5-F8 render-pass toggle bar. Shows 'n/a' and stays inert on devices without hardware ray query. The engine-side modes are landing on engine branch feat/path-tracer.
Re-measured on the 4K dev box after the engine perf rounds: 0.5 reads visibly upscale-soft (the user called it out), 0.75 is dramatically sharper at ~30 fps raster, 1.0 (~19 fps) stays selectable in the video menu for stills. Mobile keeps 0.5. The PT realtime ray budget is decoupled engine-side so path tracing does not slow down with this.
--render-scale 0.25|0.5|0.75|1 and --output-scale (same steps) override settings.json for one launch; --pt prog|rt starts in that path-tracing mode without F9 taps. Values are string-matched, never parsed (perry-quirks #5). Verified: launch with --pt rt --render-scale 0.25 shows HUD PT RT v9 and a visibly quarter-res image, no keys pressed. Claude-Session: https://claude.ai/code/session_018574BdCfSjdpNK3WLgx1hP
|
Warning Review limit reached
Next review available in: 59 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (12)
📒 Files selected for processing (20)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Game-side integration for the engine hardware path tracer (Bloom-Engine/engine#92):
--render-scale 0.25|0.5|0.75|1,--output-scale(same steps),--pt prog|rt. Values are string-matched, never parsed (perry-quirks Round-2 integration: gameplay + flicker fixes land in main #5); they land in the live settings array so the video menu reflects them.Verification
main.exe --pt rt --render-scale 0.25: HUD reads the injected mode with zero keypresses and the image shows the quarter-res scale.https://claude.ai/code/session_018574BdCfSjdpNK3WLgx1hP