[flame_3d] Nested Object3D without computeLocalAabb is culled using its local position
Los mantenedores suelen responder en 1 día
@ufrshubham ya está trabajando en esto.
Desde el 29/10/2026.
Evaluación
Este issue todavía no se ha evaluado.
Descripción
What happened?
A Component3D without geometry (one that doesn't override computeLocalAabb) and without children gets a degenerate AABB: a single point. That point is set from the component's local position instead of its world position:
if (!initialized) {
// No geometry and no children, so degenerate to point at position.
_cachedAabb
..min.setFrom(position)
..max.setFrom(position);
}
For a component directly in the world the local and world positions are the same, so this works. Once it is nested under a parent with a transform, it's frustum culled at the wrong place. For an Object3D that draws something itself without overriding computeLocalAabb, this means it disappears while it is in view (or is drawn while it isn't).
This doesn't affect MeshComponent or ModelComponent, since they override computeLocalAabb, but it does affect custom Object3D subclasses that draw in draw without reporting bounds.
What do you expect?
The degenerate AABB should be at the component's world position, like every other AABB, which is already transformed with worldTransformMatrix.
How can we reproduce this?
- Run the
main.dartbelow withflutter run --enable-flutter-gpu(on Windows also add--enable-impeller). - Both cubes are
CustomCubes, anObject3Dthat draws a cube without overridingcomputeLocalAabb. The red one is directly in the world, the green one is nested under aGroupat(0, 0, 20)with a local position of(-1.5, 1, -20), so its world position is(-1.5, 1, 0). - Only the red cube is rendered. The green cube's AABB is a point at
(-1.5, 1, -20), which is behind the camera.
Nothing else is moved or added after the first frame, so this is independent of the cached AABBs not being invalidated.
What steps should take to fix this?
Use the world translation for the degenerate AABB:
if (!initialized) {
// No geometry and no children, so degenerate to point at the world
// position.
final worldPosition = worldTransformMatrix.getTranslation();
_cachedAabb
..min.setFrom(worldPosition)
..max.setFrom(worldPosition);
}
Do have an example of where the bug occurs?
import 'package:flame/game.dart';
import 'package:flame_3d/camera.dart';
import 'package:flame_3d/components.dart';
import 'package:flame_3d/game.dart';
import 'package:flame_3d/graphics.dart';
import 'package:flame_3d/resources.dart';
import 'package:flutter/widgets.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await GpuBackend.initialize();
runApp(GameWidget(game: ReproGame()));
}
class ReproGame extends FlameGame3D {
ReproGame()
: super(
camera: CameraComponent3D(
position: Vector3(0, 2, -6),
target: Vector3(0, 1, 0),
),
);
@override
Future<void> onLoad() async {
world.addAll([
// Red: not nested, world position (1.5, 1, 0). Rendered.
CustomCube(color: const Color(0xFFFF0000), position: Vector3(1.5, 1, 0)),
// Green: nested, world position (-1.5, 1, 0). Not rendered.
Group(
position: Vector3(0, 0, 20),
children: [
CustomCube(
color: const Color(0xFF00FF00),
position: Vector3(-1.5, 1, -20),
),
],
),
]);
}
}
class Group extends Component3D {
Group({super.position, super.children});
}
/// An [Object3D] that draws a cube, without overriding `computeLocalAabb`.
class CustomCube extends Object3D {
CustomCube({required Color color, super.position})
: mesh = CuboidMesh(
size: Vector3.all(1),
material: UnlitMaterial(albedoColor: color),
);
final Mesh mesh;
@override
void draw(covariant RenderContext3D context) {
context
..model.setFrom(worldTransformMatrix)
..drawMesh(mesh);
}
}
Relevant log output
No errors or warnings are logged.
Execute in a terminal and put output into the code block below
Flutter 3.47.8 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 737ba8f885 (6 days ago) • 2026-10-22 21:37:31 -0700
Engine • hash dfd2e6cb7d319db05e3bf1503f3e2ac60f6288a2 (revision cf636b1dfb) (6 days ago) • 2026-10-23 02:13:38.000Z
Tools • Dart 3.13.7 • DevTools 2.60.0
Affected platforms
All
Other information
Reproduced on Windows (Impeller with the OpenGL ES backend), but the culling logic is platform independent.
Other culling issues found at the same time, which can each be reproduced and fixed independently: #4163 and #4164 (cached AABBs not being invalidated).
Are you interested in working on a PR for this?
- I want to work on this
- Lenguaje dominante
- Dart
- Estrellas
- 10.8k
- Forks
- 1.1k
- Merge medio
- 1 d 14 h
- PR fusionados (30 d)
- 62
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de flame-engine/flame
-
[flame_3d] Object3D.isVisible only checks the center point, so partially visible objects are not drawnPosiblemente ocupada @ufrshubham la tomó hace 1 día. Abiertobug flame_3d
flame-engine/flame#4166 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
[flame_3d] Children added to an Object3D after it was rendered can be culled while on screenPosiblemente ocupada @ufrshubham la tomó hace 1 día. Abiertobug flame_3d
flame-engine/flame#4164 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
[flame_3d] Nested components are culled at their old position after an ancestor movesPosiblemente ocupada @ufrshubham la tomó hace 1 día. Abiertobug flame_3d
flame-engine/flame#4163 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
flame-engine/flame#4157 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 3/5 1-2 días Aptitud para principiantes 45/100
flame-engine/flame#4150 · 1 reacción ·
Los mantenedores suelen responder en 1 día
Todos los issues de flame-engine/flame
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 5 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 4 días
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 69/100
Los mantenedores suelen responder en 3 días
-
area-clientside-dartpad
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
Los mantenedores suelen responder en 2 días
-
'图片收藏'功能无法滑动Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
venera-app/venera-prime#50 ·