Cameras and lights from a file: the source
Open the live demo · Read the guide · View on GitHub
Regions the guide quotes: document (line 23), roundtrip (line 50), scene (line 56), check (line 77).
1/// A camera and a light, written into a GLB and read back out of it.
2///
3/// Quoted by `gltf_cameras_lights.md` and shown whole in the Source tab.
4library;
6import 'package:flutter3d/flutter3d.dart';
7import 'package:flutter3d_showcase/src/demo/demo.dart';
8import 'package:vector_math/vector_math.dart';
10final class GltfCamerasLightsDemo extends ShowcaseDemo {
11 late final GltfAsset _readBack;
14 void configureView(DemoContext context) {
15 context.orbit
16 ..distance = 3.5
17 ..pitch = 0.3
18 ..yaw = 0.6;
19 }
22 Future<void> prepare(DemoContext context) async {
23 // glTF's own `KHR_lights_punctual` and `camera` are held on a document as
24 // `ModelLight` and `ModelCamera`, addressed from a node the same way a
25 // surface is. This document has one of each, plus a cube to see by.
26 final document = PlainModelDocument(
27 surfaces: <ModelSurface>[
28 ModelSurface(mesh: CuboidShape(size: Vector3.all(1.0)).build()),
29 ],
30 lights: <ModelLight>[
31 ModelLight(
32 type: ModelLightType.directional,
33 color: Vector3(1.0, 0.95, 0.85),
34 intensity: 2.4,
35 ),
36 ],
37 cameras: <ModelCamera>[
38 const ModelCamera(
39 projection: ModelPerspectiveCamera(yfov: 0.9, znear: 0.1),
40 name: 'framing',
41 ),
42 ],
43 nodes: <ModelNode>[
44 ModelNode(surfaces: <int>[0]),
45 ModelNode(name: 'sun', lightIndex: 0),
46 ModelNode(name: 'framing', cameraIndex: 0),
47 ],
48 );
50 final bytes = GltfWriter(document).writeGlb();
51 _readBack = await GltfLoader().load(bytes);
52 }
55 Scene build(DemoContext context) {
56 final scene = Scene();
57 for (final ModelSurface surface in _readBack.surfaces) {
58 scene.add(
59 MeshNode(
60 DeviceMesh.upload(context.device, surface.mesh),
61 Material(baseColor: Vector4(0.7, 0.75, 0.82, 1.0), roughness: 0.6),
62 name: 'cube',
63 ),
64 );
65 }
66 for (final ModelLight light in _readBack.lights) {
67 scene.add(
68 LightNode(name: light.name, intensity: light.intensity)
69 ..setLocalForward(Vector3(-0.4, -0.9, -0.3)),
70 );
71 }
72 return scene;
73 }
76 void verify(Scene scene, FrameResult frame) {
77 if (_readBack.lights.length != 1) {
78 throw StateError('the light did not survive the round trip');
79 }
80 if (_readBack.cameras.length != 1) {
81 throw StateError('the camera did not survive the round trip');
82 }
83 final ModelCameraProjection projection =
84 _readBack.cameras.single.projection;
85 if (projection is! ModelPerspectiveCamera) {
86 throw StateError('the camera came back as the wrong projection');
87 }
88 if (frame.drawCalls < 1) {
89 throw StateError('the cube was not drawn');
90 }
91 }
92}