PK creative Spring Festival, I am participating in the “Spring Festival creative submission contest”, please see: Spring Festival creative submission Contest

preface

The Spring Festival is coming, in order to let everyone learn (touch) learn (fish) learning, this issue will introduce a 3D game engine through a simple fireworks case, wish everyone a happy New Year. Click experience. The general effect is as follows:

babylon

Babylon is a 3D JS game engine developed by Microsoft.

Introduction to the official website:

Our mission is to make it as easy as possible to create fun, good-looking, all-platform games, built on javascript and Web standards, surible.js eliminates cross-platform complexity so you can focus on what really matters: That is to create amazing and fun games for online game players.

That sounds like a hell of a lot

In fact, just like three.js, it is a 3D JS library. Three.js is more about rendering, whereas babylu.js is more about doing. Babylon. Js offers more apis than Three. js, such as animation rendering (three.js usually requires tween or RequestAnimationFrame), collision detection, etc.

The bottom line is that as complex an application, Babylon. Js can be written in much less code than Three.js (the focus is different, not that Babylon is superior).

It can be used to implement complex applications, such as LocalWar, a cs-like web shooter created by the creators of mashed potato. The demo is also shown on Babylon.

The installation

Yarn create vite Babyls-test // install dependency NPM install@babylonjs /coreCopy the code

hellow babylon

The next step is to create a Babylon version of Hellow World

html <body> <canvas id="canvas" style="width: 100%; height:100%;" /> <script type="module" src="/main.js"></script> </body> main.js import * as BABYLON from "@babylonjs/core" const canvas = document.getElementById('canvas') const engine = new Engine(canvas) const createScene = () => { const scene = new BABYLON.Scene(engine); Const camera = new BABYLON.ArcRotateCamera("camera", -math.pi / 2, math.pi / 2.5, 3, new BABYLON. camera.attachControl(canvas, true); const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0)); const box = BABYLON.MeshBuilder.CreateBox("box", {}); return scene; } const scene = createScene() engine.runRenderLoop(() => { scene.render(); })Copy the code

You can see a cube when you run it, or you can view it using the online demo

coordinates

Unlike three.js, Babybabylon. Js uses a left-handed coordinate system by default.

Again, using the code above, try coordinates to see the location

. const box = BABYLON.MeshBuilder.CreateBox("box", {}); Box. The position. The set (0, 0); .Copy the code

The three parameters of position are x, y, and z. You can see that when x is raised, the cube is moved up

Let’s try changing z again

. const box = BABYLON.MeshBuilder.CreateBox("box", {}); Box. The position. The set (0, 0); .Copy the code

You can see that the cube is moving into the screen, and it feels smaller.

Particle system

The simplest particle

You can go to the particle demo on the official website and create a particle that emits 2000 particles at the origin (0,0,0) and add a map.

