flutter3d
Showcase Changelog 38 packages API reference

Perspective and orthographic: the source

since 0.5.1 Views, picking and input

Regions the guide quotes: box (line 18), perspective (line 32), orthographic (line 43).

1/// Two ways to turn a scene into a flat picture: perspective, where things
2/// shrink with distance, and orthographic, where they do not.
3///
4/// Quoted by `projections.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:vector_math/vector_math.dart';
11final class ProjectionsDemo extends ShowcaseDemo {
12 int choice = 0;
14 late Projection _projection;
16 @override
17 Scene build(DemoContext context) {
18 final Material stone = Material(
19 name: 'stone',
20 baseColor: Vector4(0.7, 0.68, 0.64, 1.0),
21 roughness: 0.8,
22 );
23 final MeshNode box = MeshNode(
24 DeviceMesh.upload(
25 context.device,
26 CuboidShape(size: Vector3.all(1.4)).build(),
27 ),
28 stone,
29 name: 'box',
30 );
32 _projection = const PerspectiveProjection(fovYRadians: 0.9);
33 context.camera.projection = _projection;
35 return Scene()
36 ..add(box)
37 ..add(
38 LightNode(name: 'sun', intensity: 3.0)
39 ..setLocalForward(Vector3(-0.4, -1.0, -0.3)),
40 );
41 }
43 void _choose(int value) {
44 choice = value;
45 _projection = value == 0
46 ? const PerspectiveProjection(fovYRadians: 0.9)
47 : const OrthographicProjection(height: 3.0);
48 }
50 @override
51 void update(DemoContext context, double dt) {
52 context.camera.projection = _projection;
53 }
55 @override
56 List<DemoControl> controls(DemoContext context) => <DemoControl>[
57 ChoiceControl(
58 'Lens',
59 options: const <String>['Perspective', 'Orthographic'],
60 index: () => choice,
61 onChanged: _choose,
62 ),
63 ];
65 @override
66 void verify(Scene scene, FrameResult frame) {
67 if (frame.drawCalls < 1) {
68 throw StateError('the box was not drawn');
69 }
70 // A perspective matrix divides by depth: row 3 sends w to -z, so the
71 // bottom-right entry of the 4x4 is 0. An orthographic one does not: a
72 // point at any depth keeps w = 1, so that entry is 1. This is the one
73 // number that tells the two matrices apart.
74 final Matrix4 matrix = _projection.toMatrix(16 / 9);
75 final double bottomRight = matrix.storage[15];
76 final bool isOrthographic = _projection is OrthographicProjection;
77 if (isOrthographic && bottomRight != 1.0) {
78 throw StateError('an orthographic matrix should keep w at 1');
79 }
80 if (!isOrthographic && bottomRight != 0.0) {
81 throw StateError('a perspective matrix should not keep w at 1');
82 }
83 }