flutter3d
Showcase Changelog 38 packages API reference

X-ray silhouettes: the source

since 0.4.3 Post-processing

Regions the guide quotes: layer (line 14), hidden (line 66), settings (line 93), draws (line 113).

1/// X-ray silhouettes: the outline of what a wall hides, painted over the wall.
2///
3/// Quoted by `xray.md` and shown whole in the Source tab.
4library;
5
6import 'package:flutter3d/flutter3d.dart';
7import 'package:flutter3d_showcase/src/demo/demo.dart';
8import 'package:vector_math/vector_math.dart';
9
10final class XrayDemo extends ShowcaseDemo {
11 bool enabled = true;
12 int colourChoice = 0;
14 /// One bit of `layerMask`, picked so it does not collide with the default.
15 static const int _watched = 1 << 2;
17 static const List<String> _colourNames = <String>['Orange', 'Green', 'Cyan'];
19 Vector3 get _colour => switch (colourChoice) {
20 1 => Vector3(0.1, 1.0, 0.2),
21 2 => Vector3(0.1, 0.9, 1.0),
22 _ => Vector3(1.0, 0.32, 0.08),
23 };
25 late final int _meshCount;
26 late final bool _stencil;
28 @override
29 void configureView(DemoContext context) {
30 context.orbit
31 ..distance = 7.0
32 ..pitch = 0.2
33 ..yaw = 0.0;
34 context.orbit.target.setValues(0.0, 1.0, 0.0);
35 }
37 @override
38 Scene build(DemoContext context) {
39 final GraphicsDevice device = context.device;
40 _stencil = device.supportsStencil;
42 final MeshNode floor = MeshNode(
43 DeviceMesh.upload(device, const PlaneShape(width: 12, depth: 12).build()),
44 Material(
45 name: 'floor',
46 baseColor: Vector4(0.5, 0.5, 0.52, 1.0),
47 roughness: 0.9,
48 doubleSided: true,
49 ),
50 name: 'floor',
51 );
53 final MeshNode wall = MeshNode(
54 DeviceMesh.upload(
55 device,
56 CuboidShape(size: Vector3(4.0, 2.4, 0.3)).build(),
57 ),
58 Material(
59 name: 'wall',
60 baseColor: Vector4(0.65, 0.6, 0.55, 1.0),
61 roughness: 0.9,
62 ),
63 name: 'wall',
64 )..setPosition(0.0, 1.2, 0.0);
66 final MeshNode monster = MeshNode(
67 DeviceMesh.upload(
68 device,
69 const CapsuleShape(radius: 0.4, height: 0.9).build(),
70 ),
71 Material(
72 name: 'monster',
73 baseColor: Vector4(0.3, 0.7, 0.35, 1.0),
74 roughness: 0.5,
75 ),
76 name: 'monster',
77 )..setPosition(0.0, 0.85, -2.0);
78 monster.layerMask = 1 | _watched;
80 _meshCount = 3;
81 return Scene()
82 ..add(floor)
83 ..add(wall)
84 ..add(monster)
85 ..add(
86 LightNode(name: 'sun', intensity: 3.0)
87 ..setLocalForward(Vector3(-0.4, -0.8, -0.6)),
88 );
89 }
91 @override
92 RenderSettings settings(DemoContext context) => RenderSettings(
93 xray: XraySettings(layerMask: enabled ? _watched : 0, color: _colour),
94 );
96 @override
97 List<DemoControl> controls(DemoContext context) => <DemoControl>[
98 ToggleControl(
99 'X-ray',
100 value: () => enabled,
101 onChanged: (bool v) => enabled = v,
102 ),
103 ChoiceControl(
104 'Colour',
105 options: _colourNames,
106 index: () => colourChoice,
107 onChanged: (int i) => colourChoice = i,
108 ),
109 ];
111 @override
112 void verify(Scene scene, FrameResult frame) {
113 final int drawn = frame.passes
114 .firstWhere((FramePass p) => p.name == 'scene')
115 .drawCalls;
116 final int extra = enabled && _stencil ? 2 : 0;
117 if (drawn != _meshCount + extra) {
118 throw StateError(
119 'the scene pass made $drawn draws; $_meshCount meshes and '
120 '$extra x-ray draws were expected',
121 );
122 }
123 }