drawStars function
📲 Draw Stars
We draw this starfield canvas - on the Canvas size - with a size rotation - and a rotation around center time - at a specific time
It fills the canvas
Implementation
void drawStars(Canvas canvas, Size size, double rotation, double time) {
/// 📷 Creates a 140 degree projection matrix for our size,
/// with a near of 0 and a far of 1
/// and rotates around the Z axis by rotation degrees
final projection = vector.makePerspectiveMatrix(
140, size.width / size.height, 0, 1)
..rotateZ(rotation);
/// 🧮 Generates a "page" of stars (back to front) of varying opacities
/// We draw pages to minimize draw calls
/// E.g.
/// 1 Draw Call = Single Paint, all stars look the same
/// 1 Draw Call for 1,000 stars = slow, inefficient
/// Solution: Create kSteps/pages and draw each page with a common
/// paint back to front (painters algorithm)
/// This allows me to artistically handle distance variations
/// without tanking performance.
final intervals = List.generate(kSteps, (idx) => idx / kSteps.toDouble());
for (final interval in intervals) {
/// 🎨 Generate star color based on the current page
/// We fade the opacity with distance to camera
///
/// We also adjust the size based on distance (between 1-2 px)
_starsPaint
..color = Colors.white.withOpacity(1 - interval)
..strokeWidth = (1 - interval) + 1.5;
// 🖌️ Draw the points
canvas.drawPoints(
PointMode.points,
_stars
// ✂️ where star Z is in current interval
.where((star) => star
.zForTime(time)
.chain((z) => z > interval && z < (interval + kStepSize)))
// 📺 Convert this Star into a Screen Space Offset
.map((star) => star
.project(time, projection) // Project to screen space
.translate(
0.5, 0.5) // Transform it from -0.5->0.5 range to 0-1 range
.scale(size.width,
size.height)) // Scale it from 0-1 range to canvas size
//Creates a List<Offset> to draw, from all stars
.toList(),
_starsPaint);
}
}