Light channels: the source
Open the live demo · Read the guide · View on GitHub
Regions the guide quotes: channels (line 31), live (line 65), check (line 83).
1/// `LightNode.channels` against `SceneNode.lightChannels`: a light reaches an
2/// object only when the two bit masks share a bit.
3///
4/// Quoted by `light_channels.md` and shown whole in the Source tab.
5library;
7import 'package:flutter3d/flutter3d.dart';
8import 'package:flutter3d_showcase/src/demo/demo.dart';
9import 'package:vector_math/vector_math.dart';
11final class LightChannelsDemo extends ShowcaseDemo {
12 bool sameChannel = false;
14 late final LightNode _redLight;
15 late final MeshNode _redBall;
18 void configureView(DemoContext context) {
19 context.orbit
20 ..distance = 6.0
21 ..pitch = 0.15;
22 }
25 Scene build(DemoContext context) {
26 final DeviceMesh sphere = DeviceMesh.upload(
27 context.device,
28 SphereShape(segments: 32, rings: 16).build(),
29 );
31 // Channel 0 for the near ball and its own light, channel 1 for the far
32 // one: the mask a light and a node meet on decides whether it reaches it,
33 // never distance or anything the shader has to guess about.
34 _redBall = MeshNode(
35 sphere,
36 Material(baseColor: Vector4(0.8, 0.8, 0.8, 1.0)),
37 name: 'near ball',
38 )..lightChannels = LightChannels.only(0);
39 final MeshNode farBall =
40 MeshNode(
41 sphere,
42 Material(baseColor: Vector4(0.8, 0.8, 0.8, 1.0)),
43 name: 'far ball',
44 )
45 ..setPosition(2.4, 0.0, 0.0)
46 ..lightChannels = LightChannels.only(1);
48 _redLight = LightNode(name: 'red', type: LightType.point, intensity: 6.0)
49 ..color.setValues(1.0, 0.25, 0.2)
50 ..channels = LightChannels.only(0)
51 ..setPosition(0.0, 1.6, 1.2);
53 final LightNode fill = LightNode(name: 'fill', intensity: 1.2)
54 ..setLocalForward(Vector3(-0.3, -0.6, -0.6));
56 return Scene()
57 ..add(_redBall)
58 ..add(farBall)
59 ..add(_redLight)
60 ..add(fill);
61 }
64 void update(DemoContext context, double dt) {
65 // With the toggle on, the near ball opens its second bit too and the
66 // light starts reaching it exactly as it always reached the far one.
67 _redBall.lightChannels = sameChannel
68 ? (LightChannels.only(0) | LightChannels.only(1))
69 : LightChannels.only(0);
70 }
73 List<DemoControl> controls(DemoContext context) => <DemoControl>[
74 ToggleControl(
75 'Near ball also on channel 1',
76 value: () => sameChannel,
77 onChanged: (bool v) => sameChannel = v,
78 ),
79 ];
82 void verify(Scene scene, FrameResult frame) {
83 if (!LightBuffer.reaches(_redLight, _redBall.lightChannels)) {
84 throw StateError('the red light does not reach the ball it lights');
85 }
86 if (_redLight.channels == LightChannels.all) {
87 throw StateError('the light was never restricted to a channel');
88 }
89 if (frame.drawCalls < 2) {
90 throw StateError('not every ball was drawn');
91 }
92 }
93}