`PostProcessSequentialGroup` skips earlier post processes when the subtree is rendered more than once
I maintainer di solito rispondono entro 1 giorno
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
What happened?
When a post process in a PostProcessSequentialGroup renders its subtree more than once, only the first call runs the post processes before it in the group. Every later call renders the raw tree and silently skips them.
Rendering the subtree more than once is common for multi-pass effects, and the PostProcess docs explicitly allow it. A drop shadow, for example, renders the subtree once as a dark, blurred shadow and then again for the scene itself. In PostProcessSequentialGroup([Grayscale(), DropShadow()]), the grayscale is only applied to the shadow pass, so the scene itself stays in full color and the grayscale effect appears to do nothing. Nothing is thrown.
https://github.com/user-attachments/assets/7315eab9-d002-490a-a954-368d15e5dc82
What do you expect?
Every call to renderSubtree or rasterizeSubtree should run the full chain of post processes before it in the group. In the example below, the whole scene should be gray, with a shadow, the same as nesting the two post processes by hand.
How can we reproduce this?
- Create a
PostProcessSequentialGroupwith a post process that renders its subtree twice, such as a drop shadow, after another post process, such as a grayscale filter. - Set it as
camera.postProcess, with some colored components in the world. - The shadows are drawn, but the components stay in color.
What steps should take to fix this?
PostProcessSequentialGroup.render (post_process.dart#L245-L260) builds a single list and removes post processes from it as it goes:
final stack = postProcesses.reversed.toList();
void runNext(Canvas c) {
if (stack.isEmpty) {
renderTree(c);
return;
}
final postProcess = stack.removeAt(0);
postProcess.render(c, size, runNext, updateContext);
}
The first subtree render empties the list, so the next one finds it empty and goes straight to renderTree.
Do have an example of where the bug occurs?
import 'dart:ui';
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/post_process.dart';
import 'package:flutter/material.dart' show Colors;
import 'package:flutter/widgets.dart';
void main() => runApp(GameWidget(game: ReproGame()));
class ReproGame extends FlameGame {
@override
Future<void> onLoad() async {
world.addAll([
CircleComponent(
radius: 40,
position: Vector2(-160, -40),
paint: Paint()..color = Colors.red,
),
RectangleComponent(
size: Vector2.all(80),
position: Vector2(-40, -40),
paint: Paint()..color = Colors.green,
),
CircleComponent(
radius: 40,
position: Vector2(80, -40),
paint: Paint()..color = Colors.blue,
),
]);
camera.postProcess = PostProcessSequentialGroup(
// Grayscale is applied first, then DropShadow, so the whole scene
// should be gray, with a shadow.
postProcesses: [Grayscale(), DropShadow()],
);
}
}
/// Renders its subtree in grayscale.
class Grayscale extends PostProcess {
final _paint = Paint()
..colorFilter = const ColorFilter.matrix([
0.2126, 0.7152, 0.0722, 0, 0, //
0.2126, 0.7152, 0.0722, 0, 0, //
0.2126, 0.7152, 0.0722, 0, 0, //
0, 0, 0, 1, 0, //
]);
@override
void postProcess(Vector2 size, Canvas canvas) {
canvas.saveLayer(null, _paint);
renderSubtree(canvas);
canvas.restore();
}
}
/// Renders its subtree as a dark, blurred shadow, then again on top.
class DropShadow extends PostProcess {
final _shadowPaint = Paint()
..colorFilter = const ColorFilter.mode(Color(0xAA000000), BlendMode.srcIn)
..imageFilter = ImageFilter.blur(sigmaX: 3, sigmaY: 3);
@override
void postProcess(Vector2 size, Canvas canvas) {
// First pass: the shadow.
canvas
..save()
..translate(8, 10)
..saveLayer(null, _shadowPaint);
renderSubtree(canvas);
canvas
..restore()
..restore();
// Second pass: the scene itself.
renderSubtree(canvas);
}
}
Expected: gray shapes with shadows. Actual: red, green and blue shapes with shadows. Replacing the group with Grayscale() alone turns the shapes gray, so the filter itself works.
Relevant log output
Nothing is logged or thrown.
Execute in a terminal and put output into the code block below
[√] Flutter (Channel stable, 3.47.8, on Microsoft Windows [Version 10.0.22631.6199], locale en-US)
• Flutter version 3.47.8 on channel stable
• Framework revision 737ba8f885 (8 days ago), 2026-10-22 21:37:31 -0700
• Engine revision cf636b1dfb
• Dart version 3.13.7
• DevTools version 2.60.0
[√] Windows Version (11 Pro 64-bit, 23H2, 2009)
[√] Android toolchain - develop for Android devices (Android SDK version 36.1.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2026 18.11.2)
[√] Connected device (3 available)
[√] Network resources
• No issues found!
Affected platforms
All
Are you interested in working on a PR for this?
- I want to work on this
- Lingua principale
- Dart
- Stelle
- 10.8k
- Fork
- 1.1k
- Merge medio
- 1g 21h
- PR unite (30g)
- 62
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di flame-engine/flame
-
`Viewfinder.visibleGameSize` is not reapplied when the viewport changes sizeForse già presa @ufrshubham l’ha presa oggi. Apertabug
flame-engine/flame#4204 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
`Viewfinder.visibleGameSize` zooms in too far with a `FixedResolutionViewport`Forse già presa @ufrshubham l’ha presa oggi. Apertabug
flame-engine/flame#4203 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
Camera bounds with `considerViewport: true` are not updated when the viewport is resizedForse già presa @ufrshubham l’ha presa oggi. Apertabug
flame-engine/flame#4202 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
`CameraComponent.setBounds` with `considerViewport: true` only works for bounds that start at (0, 0), at zoom 1Forse già presa @ufrshubham l’ha presa oggi. Apertabug
flame-engine/flame#4201 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
`findPostProcessFromContext` returns `null` for components rendered with `CameraComponent.postProcess`Forse già presa @ufrshubham l’ha presa 1 giorno fa. Apertabug
flame-engine/flame#4200 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di flame-engine/flame
Issue simili
-
[CarouselView] Crash (RangeError / ArgumentError) when children or itemCount is empty with infinite: true or CarouselController.animateToItemForse già presa Una pull request collegata a questa issue è aperta o già unita. Apertap: material_ui package platform-android platform-ios platform-linux platform-macos platform-web team-design
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
flutter/flutter#195878 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
agent-ready area:testing bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
pauljohanneskraft/Acai#479 ·
I maintainer di solito rispondono entro 3 giorni
-
[genkit_google_genai] Gemini tool call with no arguments fails with "requires a non-null input"Forse già presa @kenzieschmoll l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
genkit-ai/genkit-dart#692 ·
I maintainer di solito rispondono entro 11 giorni
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
-
bug
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
lollipopkit/flutter_server_box#1851 · 1 commento · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno