Lights in lumens and lux: the source
Open the live demo · Read the guide · View on GitHub
Regions the guide quotes: directional (line 40), point (line 45), live (line 60), check (line 84).
1/// `Photometric`: lux and lumens off a datasheet, converted into
2/// `LightNode.intensity` instead of tuned by eye.
3///
4/// Quoted by `photometric_units.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 PhotometricUnitsDemo extends ShowcaseDemo {
12 double overcastLux = 10000.0;
13 double lampLumens = 800.0;
15 late final LightNode _sky;
16 late final LightNode _lamp;
19 void configureView(DemoContext context) {
20 context.orbit
21 ..distance = 5.0
22 ..pitch = 0.2;
23 }
26 Scene build(DemoContext context) {
27 final DeviceMesh sphere = DeviceMesh.upload(
28 context.device,
29 SphereShape(segments: 32, rings: 16).build(),
30 );
31 final Scene scene = Scene()
32 ..add(
33 MeshNode(
34 sphere,
35 Material(baseColor: Vector4(0.8, 0.8, 0.8, 1.0)),
36 name: 'ball',
37 ),
38 );
40 // A directional light has no falloff, so its intensity is what a surface
41 // facing it reads: lux is the unit its own datasheet would give.
42 _sky = LightNode(name: 'sky', intensity: Photometric.fromLux(overcastLux))
43 ..setLocalForward(Vector3(-0.3, -0.7, -0.5));
45 // An 800 lm bulb is the ordinary sixty-watt incandescent it replaced.
46 _lamp = LightNode(
47 name: 'lamp',
48 type: LightType.point,
49 intensity: Photometric.fromLumens(lampLumens),
50 range: 8.0,
51 )..setPosition(1.6, 1.2, 1.0);
53 return scene
54 ..add(_sky)
55 ..add(_lamp);
56 }
59 void update(DemoContext context, double dt) {
60 _sky.intensity = Photometric.fromLux(overcastLux);
61 _lamp.intensity = Photometric.fromLumens(lampLumens);
62 }
65 List<DemoControl> controls(DemoContext context) => <DemoControl>[
66 SliderControl(
67 'Sky (lux)',
68 min: 500,
69 max: 20000,
70 value: () => overcastLux,
71 onChanged: (double v) => overcastLux = v,
72 ),
73 SliderControl(
74 'Lamp (lumens)',
75 min: 100,
76 max: 1600,
77 value: () => lampLumens,
78 onChanged: (double v) => lampLumens = v,
79 ),
80 ];
83 void verify(Scene scene, FrameResult frame) {
84 const double epsilon = 1e-6;
85 if ((Photometric.toLux(_sky.intensity) - overcastLux).abs() > epsilon) {
86 throw StateError('the sky intensity does not convert back to its lux');
87 }
88 if ((Photometric.toLumens(_lamp.intensity) - lampLumens).abs() > epsilon) {
89 throw StateError('the lamp intensity does not convert back to lumens');
90 }
91 if (frame.drawCalls < 1) {
92 throw StateError('the ball was not drawn');
93 }
94 }
95}