flutter3d
Showcase Changelog 38 packages API reference

Transparency without sorting: the source

since 0.8.0 Shading and materials

Regions the guide quotes: panes (line 32), wall (line 64), settings (line 84).

1/// Coloured panes at three depths and two that cross through each other,
2/// composited sorted or without a sort.
3///
4/// Quoted by `order_independent_transparency.md` and shown whole in the Source
5/// tab.
6library;
7
8import 'dart:math' as math;
9
10import 'package:flutter3d/flutter3d.dart';
11import 'package:flutter3d_showcase/src/demo/demo.dart';
12import 'package:vector_math/vector_math.dart';
14final class OrderIndependentTransparencyDemo extends ShowcaseDemo {
15 int mode = 1;
17 static const List<TransparencyMode> _modes = <TransparencyMode>[
18 TransparencyMode.sorted,
19 TransparencyMode.weightedBlended,
20 ];
22 @override
23 void configureView(DemoContext context) {
24 context.orbit
25 ..distance = 3.2
26 ..yaw = 0.35
27 ..pitch = 0.15;
28 }
30 @override
31 Scene build(DemoContext context) {
32 final DeviceMesh quad = DeviceMesh.upload(
33 context.device,
34 const PlaneShape(width: 1.2, depth: 1.2).build(),
35 );
36 final List<({double x, double z, double yaw, Vector4 colour})> panes =
37 <({double x, double z, double yaw, Vector4 colour})>[
38 (x: -0.3, z: 0.6, yaw: 0.0, colour: Vector4(0.9, 0.1, 0.1, 0.5)),
39 (x: 0.0, z: 0.0, yaw: 0.0, colour: Vector4(0.1, 0.9, 0.1, 0.45)),
40 (x: 0.3, z: -0.6, yaw: 0.0, colour: Vector4(0.1, 0.2, 0.9, 0.6)),
41 // These two cross through each other: no order of the two is right
42 // for every pixel.
43 (x: 0.1, z: 0.3, yaw: 0.6, colour: Vector4(0.9, 0.8, 0.1, 0.4)),
44 (x: 0.1, z: 0.3, yaw: -0.6, colour: Vector4(0.8, 0.1, 0.9, 0.35)),
45 ];
46 final Scene scene = Scene();
47 for (final pane in panes) {
48 scene.add(
49 MeshNode(
50 quad,
51 Material(
52 lighting: LightingModel.unlit,
53 baseColor: pane.colour,
54 alphaMode: MaterialAlphaMode.blend,
55 doubleSided: true,
56 ),
57 name: 'pane',
58 )
59 ..setPosition(pane.x, 0.0, pane.z)
60 ..setRotationYawPitchRoll(pane.yaw, math.pi / 2, 0.0),
61 );
62 }
64 return scene..add(
65 MeshNode(
66 DeviceMesh.upload(
67 context.device,
68 const PlaneShape(width: 8, depth: 8).build(),
69 ),
70 Material(
71 lighting: LightingModel.unlit,
72 baseColor: Vector4(0.45, 0.45, 0.45, 1.0),
73 doubleSided: true,
74 ),
75 name: 'wall',
76 )
77 ..setPosition(0.0, 0.0, -1.6)
78 ..setRotationYawPitchRoll(0.0, math.pi / 2, 0.0),
79 );
80 }
82 @override
83 RenderSettings settings(DemoContext context) => RenderSettings(
84 transparency: _modes[mode],
85 );
87 @override
88 List<DemoControl> controls(DemoContext context) => <DemoControl>[
89 ChoiceControl(
90 'Transparency',
91 options: const <String>['Sorted', 'Weighted blended'],
92 index: () => mode,
93 onChanged: (int i) => mode = i,
94 ),
95 ];
97 @override
98 void verify(Scene scene, FrameResult frame) {
99 final FramePass? pass = frame.passes
100 .where((FramePass p) => p.name == 'scene')
101 .firstOrNull;
102 if (pass == null) throw StateError('the scene pass did not run');
103 // Weighted blended adds one full-screen resolve to the scene pass, on top
104 // of a draw for every mesh.
105 final int meshes = scene.meshes.length;
106 final int expected = _modes[mode] == TransparencyMode.weightedBlended
107 ? meshes + 1
108 : meshes;
109 if (pass.drawCalls < expected) {
110 throw StateError(
111 'the scene pass drew ${pass.drawCalls}, expected at least $expected',
112 );
113 }
114 }