flutter3d
Showcase Changelog 38 packages API reference

A Catmull-Rom path: the source

since 0.4.0 or earlier Simulation, audio and XR

Regions the guide quotes: track (line 15), sample (line 43), measure (line 66).

1/// A smooth curve through a list of points, measured in metres rather than
2/// in the unitless parameter a cubic spline is naturally described by.
3///
4/// Quoted by `splines.md` and shown whole in the Source tab.
5library;
6
7import 'package:flutter3d/flutter3d.dart';
8import 'package:flutter3d_showcase/src/demo/demo.dart';
9import 'package:flutter3d_sim/flutter3d_sim.dart';
10import 'package:vector_math/vector_math.dart';
12final class SplinesDemo extends ShowcaseDemo {
13 double distance = 0.0;
15 late final CatmullRom _track = CatmullRom(<Vector3>[
16 Vector3(1.2, 0, 0),
17 Vector3(0, 0, 1.2),
18 Vector3(-1.2, 0, 0),
19 Vector3(0, 0, -1.2),
20 ]);
22 late final MeshNode _car;
23 final Vector3 _point = Vector3.zero();
25 @override
26 Scene build(DemoContext context) {
27 final material = Material(
28 name: 'car',
29 baseColor: Vector4(0.9, 0.3, 0.3, 1.0),
30 );
31 _car = MeshNode(
32 DeviceMesh.upload(context.device, SphereShape(segments: 16).build()),
33 material,
34 );
35 return Scene()
36 ..add(_car)
37 ..add(
38 LightNode(name: 'sun', intensity: 3.0)
39 ..setLocalForward(Vector3(-0.4, -1.0, -0.3)),
40 );
41 }
43 @override
44 void update(DemoContext context, double dt) {
45 distance = _track.wrap(distance + dt * 2.0);
46 _track.sampleAt(distance, _point);
47 _car.setPositionFrom(_point);
48 }
50 @override
51 List<DemoControl> controls(DemoContext context) => <DemoControl>[
52 SliderControl(
53 'Distance along the loop (m)',
54 min: 0,
55 max: _track.length,
56 value: () => distance,
57 onChanged: (double v) => distance = v,
58 ),
59 ];
61 @override
62 void verify(Scene scene, FrameResult frame) {
63 if (frame.drawCalls < 1) {
64 throw StateError('the car marker was not drawn');
65 }
66 // A closed loop through four points three metres from the centre comes
67 // back to its own start.
68 final start = Vector3.zero();
69 _track.sampleAt(0.0, start);
70 final afterALap = Vector3.zero();
71 _track.sampleAt(_track.length, afterALap);
72 final gap = (start - afterALap).length;
73 if (gap > 0.01) {
74 throw StateError(
75 'a closed spline should return to its own start '
76 'after one full length, gap was $gap',
77 );
78 }
79 }