Levels of detail: the source
Open the live demo · Read the guide · View on GitHub
Regions the guide quotes: parts (line 22), asset (line 53), instantiate (line 69), selection (line 81), check (line 86).
1/// Three sphere meshes, packed into one `ModelAsset` with levels of detail and
2/// selected by their projected screen size.
3library;
5import 'package:flutter3d/flutter3d.dart';
6import 'package:flutter3d_showcase/src/demo/demo.dart';
7import 'package:vector_math/vector_math.dart';
9final class LevelOfDetailDemo extends ShowcaseDemo {
10 late final LodGroup _group;
13 void configureView(DemoContext context) {
14 context.orbit
15 ..distance = 8.0
16 ..pitch = 0.18
17 ..yaw = 0.35;
18 }
21 Scene build(DemoContext context) {
22 final List<(String, SphereShape, Vector4)> definitions =
23 <(String, SphereShape, Vector4)>[
24 (
25 'fine',
26 const SphereShape(radius: 1.6, segments: 48, rings: 24),
27 Vector4(0.16, 0.68, 0.92, 1.0),
28 ),
29 (
30 'medium',
31 const SphereShape(radius: 1.6, segments: 20, rings: 10),
32 Vector4(0.95, 0.62, 0.16, 1.0),
33 ),
34 (
35 'coarse',
36 const SphereShape(radius: 1.6, segments: 8, rings: 4),
37 Vector4(0.84, 0.24, 0.28, 1.0),
38 ),
39 ];
40 final List<ModelPart> parts = <ModelPart>[
41 for (final (String name, SphereShape shape, Vector4 color) in definitions)
42 ModelPart(
43 mesh: DeviceMesh.upload(context.device, shape.build()),
44 material: Material(
45 name: '$name material',
46 baseColor: color,
47 roughness: 0.52,
48 ),
49 name: name,
50 ),
51 ];
53 final ModelNode node = ModelNode(
54 name: 'sphere lod',
55 surfaces: const <int>[0],
56 lods: const <ModelLod>[
57 ModelLod(surfaceIndices: <int>[1], maxScreenFraction: 0.34),
58 ModelLod(surfaceIndices: <int>[2], maxScreenFraction: 0.15),
59 ],
60 );
61 final ModelAsset asset = ModelAsset(
62 name: 'sphere lod asset',
63 parts: parts,
64 nodes: <ModelNode>[node],
65 roots: const <int>[0],
66 localBounds: parts.first.mesh.bounds,
67 );
69 final Scene scene = Scene()
70 ..ambientColor = Vector3(0.42, 0.5, 0.68)
71 ..ambientIntensity = 0.14
72 ..add(
73 LightNode(name: 'sun', intensity: 3.2)
74 ..setLocalForward(Vector3(-0.46, -0.82, -0.34)),
75 );
76 asset.instantiate(scene);
77 _group = scene.lodGroups.single;
78 return scene;
79 }
81 double _screenFraction(Scene scene) =>
82 _group.screenFraction(scene.cameras.single);
85 void verify(Scene scene, FrameResult frame) {
86 final int visibleLevels = _group.levels
87 .where((LodLevel level) => level.node.visible)
88 .length;
89 final double fraction = _screenFraction(scene);
90 if (scene.lodGroups.single != _group ||
91 _group.activeLevel < 0 ||
92 _group.activeLevel >= _group.levels.length ||
93 visibleLevels != 1 ||
94 fraction <= 0.0 ||
95 frame.drawCalls < 1) {
96 throw StateError('the LOD group did not select one visible mesh');
97 }
98 }
99}