preface

Using the Three. Points of three. js, you can implement some cool particle dynamic effects. Let’s see how these effects are implemented.

Snow effect

At Christmas and other festivals, we sometimes need to achieve some effect of falling snow, and using three. js can be easily achieved. It looks something like this:

Create scene, camera, and renderer

These are all fixed template code using three.js, which uses a perspective camera to make snowflakes look layered.

	let width = window.innerWidth; // Width of canvas
    let height = window.innerHeight; // Height of canvas

    / / the renderer
    let renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height);
    // Set the background color
    renderer.setClearColor('RGB (22,33,82)'.1.0);
    let element = document.getElementById('snow');
    element.appendChild(renderer.domElement);

    / / the scene
    let scene = new THREE.Scene();

    // Perspective projection camera
    let camera = new THREE.PerspectiveCamera(75, width / height, 1.500);
    camera.position.set(0.0.50);
    camera.lookAt(scene.position);
    scene.add(camera);
Copy the code

Loading snowflake images

The snowflake here is a picture with a transparent white circle background. Note here that the TextureLoader is loaded asynchronously, and once loaded, the PointsMaterial is created from the texture. Here you can use size to adjust the size of the snowflake.

let loader = new THREE.TextureLoader() loader.load('.. /assets/snow.png', (texture) => {let material = new three. PointsMaterial({map: texture, // texture: transparent: True, // transparent size: 5,}); // create THREE.Points... });Copy the code

Randomly generated snowflakes

Next, we need to randomly generate the position and direction and speed of the snowflake.

  • Here we specify 800 snowflakes.
  • Randomly generated positions of x, y, and z are all between [-200, 200]. By default, the speed direction is down on the Y-axis, and the size is 0.4. You can change this value to adjust the speed of the snowflake falling, and then rotate it randomly according to the X-axis and Y-axis to make the direction of its movement as random as possible, while ensuring that the overall movement of the snowflake is downward.
// let range = 400; // Let geom = new THREE.Geometry(); for (let i = 0; i < 800; Vector3(math.random () * range-range / 2, math.random () * range-range / 2, math.random () * range-range / 2, math.random () * range-range / 2, Math.random() * range - range / 2 ); V. volocity = createVelocity(); // Add vertices geom.vertex.push (v); } points = new THREE.Points(geom, material); scene.add(points); Renderer. render(scene, camera); // create a random number within the specified range. I) {return math.random () * (i-t) + t} function createVelocity() {default let velocity = new THREE. Vector3 (0, 0.4, 0). velocity.rotateX(randomRange(-45, 45)); velocity.rotateY(randomRange(0, 360)); return velocity; }Copy the code

In three.vector3, the rotateX method is added as an Angle. RotateY and rotateZ methods have been added in the same way, and can be implemented in lib/vector-util.js in the complete sample code.

var TO_RADIANS = Math.PI / 180;
THREE.Vector3.prototype.rotateX = function (t) {
    var cosRY = Math.cos(t * TO_RADIANS);
    var sinRY = Math.sin(t * TO_RADIANS);
    var i = this.z,
        o = this.y;
    this.y = o * cosRY + i * sinRY;
    this.z = o * -sinRY + i * cosRY
}
Copy the code

Let the snow move

Finally, it’s time to get the snow moving:

  • Particle motion is achieved by constantly modifying the position of the particle itself.
  • Here we usesetIntervalThe animation is implemented 40 times per second.
  • Each callanimate, will be stored according to itselfvelocityTo modify the position. Because we have a finite number of particles, if the particle is outside the specified range, it will change its direction of motion and its Y-axis position, so that the particle will always move within the specified range, and the snow will not stop falling.
  • It’s important to note that,verticesNeedUpdateProperty, particles will not move without it.
setInterval(animate, 1000 / 40); // animate() {let vertices = points.geometry. Vertices; Vertex.foreach (function (v, idx) {// Vertex.foreach (function (v, idx); v.x = v.x + (v.velocity.x); v.z = v.z + (v.velocity.z); // if (v.y <= -range / 2) v.y = range / 2; if (v.x <= -range / 2 || v.x >= range / 2) v.x = v.x * -1; if (v.z <= -range / 2 || v.z >= range / 2) v.velocity.z = v.velocity.z * -1; }); Important: / / render time need to update location (if there is no set to true, cannot show animation) points. The geometry. VerticesNeedUpdate = true; renderer.render(scene, camera); };Copy the code

The above animation can also be implemented using requestAnimationFrame, but the time difference is calculated and the length of the particle’s motion in each direction is calculated from this time difference.

The sample code

Online sample

Complete project code

Particle model switching

In the snowflake effect above, particles move in random directions in random locations. However, if I want to change the particle cloud of shape A to that of shape B, even the color needs to be changed, and the change process needs to be animated, what should I do?

Let’s take a look at the effect:

Create scene, camera, and renderer

Basically the same code as the snowflake effect, but using an orthogonal camera

. let camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 1000); camera.position.set(0, 0, 10); scene.add(camera); .Copy the code

Create two particle models

Take a look at how the positions of particles are defined in these two models:

  • pointsCountAll of 10000.
  • D3. randomNormal returns a function that generates a random number that conforms to the normal distribution. This is introduced to facilitate the generation of test data.

This is just demo data, so you can generate your own particle model.

Const RNG = d3.randomNormal(0, 0.01); // Const RNG = d3.randomNormal(0, 0.01); for (let i = 0; i < pointsCount; I++) {let v = new THREE. Vector3 ((RNG () + Math. Cos (I)) * (width / 2.5), (RNG () + math.h sin (I)) * (height / 2.5), 0). let c = new THREE.Color(0, 1, 0); / / green}Copy the code
Const RNG = d3.randomNormal(0, 0.05); // Const RNG = d3.randomNormal(0, 0.05); for (let i = 0; i < pointsCount; i++) { let v = new THREE.Vector3( rng() * width, rng() * height, 0 ); Let c = new THREE.Color(0, 0.5, 1); / / blue}Copy the code

The model material

This time the default material is solid color and the particle color is custom (green or blue), so you need to set vertexColors to THREE.VertexColors.

Let material = new THREE.PointsMaterial({size: 1.0, vertexColors: THREE.VertexColors: THREE, vertexColors)Copy the code

Switch the animation

The principle of animation is also to change the position of the point. Here I use tween.js to deal with the change of the position and color of the point.

The position of the point defined here moves to targetPosition in 800 milliseconds. Tween can also specify the easing function, set the delay, and so on, depending on the need to do different effects.

Function greelayout (geometry) {const RNG = d3.randomNormal(0, 0.01); Geometry. Are. ForEach ((d (I) = > {new TWEEN. TWEEN (d) to ({x: (RNG () + Math. Cos (I)) * (width / 2.5), y: (RNG) + Math. Sin (I)) * (height / 2.5),}, 800). / / delay (500 * Math. The random ()). The start ()}); geometry.colors.forEach((d, i) => { new TWEEN.Tween(d).to({ g: 1, b: 0, }, 800) .start() }); } function blueNormalLayout(Geometry) {function bluenormout (geometry) { }Copy the code

move

Define an array record model and switch models based on the time of movement.

  • TWEEN.updateExecute the tween.js animation.
  • Because you want to change the position and color of the particle, everything has to be setverticesNeedUpdatecolorsNeedUpdatetrue.
let layouts = [greenCircleLayout, blueNormalLayout];
let startTime = new Date().getTime();
let currentLayout = 0;

requestAnimationFrame(animate);

function animate() {
    let now = new Date().getTime();
    if (now - startTime > 1500) {
        currentLayout = (currentLayout + 1) % layouts.length;
        layouts[currentLayout](pointCloud.geometry);
        startTime = now;
    }
    TWEEN.update();
    pointCloud.geometry.verticesNeedUpdate = true;
    pointCloud.geometry.colorsNeedUpdate = true;
    renderer.render(scene, camera);
    requestAnimationFrame(animate)
}
Copy the code

The sample source code

Online sample

Project complete source code

reference

  • Derivation and mnemonic of 3 – d rotation matrix
  • ThreeJS particle system to achieve snowflake falling animation
  • BEAUTIFULLY ANIMATE POINTS WITH WEBGL AND REGL
  • 3D particle effect is shared on the web