| |
| |
| |
|
|
| import { |
| AdditiveBlending, BufferAttribute, BufferGeometry, CanvasTexture, |
| Color, Points, PointsMaterial, |
| } from 'three'; |
|
|
| function starTexture() { |
| const c = document.createElement('canvas'); |
| c.width = c.height = 64; |
| const ctx = c.getContext('2d'); |
| const g = ctx.createRadialGradient(32, 32, 0, 32, 32, 32); |
| g.addColorStop(0, 'rgba(255,255,255,1)'); |
| g.addColorStop(0.35, 'rgba(255,255,255,0.85)'); |
| g.addColorStop(0.7, 'rgba(255,255,255,0.15)'); |
| g.addColorStop(1, 'rgba(255,255,255,0)'); |
| ctx.fillStyle = g; |
| ctx.beginPath(); ctx.arc(32, 32, 32, 0, Math.PI * 2); ctx.fill(); |
| const t = new CanvasTexture(c); |
| t.needsUpdate = true; |
| return t; |
| } |
|
|
| export class ParticleField { |
| constructor(scene) { |
| this.scene = scene; |
| const N = 700; |
| const geom = new BufferGeometry(); |
| const pos = new Float32Array(N * 3); |
| for (let i = 0; i < N; i++) { |
| pos[i * 3] = (Math.random() * 2 - 1) * 90; |
| pos[i * 3 + 1] = 12 + Math.random() * 45; |
| pos[i * 3 + 2] = -20 - Math.random() * 55; |
| } |
| geom.setAttribute('position', new BufferAttribute(pos, 3)); |
| this.material = new PointsMaterial({ |
| size: 0.6, |
| color: 0xffffff, |
| map: starTexture(), |
| transparent: true, |
| opacity: 0, |
| blending: AdditiveBlending, |
| depthWrite: false, |
| }); |
| this.points = new Points(geom, this.material); |
| this.scene.add(this.points); |
| this.t = 0; |
| } |
|
|
| applyPalette(p) { |
| this.targetOpacity = p.starOpacity; |
| } |
|
|
| update(dt) { |
| this.t += dt; |
| this.points.rotation.y += 0.005 * dt; |
| if (this.targetOpacity !== undefined) { |
| this.material.opacity += (this.targetOpacity - this.material.opacity) * 0.04; |
| } |
| |
| this.material.size = 0.55 + Math.sin(this.t * 2) * 0.07; |
| } |
| } |
|
|