Skip to content

WebGPU 3D tier + full backend parity, spine on WebGPU — 20.0.0 (#1184, #1536) - #1564

Merged
obiot merged 2 commits into
masterfrom
webgpu-3d-tier
Aug 5, 2026
Merged

WebGPU 3D tier + full backend parity, spine on WebGPU — 20.0.0 (#1184, #1536)#1564
obiot merged 2 commits into
masterfrom
webgpu-3d-tier

Conversation

@obiot

@obiot obiot commented Aug 5, 2026

Copy link
Copy Markdown
Member

Completes the WebGPU renderer (#1184): the full 3D tier, the remaining backend-parity surface, point/spot 3D lights (#1536), custom mesh shaders on both GPU backends, and a WebGPU spine batcher with full two-color tinting. With this, video.AUTO defaults to WebGPU → WebGL 2 → Canvas and every engine feature renders identically on both GPU backends (all 44 examples verified side-by-side, headed).

Engine (packages/melonjs)

3D tier on WebGPU

  • drawMesh through unlit/lit WGSL mesh pipelines: retained model-space geometry under Camera3d (upload once; placement/tint/alpha-cutoff/emissive ride one per-draw uniform snapshot) plus the CPU-projected 2D-camera path; per-mesh cull/winding as pipeline state; supportsDepthBuffer / supportsRetainedMesh now true
  • depth realized as the render pass's load/store ops — one depth clear per target per frame (GL policy); pure-2D applications keep byte-identical passes
  • glTF scenes/animation, Sprite3d billboards and split-screen Camera3d viewports run unchanged on top

Lighting (#1536)

  • Light3d gains "point" and "spot" on both backends: 12-float std140 light entries, quadratic-over-range falloff (the Light2d model — deliberately not physical inverse-square), smooth-edged cones, runtime-mutable fields
  • glTF loader instantiates all three punctual types (scene-scaled position/range/cones), copies authored light names onto the Light3d (getChildByName("Sun")), and gains a lightIntensityScale load option; lamp-only scenes now correctly flag their meshes lit

Custom mesh shaders

  • GLShader is now dual-language: new GLShader(renderer.gl, { vertex, fragment, wgsl }) with isWebGL/isWebGPU flags; mesh.shader hosts it on either backend, warn-and-degrade on mismatch (WGSL validation is async and contained — a bad module can never poison frame submission)
  • shader assets grow the matching complete-program shape { type: "shader", src: { vertex, fragment, wgsl } }

Completion + parity batch

  • antiAlias: true → 4× MSAA on WebGPU canvas passes; mesh textures gain generated mip chains + trilinear + 4× anisotropy on both backends (authored compressed chains included; "nearest" opts out); 8-slot multi-texture quad batching
  • WebGL gains setBlendMode("none") and the frameless-video upload guard; WebGPU gains enableScissor/setBlendEnabled/clearRenderTarget, settings.batcher, startup settings.blendMode, GPUVendor, failIfMajorPerformanceCaveat (rejects software adapters)
  • ShineEffect adopts the uUVYDir seam (vertical sweeps ran backwards on the GL pooled path — same family as the DropShadow fix)
  • shared neutral hoists (gpu/meshvertex.ts, gpu/quadcorners.ts, gpu/primitives.ts) delete ~250 duplicated lines across backends
  • published typings hygiene: renderer internals are @internal-tagged and stripped from the emitted .d.ts by a new build pass

Docs

  • JSDoc + README refresh across the 3D surface (retained-mesh story, capability flags, dual-language shaders, glTF light options, AUTO ladder); the wiki was updated in lockstep

Spine plugin (packages/spine-plugin, 4.0.0)

  • new WebGPUSpineBatcher: spine-core's backend-neutral geometry pass feeds a WGSL port of the official two-colored shader — dark-tint now works on WebGPU, and mesh-heavy skeletons batch instead of drawing per-triangle
  • backend dispatch via renderer.type; SpineBatcherWebGLSpineBatcher (internal rename); spine runtimes ^4.3.7^4.3.13

Examples

  • all examples swept to video.AUTO; the 3D examples guard on supportsDepthBuffer; reworked Hello WebGPU

Verification

  • suite 5528 passed / 9 skipped (≈370 new tests across the arc), eslint/biome/tsc clean
  • three review rounds (3D-tier code review, shared-architecture review, documentation review) — all findings fixed; the one deliberate deferral is instancing (3D: mesh instancing (drawElementsInstanced for repeated geometry) #1508), an API-design ticket
  • headed side-by-side WebGL↔WebGPU: all 44 examples, the 9 3D examples in depth, spine's 18 skeletons on all three backends

🤖 Generated with Claude Code

https://claude.ai/code/session_01QVjYzf76AEU3wJk766JAQi

obiot and others added 2 commits August 5, 2026 13:49
The WebGPU renderer completes the engine contract and becomes the AUTO
default (WebGPU → WebGL 2 → Canvas, negotiated inside app.init()):

- 3D tier: drawMesh through unlit/lit WGSL pipelines — retained
  model-space geometry under Camera3d (upload once, placement/tint/
  cutoff/emissive per-draw uniforms) and the CPU-projected 2D path;
  per-mesh cull/winding as pipeline state; depth as pass load/store ops
  (one clear per target per frame, pure-2D passes byte-identical)
- point + spot Light3d on both backends (#1536): 12-float std140 light
  entries (posRange/dirCone/colorInner), quadratic-over-range falloff,
  runtime-mutable fields; glTF loader instantiates all three punctual
  types (scene-scaled), carries authored light names, and gains a
  lightIntensityScale load option
- custom mesh shaders on both backends: GLShader is now dual-language —
  object sources form {vertex, fragment, wgsl} with isWebGL/isWebGPU
  flags; mesh.shader hosts it (warn-and-degrade on mismatch); shader
  assets grow the matching complete-program shape
- antiAlias => 4x MSAA on WebGPU canvas passes; mesh textures gain
  generated mip chains + trilinear + 4x anisotropy on both backends
  (authored compressed chains included; "nearest" opts out); 8-slot
  multi-texture quad batching
- renderer parity batch: setBlendMode("none") on WebGL; enableScissor/
  setBlendEnabled/clearRenderTarget, settings.batcher, settings.blendMode,
  GPUVendor, failIfMajorPerformanceCaveat on WebGPU; frameless-video
  guard on WebGL; instance-scoped compressed-format memo
- shine adopts the uUVYDir seam (vertical sweeps ran backwards on the GL
  pooled path); GLTFScene flags meshes lit for lamp-only scenes
- shared neutral hoists: gpu/meshvertex.ts, gpu/quadcorners.ts,
  gpu/primitives.ts (~250 duplicated lines deleted)
- d.ts hygiene: @internal + a strip-internal build pass keep renderer
  internals out of the published typings
- examples swept to video.AUTO; 3D examples guard on supportsDepthBuffer
- documentation refresh across JSDoc and README (retained-mesh story,
  capability flags, dual-language shaders, glTF light options)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QVjYzf76AEU3wJk766JAQi
On the WebGPU backend, skeletons now render through the new
WebGPUSpineBatcher instead of the canvas-renderer fallback: spine-core's
backend-neutral SkeletonRendererCore geometry pass (world vertices,
clipping, draw-order batching, packed light+dark colors) feeds a WGSL
port of the official two-colored-textured shader, one indexed draw per
texture/blend batch — the same rendering model as the WebGL path.

- dark-tint (two-color) rendering now works on WebGPU; mesh-heavy
  skeletons go from one drawImage per triangle to batched indexed draws
- atlas pages stay image-backed and upload through the engine texture
  store honoring each page's pma flag
- backend dispatch keys on renderer.type ("WebGL2"/"WebGPU"/canvas
  fallback) instead of the deprecated WebGLVersion sniff
- SpineBatcher renamed WebGLSpineBatcher for symmetry (internal class)
- bundled spine runtimes bumped ^4.3.7 -> ^4.3.13 (SkeletonRendererCore
  clipping fixes); debug rendering remains WebGL-only for now

All 18 example skeletons verified headed on WebGPU, WebGL and Canvas.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QVjYzf76AEU3wJk766JAQi
Copilot AI lite review requested due to automatic review settings August 5, 2026 05:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@obiot
obiot merged commit 648cfba into master Aug 5, 2026
6 checks passed
@obiot
obiot deleted the webgpu-3d-tier branch August 5, 2026 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants