flutter3d
Showcase Changelog 38 packages API reference

Mesh particles: the source

since 0.2.0 or earlier Physics and particles

Regions the guide quotes: mesh (line 34), contributor (line 53), check (line 78).

1/// Every live particle drawn as a copy of a real mesh instead of a
2/// camera-facing quad, in one instanced call.
3///
4/// Quoted by `mesh_particles.md` and shown whole in the Source tab.
5library;
6
7import 'package:flutter3d/flutter3d.dart';
8import 'package:flutter3d_particles/flutter3d_particles.dart';
9import 'package:flutter3d_showcase/src/demo/demo.dart';
10import 'package:vector_math/vector_math.dart';
12final class MeshParticlesDemo extends ShowcaseDemo {
13 late final ParticleSystem _particles;
14 late final ParticleEffect _debrisEffect;
15 late final MeshParticleContributor _contributor;
17 static const int _count = 40;
19 // Debris that fell once and lay still would leave nothing moving to look
20 // at once gravity settled it below the frame.
21 static const double _pause = 1.0;
22 double _cooldown = 0.0;
24 @override
25 void configureView(DemoContext context) {
26 context.orbit
27 ..distance = 4.5
28 ..pitch = 0.25
29 ..yaw = 0.4;
30 }
32 @override
33 Scene build(DemoContext context) {
34 // One shape, uploaded once. Every particle is a placement of it rather
35 // than a separate draw, which is what keeps this a single instanced call
36 // however many shards are on screen.
37 final DeviceMesh shard = DeviceMesh.upload(
38 context.device,
39 CuboidShape(size: Vector3(0.12, 0.12, 0.12)).build(),
40 );
42 _particles = ParticleSystem(capacity: _count, seed: 808);
43 _debrisEffect = ParticleEffect(
44 count: _count,
45 emitter: const SphereEmitter(speed: Range(1.0, 2.5)),
46 lifetime: const Range(1.0, 1.8),
47 size: const Range(0.6, 1.2),
48 color: Vector4(0.8, 0.75, 0.7, 1.0),
49 affectors: <ParticleAffector>[const ParticleGravity(-3.0)],
50 );
51 _particles.burst(_debrisEffect, Vector3.zero());
53 _contributor = context.renderer.addContributor(
54 MeshParticleContributor(_particles, mesh: shard),
55 );
57 return Scene()..add(
58 LightNode(name: 'sun', intensity: 2.0)
59 ..setLocalForward(Vector3(-0.3, -0.6, -0.4)),
60 );
61 }
63 @override
64 void update(DemoContext context, double dt) {
65 _particles.advance(dt);
67 if (_particles.aliveCount == 0) {
68 _cooldown -= dt;
69 if (_cooldown <= 0.0) {
70 _particles.burst(_debrisEffect, Vector3.zero());
71 _cooldown = _pause;
72 }
73 }
74 }
76 @override
77 void verify(Scene scene, FrameResult frame) {
78 if (!_contributor.isActive) {
79 throw StateError('the mesh particles should be alive and drawing');
80 }
81 if (_particles.aliveCount != _count || frame.drawCalls < 1) {
82 throw StateError('the shards did not reach the frame');
83 }
84 }