cut-it / src /LaserCutter.ts
KaygNas's picture
Add LaserCutter;
4d603ca
import type { Mesh, Scene } from '@babylonjs/core'
import { Animation, Color3, Color4, CubicEase, GlowLayer, Matrix, MeshBuilder, ParticleSystem, StandardMaterial, Texture, TransformNode, Vector3 } from '@babylonjs/core'
export class LaserCutter {
scene: Scene
pivot: Mesh
beam: Mesh
sparkEmitter: Mesh
sparks: ParticleSystem
constructor(scene: Scene) {
this.scene = scene
const pivot = this.createLasePivot(scene)
const sparkEmitter = this.createSparkEmitter(scene)
const beam = this.createBeam(pivot.position, sparkEmitter.position, scene)
const sparks = this.createSparks(sparkEmitter, scene)
const gl = new GlowLayer('GlowLayer', scene)
gl.addIncludedOnlyMesh(beam)
gl.intensity = 2
this.pivot = pivot
this.sparkEmitter = sparkEmitter
this.beam = beam
this.sparks = sparks
}
async cut(path: Vector3[]) {
this.beam.isVisible = true
this.sparks.start()
for (let i = 1; i < path.length; i++)
await this.move(path[i - 1], path[i])
this.sparks.stop()
this.beam.isVisible = false
}
private async move(from: Vector3, to: Vector3) {
const { scene } = this
const SPEED = 1.0
const frameRate = 1 / (to.subtract(from).length() / SPEED)
const anim = new Animation('Move', 'position', frameRate, Animation.ANIMATIONTYPE_VECTOR3, Animation.ANIMATIONLOOPMODE_CONSTANT)
anim.setKeys([
{ frame: 0, value: from },
{ frame: 1, value: to },
])
anim.setEasingFunction(new CubicEase())
const tn = new TransformNode('Target')
tn.animations.push(anim)
const animatable = scene.beginAnimation(tn, 0, 1)
const trackTarget = () => {
this.attachTo(tn.position)
}
const observer = scene.onBeforeRenderObservable.add(trackTarget)
await animatable.waitAsync()
observer?.remove()
}
private attachTo(target: Vector3) {
const start = this.pivot.getAbsolutePosition()
const direction = target.subtract(start).normalize()
const offset = direction.negate().scale(0.01)
this.sparkEmitter.setAbsolutePosition(target.add(offset))
this.createBeam(this.pivot.getAbsolutePosition(), this.sparkEmitter.getAbsolutePosition(), this.scene, this.beam)
}
private createLasePivot(scene: Scene) {
const laserPivot = MeshBuilder.CreateSphere('Target', { diameter: 0.1 }, scene)
laserPivot.position = new Vector3(0, 0, 0)
laserPivot.isVisible = false
return laserPivot
}
private createSparkEmitter(scene: Scene) {
const sparkEmitter = MeshBuilder.CreateSphere('Spark', { diameter: 0.1, segments: 32 }, scene)
sparkEmitter.position = new Vector3(0, 0, 0)
sparkEmitter.isVisible = false
return sparkEmitter
}
private createBeam(start: Vector3, end: Vector3, scene: Scene, mesh?: Mesh) {
const beam = MeshBuilder.CreateTube('Laser', { path: [start, end], radius: 0.05, instance: mesh }, scene)
beam.bakeTransformIntoVertices(Matrix.Translation(0, 0, 0))
const laserBeamMtl = new StandardMaterial('Emissive')
laserBeamMtl.emissiveColor = new Color3(1, 0, 0)
beam.material = laserBeamMtl
return beam
}
private createSparks(emitter: Mesh, scene: Scene) {
const sparks = new ParticleSystem('Sparks', 1000, scene)
sparks.createPointEmitter(new Vector3(1, 1, 1), Vector3.Up())
sparks.particleTexture = new Texture('textures/flare.png')
sparks.emitter = emitter
sparks.emitRate = 160
sparks.color1 = new Color4(1, 0.12, 0)
sparks.color2 = new Color4(1, 0.37, 0)
sparks.maxSize = 0.15
sparks.minSize = 0.1
sparks.minEmitPower = 2
sparks.maxEmitPower = 6
sparks.maxLifeTime = 3
sparks.minLifeTime = 0.5
sparks.gravity = new Vector3(0, -3, 0)
return sparks
}
}