flutter3d
Showcase Changelog 38 packages API reference

The scene surface and its status screens

since 0.7.0 Widgets and the rest

Every viewport in this application, including the one this page would use if it did not override its own body, is built from the same two pieces: SceneSurface renders a scene into a widget, and DidNotStart is what shows instead when opening a renderer failed.

Step 1: A scene to draw #

@override
Scene build(DemoContext context) {
  final material = f3d.Material(
    name: 'ball',
    baseColor: Vector4(0.6, 0.7, 0.9, 1.0),
  );
  final ball = MeshNode(
    DeviceMesh.upload(context.device, SphereShape(segments: 24).build()),
    material,
  );
  _scene = Scene()
    ..add(ball)
    ..add(
      LightNode(name: 'sun', intensity: 3.0)
        ..setLocalForward(Vector3(-0.4, -1.0, -0.3)),
    );
  return _scene;
}

Step 2: Wrap it in a surface #

SceneSurface calls onBeforeFrame, then settings, then renders, and hands the result to presentFrame — the one function every backend can answer, since a backend whose frame is composited elsewhere has no image of its own to paint.

@override
Widget? customBody(BuildContext buildContext, DemoContext context) =>
    SceneSurface(
      renderer: context.renderer,
      scene: _scene,
      view: context.view,
      settings: () => const RenderSettings(),
      onBeforeFrame: () {},
      presentFrame: presentFrame,
    );

Step 3: What failure looks like #

Five applications each wrote their own screen for "the renderer never opened"; DidNotStart is the one that is left, with room for an application to add what the bare error does not say.

// What an application shows instead, when the renderer never opened.
final failure = DidNotStart(
  StateError('no shader bundle for this build'),
  explaining: 'run tool/build_shaders.sh first',
);

The explanation an application supplies is shown alongside the error, verbatim.