Stretched highlights: the source
Open the live demo · Read the guide · View on GitHub
Regions the guide quotes: materials (line 28), mesh (line 45), live (line 66).
1/// One highlight round, the same highlight stretched: the anisotropy layer.
2///
3/// Quoted by `anisotropic_highlights.md` and shown whole in the Source tab.
4library;
6import 'dart:math' as math;
8import 'package:flutter3d/flutter3d.dart';
9import 'package:flutter3d_showcase/src/demo/demo.dart';
10import 'package:vector_math/vector_math.dart';
12final class AnisotropicHighlightsDemo extends ShowcaseDemo {
13 double strength = 0.9;
14 double rotation = 0.0;
16 late final Material _brushed;
19 void configureView(DemoContext context) {
20 context.orbit
21 ..distance = 3.4
22 ..yaw = 0.0
23 ..pitch = 0.1;
24 }
27 Scene build(DemoContext context) {
28 final Material plain = Material(
29 name: 'plain',
30 lighting: LightingModel.pbrLayered,
31 baseColor: Vector4(0.8, 0.05, 0.05, 1.0),
32 roughness: 0.3,
33 );
34 _brushed = Material(
35 name: 'brushed',
36 lighting: LightingModel.pbrLayered,
37 baseColor: Vector4(0.8, 0.05, 0.05, 1.0),
38 roughness: 0.3,
39 extensions: MaterialExtensions(
40 anisotropyStrength: strength,
41 anisotropyRotation: rotation,
42 ),
43 );
45 // A sphere from `SphereShape` carries a tangent at every vertex, running
46 // around the sphere along its lines of latitude.
47 final DeviceMesh ball = DeviceMesh.upload(
48 context.device,
49 SphereShape(radius: 0.5, segments: 48, rings: 24).build(),
50 );
52 return Scene()
53 ..ambientIntensity = 0.15
54 ..add(MeshNode(ball, plain, name: 'plain')..setPosition(-0.6, 0.0, 0.0))
55 ..add(
56 MeshNode(ball, _brushed, name: 'brushed')..setPosition(0.6, 0.0, 0.0),
57 )
58 ..add(
59 LightNode(name: 'key', intensity: 3.0)
60 ..setLocalForward(Vector3(-0.35, -0.45, -1.0).normalized()),
61 );
62 }
65 void update(DemoContext context, double dt) {
66 _brushed.extensions = MaterialExtensions(
67 anisotropyStrength: strength,
68 anisotropyRotation: rotation,
69 );
70 }
73 List<DemoControl> controls(DemoContext context) => <DemoControl>[
74 SliderControl(
75 'Strength',
76 min: 0,
77 max: 1,
78 value: () => strength,
79 onChanged: (double v) => strength = v,
80 ),
81 SliderControl(
82 'Rotation',
83 min: 0,
84 max: math.pi,
85 value: () => rotation,
86 onChanged: (double v) => rotation = v,
87 format: (double v) => '${(v * 180 / math.pi).round()}°',
88 ),
89 ];
92 void verify(Scene scene, FrameResult frame) {
93 final MeshNode brushed = scene.meshes.firstWhere(
94 (MeshNode m) => m.name == 'brushed',
95 );
96 if (!identical(brushed.material.lighting, LightingModel.pbrLayered)) {
97 throw StateError('the brushed sphere is not on the layered model');
98 }
99 if ((brushed.material.extensions?.anisotropyStrength ?? 0.0) <= 0.0) {
100 throw StateError('the brushed sphere has no anisotropy');
101 }
102 if (frame.drawCalls < 2) {
103 throw StateError('the two spheres were not both drawn');
104 }
105 }
106}