`findPostProcessFromContext` returns `null` for components rendered with `CameraComponent.postProcess`

未关闭
#4,200 0 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@ufrshubham 已经在做这个了。

开始于 2026年11月2日。

  • #4218 来自 @Dhairya-007 —— 未关闭

评估

这个 Issue 还没有评估数据。

描述

bug
What happened?

When a post process is set as camera.postProcess, findPostProcessFromContext returns null for every component in the world and in the viewfinder. The components have no way to know which post process is rendering them. The same post process in a PostProcessComponent is found as expected.

This breaks multi-pass effects where components draw differently in each pass, which is what the render context is for. Take a selection highlight, like in a strategy game: it renders its subtree once as a mask, where only the selected unit draws itself, and turns that mask into an outline. Then it renders the subtree again for the scene itself. With camera.postProcess, the lookup fails, so every component draws itself into the mask, and everything gets outlined instead of only the selected unit. Nothing is thrown.

https://github.com/user-attachments/assets/1efc7431-880c-480e-bb7e-771270004aa8

What do you expect?

findPostProcessFromContext should return the camera's post process for any component that the camera renders, the same as it does for the children of a PostProcessComponent. In the example below, only the green square should be outlined.

How can we reproduce this?
  1. Set a post process as camera.postProcess.
  2. Add a component to the world that calls findPostProcessFromContext in its render.
  3. It always gets null.
What steps should take to fix this?

When no PostProcessComponent is found, findPostProcessFromContext (post_process_component.dart#L128-L143) falls back to looking up the camera's render context:

final contextInCamera =
    findRenderContext<CameraRenderContext>()?.currentPostProcess;

Render contexts are passed from a component to its children in renderChild. The world isn't a child of the camera, and the camera renders both the world and the viewfinder directly (camera_component.dart#L227-L233), so the camera's render context never reaches either of them. This lookup can never succeed.

The cameras that are rendering are already tracked in CameraComponent.currentCameras. The fallback can check their post processes there instead, from the innermost camera to the outermost.

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 {
    camera.postProcess = SelectionHighlight();
    world.addAll([
      Unit(color: Colors.red, position: Vector2(-160, -40)),
      Unit(color: Colors.green, position: Vector2(-40, -40), isSelected: true),
      Unit(color: Colors.blue, position: Vector2(80, -40)),
    ]);
  }
}

/// Outlines the selected units, like in a strategy game.
///
/// It renders its subtree twice: first as a mask, where only the selected
/// units draw themselves, which is turned into a yellow outline. Then the
/// scene itself, on top of the outline.
class SelectionHighlight extends PostProcess {
  bool drawingMask = false;

  final _outlinePaint = Paint()
    ..colorFilter = const ColorFilter.mode(Colors.yellow, BlendMode.srcIn)
    ..imageFilter = ImageFilter.dilate(radiusX: 6, radiusY: 6);

  @override
  void postProcess(Vector2 size, Canvas canvas) {
    drawingMask = true;
    canvas.saveLayer(null, _outlinePaint);
    renderSubtree(canvas);
    canvas.restore();
    drawingMask = false;

    renderSubtree(canvas);
  }
}

class Unit extends RectangleComponent {
  Unit({
    required Color color,
    required super.position,
    this.isSelected = false,
  }) : super(size: Vector2.all(80), paint: Paint()..color = color);

  final bool isSelected;

  @override
  void render(Canvas canvas) {
    final highlight = findPostProcessFromContext<SelectionHighlight>();
    // Only the selected units draw themselves into the mask.
    if ((highlight?.drawingMask ?? false) && !isSelected) {
      return;
    }
    super.render(canvas);
  }
}

Expected: only the green square is outlined. Actual: all three squares are outlined, because findPostProcessFromContext returns null and every unit draws itself into the mask.

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 (11 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
主要语言
Dart
星标
10.8k
派生
1.1k
平均合并
1 天 19 小时
30 天内合并 PR
54

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

flame-engine/flame 的其他 Issue

查看 flame-engine/flame 的全部 Issue

相似的 Issue

更多 Dart Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。