fix(example/game-2d): write ball radius in CSS pixels for WebGL/WebGPU parity - #140
Merged
Conversation
…U parity PR euv-dev#138 introduced DPR scaling inside `game_2d_ball_gpu_record` (writing `ball.radius * dpr` to the shader's pos_radius vec4). That was wrong: the shader's clip space is the same [-1, 1] NDC regardless of the backing store's physical size, so a CSS-unit radius already lands on `r * dpr` physical pixels via the viewport mapping. Multiplying by dpr in Rust made every WebGL/WebGPU ball render at `2 * radius` CSS pixels on a DPR=2 display, so the GPU tabs showed balls visibly twice as large as the Canvas 2D tab's SSAA output. With visual radius > physics radius, the per-ball "free space" looked huge and users reported the balls were no longer colliding. This change reverts the dpr multiplication: the radius is written in the same CSS-unit space as `ball.position`, which makes the visual ball size match the Canvas 2D path exactly (both end up as `radius` CSS pixels after the browser downscale of the physical backing to the element's CSS box) and makes the shader's per-ball disc the same size the physics solver is solving for, so the stacking/collision behavior the user saw in the Canvas 2D tab is restored in the WebGL/WebGPU tabs. The `dpr` parameter is preserved on the helper signature so callers keep their threaded-through arguments and a future change to the clip-space mapping assumption can be applied here without a wider signature change. Validated at DPR=2 headless: 2D / GL / GPU tabs now show visually identical ball sizes and the four initial balls settle into the same cluster at the canvas floor.
eastspire
added a commit
that referenced
this pull request
Sep 4, 2026
Includes: - #140 fix(example/game-2d): write ball radius in CSS pixels for WebGL/WebGPU parity CI's sync_workspace_version job will propagate the new root version to all sub-crates on master merge. Co-authored-by: eastspire <eastspire@users.noreply.github.com>
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.
fix(example/game-2d): write ball radius in CSS pixels for WebGL/WebGPU parity
PR #138 introduced DPR scaling inside
game_2d_ball_gpu_record(writingball.radius * dprto the shader's pos_radius vec4). That was wrong: the shader's clip space is the same [-1, 1] NDC regardless of the backing store's physical size, so a CSS-unit radius already lands onr * dprphysical pixels via the viewport mapping. Multiplying by dpr in Rust made every WebGL/WebGPU ball render at2 * radiusCSS pixels on a DPR=2 display, so the GPU tabs showed balls visibly twice as large as the Canvas 2D tab's SSAA output. With visual radius > physics radius, the per-ball "free space" looked huge and users reported the balls were no longer colliding.This change reverts the dpr multiplication: the radius is written in the same CSS-unit space as
ball.position, which makes the visual ball size match the Canvas 2D path exactly (both end up asradiusCSS pixels after the browser downscale of the physical backing to the element's CSS box) and makes the shader's per-ball disc the same size the physics solver is solving for, so the stacking/collision behavior the user saw in the Canvas 2D tab is restored in the WebGL/WebGPU tabs.The
dprparameter is preserved on the helper signature so callers keep their threaded-through arguments and a future change to the clip-space mapping assumption can be applied here without a wider signature change.Validated at DPR=2 headless: 2D / GL / GPU tabs now show visually identical ball sizes and the four initial balls settle into the same cluster at the canvas floor.