const createScene = function () { const scene = new BABYLON.Scene(engine); Const camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", -math.PI / 2, Math. 0, 0), scene); camera.attachControl(canvas, true); const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene); // Create particle const particleSystem = new BABYLON.ParticleSystem(" Particles ", 2000); / / particle map particleSystem. ParticleTexture = new BABYLON. Texture (" textures/flare. PNG "); // Emitter.emitter = new BABYLON.Vector3(0,0, 0); particleSystem.start(); return scene; }Copy the code

Particle pictures should be symmetrical

Here is my attempt to use “fu” as a particle effect in parkour. Since “fu” is not a stacked pattern, the effect of the footprint particles is bad.

New Year fireworks

Initialization interface

A class is simply constructed.

To make it easier not to write canvas in the HTML of each project, we provide a canvas creation method, _createCanvas, and initialize the interface in the constructor to get a night background.

class App { _scene _canvas _engine constructor() { this._canvas = this._createCanvas(); this._engine = new Engine(this._canvas, true); this._scene = new Scene(this._engine); this._scene.clearColor = Color3.Black; const camera = new ArcRotateCamera("ArcRotateCamera", -1, 1, 100, new Vector3(0, 0, 0), this._scene); camera.attachControl(this._canvas, true); this._engine.runRenderLoop(() => { this._scene.render(); }) } _createCanvas(id = 'babylon') { document.documentElement.style["overflow"] = "hidden"; document.documentElement.style.overflow = "hidden"; document.documentElement.style.width = "100%"; document.documentElement.style.height = "100%"; document.documentElement.style.margin = "0"; document.documentElement.style.padding = "0"; document.body.style.overflow = "hidden"; document.body.style.width = "100%"; document.body.style.height = "100%"; document.body.style.margin = "0"; document.body.style.padding = "0"; this._canvas = document.createElement("canvas"); this._canvas.style.width = "100%"; this._canvas.style.height = "100%"; this._canvas.id = id; document.body.appendChild(this._canvas); return this._canvas; }}Copy the code

Fireworks rose

Building up particle systems

import { Mesh, Vector3, Color4, ParticleSystem, Texture, VertexBuffer } from "@babylonjs/core" export class artifice { constructor(scene) { this.scene = scene this.isTop = false; this.timer = 0; this.isFired = false; this.timer1 = 0; this.textureFirework = "textures/flare.png"; this.posX = 0 this.posY = 0 this.posZ = 0 } shoot(posX = 0, posY = -20, posZ = 0) { let startSphere = new Mesh.CreateSphere("Shoot", 4, 1, this.scene); startSphere.position = new Vector3(posX, posY, posZ); startSphere.isVisible = false; let particleSystem = new ParticleSystem("particles", 350, this.scene); particleSystem.particleTexture = new Texture(this.textureFirework, this.scene); particleSystem.emitter = startSphere; particleSystem.minEmitBox = new Vector3(0, 0, 0); particleSystem.maxEmitBox = new Vector3(0, 0, 0); Color1 = new Color4(1, 0.8, 1.0, 1.0); Color2 = new Color4(1, 0.5, 1.0, 1.0); ColorDead = new Color4(0, 0, 0.2, 0.5); particleSystem.minSize = 1; particleSystem.maxSize = 1; ParticleSystem. MinLifeTime = 0.5; particleSystem.maxLifeTime = .5; particleSystem.emitRate = 350; particleSystem.blendMode = ParticleSystem.BLENDMODE_ONEONE; particleSystem.direction1 = new Vector3(0, -2, 0); particleSystem.direction2 = new Vector3(0, -2, 0); particleSystem.minEmitPower = 1; particleSystem.maxEmitPower = 1; ParticleSystem. UpdateSpeed = 0.005; let bigEnough = false; let updateFunction = function(particles) { for (let index = 0; index < particles.length; index++) { let particle = particles[index]; particle.age += this._scaledUpdateSpeed; if (particle.age >= particle.lifeTime) { this.recycleParticle(particle); index--; continue; } else { if(! bigEnough){ particle.size -= .01; } particle.direction.scaleToRef(particleSystem._scaledUpdateSpeed, particleSystem._scaledDirection); particle.position.addInPlace(particleSystem._scaledDirection); particleSystem.gravity.scaleToRef(particleSystem._scaledUpdateSpeed, particleSystem._scaledGravity); particle.direction.addInPlace(particleSystem._scaledGravity); }}}; particleSystem.updateFunction = updateFunction; particleSystem.start(); this.scene.registerBeforeRender(() => { if(! this.isFired){ if(! this.isTop){ startSphere.position.y += .5; if(startSphere.position.y > 30){ this.isTop = ! this.isTop; if (this.isTop ) { this.posX = startSphere.position.x this.posY = startSphere.position.y this.posZ = startSphere.position.z } particleSystem.stop(); startSphere.position.x -= .5; } } else { this.timer +=5; if(this.timer == 125){ for(let i = 0; i < 2; i++){ this.firework(); } this.isFired = ! this.isFired; }}}}); } getRandomBetween(Min, Max){ let Range = Max - Min; let Rand = Math.random(); let num = Min + Math.round(Rand * Range); return num; }... }Copy the code

fireworks

class artifice{ ... firework() { let fountain = new Mesh.CreateSphere("explosion", 4, 1, this.scene); fountain.isVisible = false; fountain.position.x = this.posX fountain.position.y = this.posY fountain.position.z = this.posZ let perticleFromVerticesEmitter = fountain; perticleFromVerticesEmitter.useVertexColors = true; let verticesPositions = perticleFromVerticesEmitter.getVerticesData(VertexBuffer.PositionKind); let verticesNormals = perticleFromVerticesEmitter.getVerticesData(VertexBuffer.NormalKind); let verticesColor = []; for (let i = 0; i < verticesPositions.length; i += 3){ let vertexPosition = new Vector3( verticesPositions[i], verticesPositions[i + 1], verticesPositions[i + 2] ); let vertexNormal = new Vector3( verticesNormals[i], verticesNormals[i + 1], verticesNormals[i + 2] ); let r = Math.random(); let g = Math.random(); let b = Math.random(); Let the alpha = 1.0; let color = new Color4(r, g, b, alpha); verticesColor.push(r); verticesColor.push(g); verticesColor.push(b); verticesColor.push(alpha); Let gizmo = Mesh.CreateBox('gizmo', 0.001, this.scene); gizmo.position = vertexPosition; gizmo.parent = perticleFromVerticesEmitter; this.createParticleSystem(gizmo, vertexNormal.normalize().scale(1), color); } perticleFromVerticesEmitter.setVerticesData(VertexBuffer.ColorKind, verticesColor); } createParticleSystem(emitter, direction, color) { let bigEnough = false; let particleSystem1 = new ParticleSystem("particles", 500, this.scene); let updateFunction = function(particles) { for (let index = 0; index < particles.length; index++) { let particle = particles[index]; particle.age += this._scaledUpdateSpeed; if (particle.age >= particle.lifeTime) { this.recycleParticle(particle); index--; continue; } else { if(! bigEnough){ particle.size = particle.size +.005; if(particle.size >= .162){ bigEnough = ! bigEnough; } } particle.direction.scaleToRef(particleSystem1._scaledUpdateSpeed, particleSystem1._scaledDirection); particle.position.addInPlace(particleSystem1._scaledDirection); particleSystem1.gravity.scaleToRef(particleSystem1._scaledUpdateSpeed, particleSystem1._scaledGravity); particle.direction.addInPlace(particleSystem1._scaledGravity); }}}; particleSystem1.updateFunction = updateFunction; particleSystem1.domeRadius = 10; particleSystem1.particleTexture = new Texture(this.textureFirework, this.scene); particleSystem1.emitter = emitter; // the starting object, the emitter particleSystem1.minEmitBox = new Vector3(1, 0, 0); // Starting all from particleSystem1.maxEmitBox = new Vector3(1, 0, 0); // To... particleSystem1.color1 = color; particleSystem1.color2 = color; ParticleSystem1. ColorDead = new Color4 (0, 0, 0, 0.0); particleSystem1.minSize = .1; particleSystem1.maxSize = .1; particleSystem1.minLifeTime = 1; particleSystem1.maxLifeTime = 2; particleSystem1.emitRate = 500; particleSystem1.blendMode = ParticleSystem.BLENDMODE_ONEONE; Gravity = new Vector3(0, -9.81, 0); particleSystem1.direction1 = direction; particleSystem1.direction2 = direction; particleSystem1.minEmitPower = 10; particleSystem1.maxEmitPower = 13; ParticleSystem1. UpdateSpeed = 0.01; particleSystem1.start(); This. Scene. RegisterBeforeRender (() = > {{if (this. Timer1 < 300). This timer1 + = 0.15; } else { particleSystem1.stop(); }}); }... }Copy the code

Add a button

class App { ... _createPlayButton() { const advancedTexture = AdvancedDynamicTexture.CreateFullscreenUI("UI"); Const button = button. CreateSimpleButton (" playButton ", "launch"); button.width = "150px" button.height = "40px"; button.color = "white"; button.posi button.cornerRadius = 20; button.background = "red"; button.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM button.horizontalAlignment = Control. HORIZONTAL_ALIGNMENT_RIGHT button. OnPointerUpObservable. Add (() = > {const x = getRandomBetween (20, 20) - this.play(x) }); advancedTexture.addControl(button); } play(x) { const firework = new artifice(this._scene) firework.shoot(x) } .... }Copy the code

Click the launch button in the lower right corner to launch fireworks

The last

Click on the GIT code of this issue, this time it is mainly about the case of Spring Festival fireworks, and it does not systematically explain Babylon. If you are interested, you can go to the Website of Babylon to learn. In this year’s Alipay Five Blessings activity, the AR blessing viewing method is added, which is realized by Oasis developed by Ali. The editor is not open to the public for the time being. At present, it is more friendly to use Babylon to develop, and Babylon can easily realize this kind of method.