Skip to content

Add FBO-based post-processing pipeline for camera shader effects#1397

Merged
obiot merged 3 commits intomasterfrom
feat/post-processing-pipeline
Apr 17, 2026
Merged

Add FBO-based post-processing pipeline for camera shader effects#1397
obiot merged 3 commits intomasterfrom
feat/post-processing-pipeline

Conversation

@obiot
Copy link
Copy Markdown
Member

@obiot obiot commented Apr 17, 2026

Summary

Closes #1367

  • Camera post-processing: assign a ShaderEffect to any camera's shader property to apply full-screen post-effects (vignette, scanlines, desaturation, etc.). Works with multiple cameras independently (e.g. main camera + minimap with different effects)
  • WebGLRenderTarget: new FBO wrapper class with bind/unbind/resize/destroy/clear, plus getImageData/toBlob/toImageBitmap/toDataURL (API aligned with CanvasRenderTarget)
  • Renderer methods: beginPostEffect(camera), endPostEffect(camera), blitEffect(source, x, y, w, h, shader) — no-op on Canvas renderer
  • QuadBatcher.blitTexture(): screen-aligned quad rendering through a shader effect
  • VignetteEffect: new built-in shader effect for edge darkening
  • RenderState: currentShader added to save/restore stack, fixing shader leak between parent cameras and child renderables
  • Renderable: preDraw/postDraw shader scoping simplified — always sets renderer.customShader = this.shader, relies on save/restore
  • Examples: platformer uses VignetteEffect on both main camera and minimap
  • Version bumped to 19.2.0

Test plan

  • RenderState unit tests pass (21 tests, including 4 new tests for shader save/restore)
  • Platformer example: vignette on main camera + minimap, particles render correctly, no shader leaking
  • Multi-camera: each camera renders with its own independent effect
  • No visual regression when no shader is assigned (zero overhead path)
  • Context loss/restore: FBO is recreated on demand after context restore

🤖 Generated with Claude Code

Add render-to-texture support via WebGLRenderTarget and a camera post-effect
pipeline that allows assigning ShaderEffect instances to any Camera2d.

- WebGLRenderTarget: FBO wrapper with bind/unbind/resize/destroy/clear,
  plus getImageData/toBlob/toImageBitmap/toDataURL (aligned with CanvasRenderTarget)
- Renderer: beginPostEffect(camera)/endPostEffect(camera)/blitEffect() methods
  (no-op on Canvas renderer)
- QuadBatcher: blitTexture() for screen-aligned quad rendering through a shader
- RenderState: currentShader added to save/restore stack, fixing shader leak
  between parent cameras and child renderables
- VignetteEffect: new built-in shader effect for edge darkening
- Renderable: preDraw/postDraw shader scoping simplified via save/restore
- Examples: platformer uses VignetteEffect on both main camera and minimap
- Version bumped to 19.2.0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 17, 2026 23:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a WebGL FBO-backed post-processing path so a ShaderEffect assigned to camera.shader can be applied as a full-screen (per-camera) post-effect, plus a new built-in VignetteEffect.

Changes:

  • Introduces WebGLRenderTarget (FBO wrapper) and WebGLRenderer beginPostEffect/endPostEffect/blitEffect pipeline hooks.
  • Extends RenderState save/restore to include currentShader, and simplifies Renderable shader scoping to rely on save/restore.
  • Adds QuadBatcher.blitTexture() for screen-aligned shader blits, exports VignetteEffect, and updates examples/changelog/version.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
packages/melonjs/src/video/webgl/webgl_renderer.js Adds post-effect capture/blit flow and renderState↔customShader sync
packages/melonjs/src/video/rendertarget/webglrendertarget.js New FBO wrapper with resize/destroy/readback helpers
packages/melonjs/src/video/webgl/batchers/quad_batcher.js Adds raw-texture blit through shader
packages/melonjs/src/video/renderstate.js Adds shader to save/restore stack
packages/melonjs/src/renderable/renderable.js Simplifies shader scoping to always set/restore via save/restore
packages/melonjs/src/camera/camera2d.ts Hooks camera draw into post-effect pipeline
packages/melonjs/src/video/webgl/effects/vignette.js New built-in vignette effect
packages/melonjs/tests/renderstate.spec.js Adds tests for shader save/restore behavior
packages/melonjs/src/index.ts Exports VignetteEffect
packages/melonjs/src/video/renderer.js Adds no-op base methods for post-effect API
packages/melonjs/CHANGELOG.md Documents new rendering features
packages/melonjs/package.json Bumps version to 19.2.0
packages/examples/... Demonstrates camera vignette usage in examples

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/melonjs/src/video/rendertarget/webglrendertarget.js
Comment thread packages/melonjs/src/camera/camera2d.ts
Comment thread packages/melonjs/src/video/webgl/webgl_renderer.js
Comment thread packages/melonjs/src/video/webgl/batchers/quad_batcher.js
Comment thread packages/melonjs/src/video/rendertarget/webglrendertarget.js
Comment thread packages/melonjs/src/video/rendertarget/webglrendertarget.js
Comment thread packages/melonjs/src/video/webgl/effects/vignette.js Outdated
Comment thread packages/melonjs/src/video/webgl/webgl_renderer.js
Comment thread packages/melonjs/src/video/rendertarget/webglrendertarget.js Outdated
- WebGLRenderTarget.getImageData(): clamp inputs to render target bounds
- WebGLRenderTarget.getImageData(): fix JSDoc (binds/unbinds internally)
- WebGLRenderTarget.toBlob(): fallback for environments without OffscreenCanvas
- WebGLRenderTarget: handle WebGL1 without OES_packed_depth_stencil extension,
  falls back to DEPTH_COMPONENT16 when packed depth/stencil is unavailable
- VignetteEffect: fix JSDoc description (lower = stronger, higher = softer)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/melonjs/src/video/renderstate.js
Comment thread packages/melonjs/src/video/webgl/webgl_renderer.js Outdated
Comment thread packages/melonjs/src/video/webgl/webgl_renderer.js
- RenderState.reset(): clear currentShader to avoid stale references
  after context loss/restore
- beginPostEffect/endPostEffect: use `camera.shader.enabled === false`
  instead of `!camera.shader.enabled` so GLShader (which has no
  `enabled` property) is treated as enabled

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@obiot obiot merged commit e329def into master Apr 17, 2026
6 checks passed
@obiot obiot deleted the feat/post-processing-pipeline branch April 17, 2026 23:59
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.

Add post-processing pipeline: render-to-texture and camera shader effects

2 participants