What a frame reports: the source
Open the live demo · Read the guide · View on GitHub
Regions the guide quotes: geometry (line 24), light (line 69), totals (line 91), check (line 102).
1/// A small mixed scene whose result exposes useful frame counters.
2library;
4import 'package:flutter3d/flutter3d.dart';
5import 'package:flutter3d_showcase/src/demo/demo.dart';
6import 'package:vector_math/vector_math.dart';
8final class FrameStatsDemo extends ShowcaseDemo {
9 bool shadows = true;
11 late final LightNode _sun;
14 void configureView(DemoContext context) {
15 context.orbit
16 ..distance = 8.0
17 ..pitch = 0.3
18 ..yaw = 0.5;
19 context.orbit.target.setValues(0.0, 0.7, 0.0);
20 }
23 Scene build(DemoContext context) {
24 final Material matte = Material(
25 name: 'matte',
26 baseColor: Vector4(0.24, 0.62, 0.82, 1.0),
27 roughness: 0.72,
28 );
29 final Material metal = Material(
30 name: 'metal',
31 baseColor: Vector4(0.82, 0.43, 0.18, 1.0),
32 metallic: 0.76,
33 roughness: 0.24,
34 );
35 final Scene scene = Scene()
36 ..ambientColor = Vector3(0.42, 0.5, 0.68)
37 ..ambientIntensity = 0.12
38 ..add(
39 MeshNode(
40 DeviceMesh.upload(
41 context.device,
42 const PlaneShape(width: 8.0, depth: 7.0).build(),
43 ),
44 matte.copy()..doubleSided = true,
45 name: 'floor',
46 )..castsShadow = false,
47 )
48 ..add(
49 MeshNode(
50 DeviceMesh.upload(
51 context.device,
52 CuboidShape(size: Vector3.all(1.5)).build(),
53 ),
54 matte,
55 name: 'cube',
56 )..setPosition(-1.25, 0.75, 0.0),
57 )
58 ..add(
59 MeshNode(
60 DeviceMesh.upload(
61 context.device,
62 const TorusShape(radius: 0.72, tubeRadius: 0.28).build(),
63 ),
64 metal,
65 name: 'torus',
66 )..setPosition(1.35, 1.0, 0.0),
67 );
69 _sun = LightNode(name: 'sun', intensity: 3.2, castsShadow: shadows)
70 ..setLocalForward(Vector3(-0.45, -0.82, -0.35));
71 scene.add(_sun);
72 return scene;
73 }
76 void update(DemoContext context, double dt) {
77 _sun.castsShadow = shadows;
78 }
81 List<DemoControl> controls(DemoContext context) => <DemoControl>[
82 ToggleControl(
83 'Shadow pass',
84 value: () => shadows,
85 onChanged: (bool value) => shadows = value,
86 ),
87 ];
90 void verify(Scene scene, FrameResult frame) {
91 final FramePass scenePass = frame.passes.firstWhere(
92 (FramePass pass) => pass.name == 'scene',
93 );
94 final FramePass compositePass = frame.passes.firstWhere(
95 (FramePass pass) => pass.name == 'composite',
96 );
97 final int passDraws = frame.passes.fold<int>(
98 0,
99 (int total, FramePass pass) => total + pass.drawCalls,
100 );
102 if (scenePass.drawCalls < 3 ||
103 compositePass.drawCalls != 1 ||
104 frame.drawCalls != passDraws ||
105 frame.triangles <= 0 ||
106 frame.pipelineSwitches <= 0 ||
107 frame.cpuMicros < frame.submitMicros) {
108 throw StateError('the frame counters do not describe the rendered scene');
109 }
110 }
111}