Add FBO-based post-processing pipeline for camera shader effects#1397
Merged
Add FBO-based post-processing pipeline for camera shader effects#1397
Conversation
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>
Contributor
There was a problem hiding this comment.
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 WebGLRendererbeginPostEffect/endPostEffect/blitEffectpipeline hooks. - Extends
RenderStatesave/restore to includecurrentShader, and simplifiesRenderableshader scoping to rely on save/restore. - Adds
QuadBatcher.blitTexture()for screen-aligned shader blits, exportsVignetteEffect, 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.
- 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>
Contributor
There was a problem hiding this comment.
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.
- 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>
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.
Summary
Closes #1367
ShaderEffectto any camera'sshaderproperty to apply full-screen post-effects (vignette, scanlines, desaturation, etc.). Works with multiple cameras independently (e.g. main camera + minimap with different effects)beginPostEffect(camera),endPostEffect(camera),blitEffect(source, x, y, w, h, shader)— no-op on Canvas renderercurrentShaderadded to save/restore stack, fixing shader leak between parent cameras and child renderablesrenderer.customShader = this.shader, relies on save/restoreTest plan
🤖 Generated with Claude Code