Fix gun viewmodel orientation: point the barrel forward, not at the player - #42
Merged
Merged
Conversation
…layer Both guns were mounted barrel-up in the knife rig's wrist frame, so with an identity transform the Deagle read as upside-down and both pointed back toward the player. Rather than guess Euler angles, compute the Gun mesh's correction analytically: reorient it (relative to its animated wrist parent) so the muzzle points along the viewmodel forward with a small downward pitch, and the top points up. The math is frame-invariant (camera + sway rotation cancel), so it holds as the player looks around and the idle animation plays. - New seatGunForward() seats each gun's barrel forward/up from a per-gun pitch and yaw (the AWP gets a slight yaw so a long rifle reads as a canted profile instead of a foreshortened pole). - Pulled the models closer and reframed so the hands sit like the knife reference, addressing 'hands too far away'. Verified in-engine (real ViewmodelRenderer harness) with a programmatic barrel/up direction probe: both guns read FORWARD + UPRIGHT. CI green (138 tests, typecheck, build).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
yassinsolim
added a commit
that referenced
this pull request
Jul 3, 2026
…at per frame (#43) Follow-up to #42. Two bugs remained that made the Deagle and AWP point at the ground: 1. Wrong barrel axis. The previous seat assumed the gun's muzzle was its local +Y axis. The real downloaded GLBs are authored with the standard glTF viewmodel convention — barrel along local -Z, up along local +Y (confirmed by measuring each Gun mesh's geometry: the longest extent is -Z). Forcing +Y forward therefore aimed the true barrel downward. seatGunForward now aligns the actual -Z/+Y axes to the target world forward/up. 2. One-time seat drifted. The seat was computed once at load, but the shared idle animation rotates the wrist every frame, so the barrel dipped as the hand moved. We now cache the Gun mesh and re-seat it every frame in update(), after the mixer moves the wrist — so the muzzle stays locked forward through the whole idle loop. gun.world is forced to the desired orientation each frame, which tracks the camera + sway (so the gun follows the view and sways) but ignores the idle wrist rotation (no drift). Also reframed both guns closer/tuned so the hands sit like the knife reference ('arms too far away'), and gave the AWP a sideways cant so a long rifle reads as a scoped profile instead of a foreshortened pole. Verified in the ACTUAL game (not just a harness): drove the real build with Playwright, enabled combat, switched to slot 2/3, and confirmed both guns point forward, upright, gripped — and stay forward while looking around (the frame-invariant seat holds). CI green (138 tests, typecheck, build).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
After #41 the guns rendered on the knife's gripping arms, but the orientation was wrong in-game: the Deagle read upside-down and pointed back toward the player, and the AWP (though upright) also pointed at the player. The hands also sat too far away.
Root cause: the
Gunmesh is authored barrel-up (+Y) in the knife rig's wrist frame, so an identity transform aims it at the ceiling/back, not forward.Fix
Instead of guessing Euler angles,
seatGunForward()computes the correction analytically: it reorients theGunmesh — relative to its animated wrist parent — so the muzzle (local +Y) points along the viewmodel forward (camera −Z) with a small downward pitch, and the top (local +Z) points up. Key property: the math is frame-invariant (the camera's world rotation and the per-frame sway cancel out), so the barrel keeps pointing where the player aims as they look around and the idle animation plays. The grip stays in the hand because the correction rotates about the gun's grip origin.barrelPitch/barrelYaw: the pistol aims essentially straight; the long rifle gets a slight yaw so it reads as a canted profile with a visible scope instead of a foreshortened pole.Verification
Built a faithful in-engine harness that drives the real
ViewmodelRendererexactly likeGameApp, with a programmatic barrel/up-direction probe (no more guessing from dark screenshots). Both guns now report FORWARD ✓ + UPRIGHT ✓ and screenshot correctly in POV and side views. Harness removed before commit.npm run cigreen: 138 tests, typecheck, build.Note
This is a focused 1-file change (
WeaponViewmodels.ts, +66/−6). Fire/reload still use the procedural recoil kick (the shared knife clip has no gun-specific segments) — unchanged from #41.