flutter3d
Showcase Changelog 38 packages API reference

Cascaded shadows: the source

since 0.2.0 Shadows

Regions the guide quotes: floor (line 30), pillars (line 44), sun (line 56), settings (line 65).

1/// The sun's shadow, split into cascades so that it is sharp near you and
2/// still reaches the horizon.
3///
4/// Quoted by `cascaded_shadows.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 CascadedShadowsDemo extends ShowcaseDemo {
12 int cascades = 3;
13 double split = 0.7;
14 double viewDistance = 60.0;
15 int resolutionChoice = 1;
17 static const List<int> _resolutions = <int>[512, 1024, 2048];
19 @override
20 void configureView(DemoContext context) {
21 context.orbit
22 ..distance = 9.0
23 ..pitch = 0.35
24 ..yaw = 0.5;
25 context.orbit.target.setValues(0.0, 1.0, -14.0);
26 }
28 @override
29 Scene build(DemoContext context) {
30 final Material stone = Material(
31 name: 'stone',
32 baseColor: Vector4(0.72, 0.7, 0.66, 1.0),
33 roughness: 0.85,
34 );
35 final MeshNode floor = MeshNode(
36 DeviceMesh.upload(
37 context.device,
38 const PlaneShape(width: 80, depth: 80).build(),
39 ),
40 stone.copy()..doubleSided = true,
41 name: 'floor',
42 );
44 final Scene scene = Scene()..add(floor);
45 final DeviceMesh pillar = DeviceMesh.upload(
46 context.device,
47 CuboidShape(size: Vector3(1.0, 3.0, 1.0)).build(),
48 );
49 for (var i = 0; i < 10; i++) {
50 scene.add(
51 MeshNode(pillar, stone, name: 'pillar $i')
52 ..setPosition(i.isEven ? -3.0 : 3.0, 1.5, -i * 5.0),
53 );
54 }
56 scene.add(
57 LightNode(name: 'sun', intensity: 3.0, castsShadow: true)
58 ..setLocalForward(Vector3(-0.5, -0.8, -0.3)),
59 );
60 return scene;
61 }
63 @override
64 RenderSettings settings(DemoContext context) => RenderSettings(
65 shadows: ShadowSettings(
66 cascades: cascades,
67 cascadeSplit: split,
68 viewDistance: viewDistance,
69 resolution: _resolutions[resolutionChoice],
70 ),
71 );
73 @override
74 List<DemoControl> controls(DemoContext context) => <DemoControl>[
75 SliderControl(
76 'Cascades',
77 min: 1,
78 max: 4,
79 divisions: 3,
80 value: () => cascades.toDouble(),
81 onChanged: (double v) => cascades = v.round(),
82 format: (double v) => '${v.round()}',
83 ),
84 SliderControl(
85 'Split',
86 min: 0.1,
87 max: 0.95,
88 value: () => split,
89 onChanged: (double v) => split = v,
90 ),
91 SliderControl(
92 'Shadow distance',
93 min: 10,
94 max: 120,
95 value: () => viewDistance,
96 onChanged: (double v) => viewDistance = v,
97 format: (double v) => '${v.round()} m',
98 ),
99 ChoiceControl(
100 'Map size',
101 options: <String>[for (final int r in _resolutions) '$r'],
102 index: () => resolutionChoice,
103 onChanged: (int i) => resolutionChoice = i,
104 ),
105 ];
107 @override
108 void verify(Scene scene, FrameResult frame) {
109 if (frame.shadowsDenied > 0) {
110 throw StateError('the sun was denied its shadow');
111 }
112 }