voxel_scene 0.5.0-dev
voxel_scene: ^0.5.0-dev copied to clipboard
flutter_scene renderer for voxel_engine: one scene node per chunk, the terrain material and its shaders.
voxel_scene #
Draws voxel_engine worlds with flutter_scene:
chunks drawn a region at a time, a terrain material with its own shaders, a day
and night sky, block models and the selection outline.
Status: 0.5.0-dev, beta. The API can still change.
Features #
VoxelChunkView: aChunkMeshSinkthat draws chunks in regions (2 × 2 by default), one geometry per surface a region, so the terrain costs few draws, and its lit surfaces in a packed 16-byte vertex (the engine's is 72) with a vertex shader of its own. It rebuilds the regions that changed once a frame, nearest first, within a time budget, so a burst of chunks is drawn over a few frames.cull(eye)hides the regions sight cannot reach from the camera through open cells, which underground is most of them; above ground it hides nothing. Once an area has been quiet forsettleAfter(2 s), outsidesettleClearchunks (2) of the focus, its 2 × 2s settle into one region ofsettledRegionChunks(4 × 4), in steps within the same budget: one draw a surface (or part of one) where four drew. A change there splits it back without a hole.TerrainMaterial: the terrain shader (lit, fogged, shadowed).MirroredCamera: the camera that showsvoxel_engine's winding the right way round.SelectionOutline: the edges of the aimed box, one mesh, one draw;BoxMesh, boxes as one mesh wound the engine's way, which it is made of.ResizeSafeScene: aSceneto render with when the sun caches its static shadows, asDayNightSky's does. It drops the cache on the frame the view changes size, which keeps Impeller's Vulkan backend from beginning a render pass on a freed depth texture (flutter/flutter#192538), a crash seen on Adreno phones as a game turns to landscape.GpuPacedScene: aResizeSafeScenewhose frames reach the screen only once the GPU has finished them, so text over the scene stays readable on a busy GPU under Metal; the scene shows one frame late and renders only when the last one is done (ScenePacer).ItemMesh: one mesh perItemModel, shared by everything that draws the item.DayNightSky: the sun's day, the weather's grey and lightning (overcast,flash), a dimension's own sunless sky (StillSky) and a fog of one colour from the eye (Haze, water's); the numbers areSkyLook's, checked with no GPU.WeatherParticles(rain and snow around a point) andDebrisParticles(chips and embers thrown out of one), each oneParticleSystem, so one draw.PulseEffects: a see-through sphere of a colour that grows and fades where a blow lands, from a pool of spheres built once.VoxelModelMesh, with one shared material a tint (tinted, see-through under an alpha of 1) and a white one for a hit (flash);RigPart,NodeBody.
Install #
dependencies:
voxel_scene: ^0.5.0-dev
Dart SDK ^3.13.0.
-
Flutter 3.47.1 or later, with Flutter GPU turned on in each runner:
flutter_scenedraws through it, and it is off by default. macOS and iOS take<key>FLTEnableFlutterGPU</key><true/>inRunner/Info.plist, Android theio.flutter.embedding.android.EnableFlutterGPUmeta-data in its manifest, Windowsproject.set_enable_flutter_gpu(true);inrunner/main.cppand Linuxfl_dart_project_set_enable_flutter_gpu(project, TRUE);inrunner/my_application.cc(the last two exist from Flutter 3.47.1).voxel_game's README has the table. -
Not the web.
voxel_enginestreams chunks on worker isolates and talks over TCP sockets (dart:isolate,dart:io), which a browser does not have. -
flutter_sceneis pinned to0.23.0: the terrain material and geometry use its private GPU layer and its geometry's stream binding. -
The shaders ship compiled in
assets/shaders/. After a Flutter upgrade or a shader edit, rebuild them withdart tool/build_shaders.dart.
Usage #
-
Load the resources before the first frame.
WidgetsFlutterBinding.ensureInitialized(); await Scene.initializeStaticResources(); await TerrainMaterial.loadLibrary(); // before the first TerrainMaterial -
Put a chunk view in a scene.
final scene = Scene(); final view = VoxelChunkView(); scene.add(view.root); -
Stream
voxel_enginechunks into it. The view is the streamer's sink.final streamer = ChunkStreamer(table: table, sink: view, loadRadius: 6)..jobs = pool; streamer.updateAround(ChunkStreamer.chunkOfXZ(0, 0)); -
Show it with a
MirroredCamera, callingstreamer.update(),view.rebuild(centre)andview.cull(eye)every tick: the streamer hands the view its meshes, the view draws the regions they changed, nearestcentrefirst, within its budget, and hides the ones the camera cannot see into. Start culling only after anyScene.warmUp, which must see every region to compile its pipelines.SceneView(scene, cameraBuilder: (elapsed) => MirroredCamera(position: eye, target: target), onTick: (elapsed, dt) { streamer.update(); view.rebuild(ChunkStreamer.chunkOfXZ(0, 0)); view.cull(eye); }); -
Shadows: give the
SunLightshadowCasterFaces: MirroredCamera.shadowCasterFaces.
Example #
cd example
flutter run -d macos
example/lib/main.dart draws sine hills with a lake
and lamps under a sun with shadows, from a camera that circles them.