The first part of this tutorial introduces the basic concepts of Billboard Particle technology and implements a simple particle scenario based on Three.Sprite. This time I will use a simple example to give you a better understanding of the physical properties of particles such as velocity and acceleration, which will be the basis for implementing part 3 particle systems.

A better way to implement the bulletin board particle system in three.js is to use three. Points objects, like Sprite, are always facing the camera. Unlike Sprite’s flat construction, Points objects are vertices in 3D space. Each vertex is a particle. THREE.Points has a significant performance advantage over the cost of rendering a surface, and also supports texturing. The final result is almost the same as Sprite, but it’s definitely more efficient.

THREE.Points by default uses the BufferGeometry object to create vertex data. We need to set the particle vertex size, position, speed, acceleration in the shader, and rotate the map according to the Angle value.

Start by creating vertex and fragment shaders, and create parameters such as size, speed, and gravitational acceleration.

const vertexShader = `
  uniform floatu_time; // time total uniform vec3 u_gravity; // Attribute vec3 velocity; // Particle velocity voidmain() { vec3 vel = velocity * u_time; // Calculate speed by time vel = vel + u_gravity * u_time * u_time; Vec3 pos = position + vel; Gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0); Gl_PointSize = 6.0; } ` const fragmentShader = ` voidmain() {color = vec3(1.0); Gl_FragColor = vec4 (color, 1.0); } `Copy the code

Create 100 particles and set random position and speed values, which are then passed to the shader.

_initParticles() {
    const uniforms = {
      u_time: { value: 0 },
      u_gravity: { value: new THREE.Vector3(0, -5, 0) }
    }
    const material = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader,
      fragmentShader
    })
    const COUNT = 100
    const positions = new Float32Array(COUNT*3)
    const velocity = new Float32Array(COUNT*3)
    const geometry = new THREE.BufferGeometry()
    const size = 0
    const speed = 20
    for(leti = 0; i < positions.length; I ++) {positions[I] = (math.random () -0.5) * size velocity[I] = (math.random () -0.5) * speed} geometry. SetAttribute ('position', new THREE.BufferAttribute(positions, 3))
    geometry.setAttribute('velocity', new THREE.BufferAttribute(velocity, 3))
    const mesh = new THREE.Points(geometry, material)
    this.scene.add(mesh)
    this.uniforms = uniforms
}
Copy the code

In the render function, we update the time parameter value to the vertex shader, and as the time value accumulates, our particles get excited.

_render() {this.imaginative.u_time.value += this.clock.getDelta() // Update time parametersifU_time. value = 0} this. Renderer. Render (this. this.camera) requestAnimationFrame(this._render.bind(this)) }Copy the code



Well, it looks a little flat, let’s add a map and give the particles different colors, rotation angles and sizes to see how they look, and to do this we need to add some new variables in the vertex and fragment shaders.

// Add variable attribute to vertex shaderfloat angle;
varying floatvAngle; varying vec3 vColor; The uniform sampler2D texture is set to rotate the texture according to the variable passed by the vertex shader; varyingfloat vAngle;
varying vec3 vColor;
void main() {// Rotate mapfloat c = cos(vAngle);
  floats = sin(vAngle); Vec2 uv = VEC2 (c * (gl_pointcoord.x-0.5) + S * (gl_pointcoord.y-0.5) + 0.5, C * (gl_pointcoord.y-0.5) -s * (gl_pointcoord.x-0.5) + 0.5); // Particle color gl_FragColor = vec4(vColor, 1.0); vec4 color = texture2D(texture, uv); gl_FragColor = gl_FragColor * color; }Copy the code

Pass variable values to shaders in the main program.

for(leti = 0; i < positions.length; Positions [I] = (math.random () -0.5) * size velocity[I] = (math.random () -0.5) * speed color[I] = math.random () }for(let i = 0; i < COUNT; i++) {
  angle[i] = Math.PI * 2 * Math.random()
}
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
geometry.setAttribute('velocity', new THREE.BufferAttribute(velocity, 3))
geometry.setAttribute('color', new THREE.BufferAttribute(color, 3))
geometry.setAttribute('angle', new THREE.BufferAttribute(angle, 1))
Copy the code



In part 2, we learned how to set the parameters of particle properties in vertex and fragment shaders. This knowledge is the foundation of implementing a particle system. If you think it is not cool enough, don’t be too excited. In part three, we will implement a basic particle system and use it to achieve cool effects like flame, smoke, snow, etc. Have fun and see you next time!

Final effect source file