Conversation
Moves flame_flutter3d 0.8.4 from the flutter3d repository into the Flame monorepo as 0.9.0-dev.0 and ports it to Flame 2.0: synchronous add, HasGameRef, MouseMoveCallbacks, list-based collision points, the forge2d on Box2D v3, tiled 0.12, and CustomTraversal in place of the updateTree overrides that write a component's transform after its effects. Adds a bridge package page covering the shared loop, the bridge plane, post-processing through HasFlutter3d.renderSettings, and WebGL2/WebGPU builds.
Three stories: post-processing toggled at runtime under a Flame HUD, one game loop driving both engines, and a Tiled map stood up in 3D. Each shows which backend draws it, WebGL2 or WebGPU in a browser.
A River Raid-style game built on the bridge: Flame components and effects, flutter3d physics, particles and a chase camera, on one loop. This copy is silent, since a real audio backend would bring SoLoud's native build into the workspace.
spydon
left a comment
There was a problem hiding this comment.
Hey, this looks really cool and it looks like a massive amount of work!
This isn't something that we would like to bring into the repository right now though since it is huge and adds a lot of maintenance.
I see that you already have it published as a package so I would recommend keeping it as maintained by you.
On another note, it's such a coincidence that you open this today, since I'm also opening a PR related to 3D today, but with a much smaller scope. You can check it out here:
#4086
|
Thanks for taking a look; that makes sense. 20k lines is a lot to take on, and I'd rather maintain it myself than hand you something that big. I'll keep flame_flutter3d on pub.dev and keep it working with new Flame releases. Would you be open to a link from awesome-flame? I can open the PR there. Funny timing with #4086. Most Flame games are 2D, so being able to drop one 3D model into the normal component tree is probably what most people will use. |
Absolutely, go for it! |
Adds flame_flutter3d, a bridge between Flame and the flutter3d 3D engine. It's published on pub.dev: https://pub.dev/packages/flame_flutter3d Follow-up to flame-engine/flame#4085, where it was suggested to keep the package outside the main repo.
Description
This adds
flame_flutter3d, a bridge package that puts a flutter3d scene under a Flame game. I've been developing it in the flutter3d repository, where it reached 0.8.4 on pub.dev. This moves it here as 0.9.0-dev.0, ported to Flame 2.0.Flame keeps running the game and drawing its own layer. flutter3d draws a 3D layer under it, and the bridge keeps the two in agreement on transforms, lifecycle, physics contacts, input, the camera and an actor system. A Flame game gets a full 3D renderer without being rewritten: its components, effects, hitboxes, collision callbacks, camera, overlays,
flame_tiledmaps andflame_forge2dbodies keep working, and the bridge draws them in 3D.One loop and one event model
The two engines share Flame's loop. A
BridgeClockcomponent draws the 3D frame after Flame's components have updated, so aMoveEffectthat moved a component this frame is drawn in 3D this frame, and there is no second ticker to drift from the first.HasFixedStepruns the game's logic, the physics and the actors in fixed steps, so a second of play comes out the same at 30 and at 120 frames per second, and bodies are drawn interpolated between two steps.BridgePrioritynames the order everything runs in. Some of it runs after Flame's ownCameraComponent, so a 3D camera followingcamera.follow()doesn't trail it by a frame.Events stay Flame's too. Contacts from flutter3d's physics arrive as Flame's
onCollisionStart,onCollisionandonCollisionEnd, a tap reaches the component the player sees under a perspective camera throughTap3dCallbacks, and keys, drags, the touch joystick and gamepads all write into one input state. A game handles its events the way it already does.Rendering
The 3D layer renders in HDR through flutter3d's post-processing chain: tone mapping (Neutral, ACES, AgX, Reinhard), exposure and auto exposure, bloom, SSAO and GTAO, screen-space reflections, contact shadows, light shafts, volumetric fog, depth of field, motion blur, temporal AA, a LUT and spatial upscaling.
HasFlutter3d.renderSettings()is read before every frame, so a game can switch any of it on Flame's clock: depth of field for a cutscene, fog as the day turns.Under that there are directional shadows, six lighting models (PBR among them, plus toon and unlit), up to eight lights per draw out of however many a scene holds, glTF and OBJ models with skinning, morph targets and animation, frustum culling and LOD.
WebGL2, WebGPU, Flutter GPU, and no GPU at all
flutter3d draws through Flutter GPU on macOS, Android and iOS, and through WebGL2 or WebGPU in a browser. A web build draws through WebGL2 by default, so it runs in any current browser with no setup step and no extra shader build. With
--dart-define=FLUTTER3D_WEBGPU=trueit tries WebGPU first and falls back to WebGL2 where the browser has no adapter. I made WebGPU opt-in because it adds about 368 KiB of JavaScript.There is also a software rasterizer that needs no GPU. All 213 of this package's tests draw through it, so they run on any CI machine, and the stack's golden images are checked against two independently written renderers.
How this compares to
flame_3dThe two packages take different routes.
flame_3dis a 3D component tree inside Flame, built on Flutter GPU and, by its own README, experimental. This keeps Flame's world as it is and puts a separate, released engine under it. Where they differ today:flame_flutter3dflame_3dnagaComponent3DsThey don't compete for the same games. A 2D game with a 3D look (a top-down shooter, a side-scroller with depth, a board in perspective) or a 3D scene that wants Flame's HUD, effects and input fits this one.
What's in the PR
packages/flame_flutter3d: the package and its minimal example.doc/bridge_packages/flame_flutter3d: a docs page, linked from the bridge packages index.examples/lib/stories/bridge_libraries/flame_flutter3d: three stories. One toggles post-processing live under a Flame HUD. One drives both engines from one loop: Flame effects move 3D boxes, taps hit the 3D boxes, and a physics landing arrives asonCollisionStart. The third is a Tiled maze in 3D. Each story shows which backend is drawing. I built the examples for web with and without the WebGPU flag and checked that all three stories render under both.examples/games/river_sortie: a small River Raid-style game built on the bridge, with 54 tests. This copy is silent; the section on Flutter 3.44 says why.Nothing else in Flame changes: no package, dependency constraint or workflow.
Porting to Flame 2.0
Most of it was mechanical: synchronous
add,HasGameRef,MouseMove*, list-based collision points, forge2d on Box2D v3, tiled 0.12. One change wasn't. The bridged components overrodeupdateTreeto write their transform after their effects had run, and with the flattened traversal those overrides would have silently stopped being called. They useCustomTraversal.updateSubtreenow.Resolving on Flutter 3.44
The flutter3d packages used to ask for Dart
^3.12.2, andflutter3d_gamepulled influtter_soloud, whose native build needshooks2.2 and a newermetathan Flutter 3.44 pins. I didn't want to touch Flame's constraints for that, so I published 0.8.x patch releases of the stack with relaxed constraints and split the audio code soflutter3d_gameno longer depends on SoLoud. It's also why River Sortie is silent here: a real audio backend would bring SoLoud back into the workspace.The workspace resolves from pub.dev on Flutter 3.44.0 and 3.47.0. CI passes analyze on both versions, DCM, format, markdownlint and the full test run.
Open questions
colour,behaviour), and a few public parameters are namedcolour. I added the words to the dictionary rather than renaming anything, but I can switch tocolorif you prefer.gh-pages.ymlwould needcustomArgs: --dart-define=FLUTTER3D_WEBGPU=true. I left the workflow alone.Checklist
docsand added dartdoc comments with///.examplesordocs.Breaking Change?
Related Issues