WebGL2: the source
Open the live demo · Read the guide · View on GitHub
Regions the guide quotes: fallback (line 39), settings (line 51), read (line 55).
1/// The browser path: WebGL2 over a canvas the browser composites, the
2/// second implementation of `flutter3d_hardware`.
3///
4/// Quoted by `backend_webgl.md` and shown whole in the Source tab.
5library;
7import 'package:flutter/widgets.dart';
8import 'package:flutter3d/flutter3d.dart';
9import 'package:flutter3d_showcase/src/demo/demo.dart';
10import 'package:vector_math/vector_math.dart';
12final class BackendWebglDemo extends ShowcaseDemo {
13 late final GraphicsDevice _device;
16 Scene build(DemoContext context) {
17 _device = context.device;
18 final Material stone = Material(
19 name: 'stone',
20 baseColor: Vector4(0.4, 0.55, 0.7, 1.0),
21 roughness: 0.6,
22 );
23 final MeshNode ball = MeshNode(
24 DeviceMesh.upload(
25 context.device,
26 SphereShape(segments: 24, rings: 12).build(),
27 ),
28 stone,
29 name: 'ball',
30 );
31 return Scene()
32 ..add(ball)
33 ..add(
34 LightNode(name: 'sun', intensity: 3.0)
35 ..setLocalForward(Vector3(-0.4, -1.0, -0.3)),
36 );
37 }
39 // On the web, `flutter3d_app`'s `openDevice` registers WebGL2 always and
40 // WebGPU only when the build was compiled with
41 // `--dart-define=FLUTTER3D_WEBGPU=true`. Either way it asks the shared
42 // registry for a backend rather than choosing one by name:
43 //
44 // ensureWebGlBackendRegistered();
45 // if (tryWebGpu) registerBackendOpener('WebGPU', openWebGpu);
46 // return openRegisteredDevice(width: width, height: height, ...);
47 //
48 // A build that never asked for WebGPU never carries its code at all; a
49 // canvas that only WebGL2 can open still draws.
52 RenderSettings settings(DemoContext context) =>
53 const RenderSettings(wireframe: true);
55 String _report(GraphicsDevice device) =>
56 'wireframe: ${device.supportsWireframe}\n'
57 'offscreen MSAA: ${device.supportsOffscreenMsaa}\n'
58 'preferred samples: ${device.preferredSampleCount}\n'
59 'max anisotropy: ${device.maxAnisotropy}';
62 Widget? customBody(BuildContext buildContext, DemoContext context) =>
63 Container(
64 color: const Color(0xFF14161A),
65 padding: const EdgeInsets.all(24),
66 alignment: Alignment.topLeft,
67 child: DefaultTextStyle(
68 style: const TextStyle(color: Color(0xFFE8E8EC), fontSize: 16),
69 child: Text(
70 'WebGL2 has no glPolygonMode, so it answers false to wireframe the '
71 'same way the software rasteriser does: drawing triangles as edges '
72 'needs line primitives this API does not expose. Anisotropic '
73 'filtering and multisampling both depend on extensions the browser '
74 'may or may not hand back.\n\n'
75 'What the device actually open right now answers:\n\n'
76 '${_report(context.device)}',
77 ),
78 ),
79 );
82 void verify(Scene scene, FrameResult frame) {
83 if (frame.drawCalls < 1) {
84 throw StateError('the ball was not drawn');
85 }
86 if (frame.wireframeDeclined != !_device.supportsWireframe) {
87 throw StateError(
88 'wireframeDeclined disagreed with supportsWireframe for the open '
89 'device',
90 );
91 }
92 }
93}