Author: Liang Shen, front-end development engineer of Getui Web

The background,

Particle special effect is a production module developed by various 3d software to simulate the effects of water, fire, fog, gas and so on in reality. The principle is to combine numerous single particles to make them present a fixed shape, and control their overall or single movement by controller and script, so as to simulate the real effect. Three. js is a third-party library of WebGL written in JavaScript. Three. js provides rich APIS to help us realize 3D dynamic effects. This paper mainly introduces how to use Three. js to realize particle transition effects and basic mouse interactive operations. (Note: The APIS for Three.js used in this article are based on version R98.)

Two, implementation steps

1. Create a render scene

Scene is actually equivalent to a three-dimensional space, which is used to carry and display everything we define, including camera, objects, lights, etc. Some auxiliary tools, such as grids and coordinate axes, can be added to facilitate observation during actual development.

scene = new THREE.Scene();
 scene.fog = new THREE.Fog(0x05050c.10.60);
 scene.add( new THREE.GridHelper( 2000.1));//Add the gridCopy the code

2. Add a camera

PerspectiveCamera, OrthographicCamera, CubeCamera, and StereoCamera are implemented within THREE: PerspectiveCamera, OrthographicCamera, CubeCamera, and StereoCamera. PerspectiveCamera: PerspectiveCamera

The visual effect is near big far small.

PerspectiveCamera (FOv, aspect, near, far).

Fov: Camera viewing Angle.

Aspect: The aspect ratio of the camera’s visual range.

Near: Distance from the deep shear plane.

Far: Distance relative to the deep shear plane.

camera = new THREE.PerspectiveCamera(45, window.innerWidth /window.innerHeight, 5.100);
   camera.position.set(10, -10, -40);
   scene.add(camera);
Copy the code

3. Add lighting for scene rendering

Light source implemented in three.js: AmbientLight (ambient light), DirectionalLight (parallel light), HemisphereLight (half light), PointLight (point source), RectAreaLight (lighting), the SpotLight (spot), etc. When configuring the light source parameters, pay attention to the color overlay effect. For example, the color of the ambient light directly affects the current color of the object. The configuration parameters of various light sources are somewhat different. Here are the two light sources used in this example.

let ambientLight = new THREE.AmbientLight(0x000000.0.4);
   scene.add(ambientLight);
   let pointLight = new THREE.PointLight(0xe42107);
   pointLight.castShadow = true;
   pointLight.position.set(-10, -5, -10);
   pointLight.distance = 20;
   scene.add(pointLight);

Copy the code

4. Create, export, and load the model file loader

Models can be created using the three.js Editor or the basic model generation class of three.js. Complex or special models need to be created using modeling tools (C4D, 3Dmax, etc.).

Create using the three.js Editor to add base geometry and adjust its various parameters (position, color, material, etc.).

let geometryCube = new THREE.BoxBufferGeometry( 1.1.1 );
   let materialCube = new THREE.MeshBasicMaterial( {color: 0x00ff00}); let cubeMesh = new THREE.Mesh( geometryCube, materialCube ); scene.add( cubeMesh );Copy the code

Export the required model file (the obJ format is used here).

Load and parse the model file data.

let onProgress = function (xhr) {
       if (xhr.lengthComputable) {
           //Model loading progress can be calculated}}; let onError = function () {}; particleSystem = new THREE.Group(); var texture = new THREE.TextureLoader().load('./point.png');
   new THREE.OBJLoader().load('./model.obj', function (object) {
       //Object model file data}, onProgress, onError);Copy the code

5. Convert the imported model file into particle system Points

Gets the coordinate value of the model.

Copy the particle coordinate value to the new position1 property, which will be the final coordinate position of the particle transition effect.

Add a random THREE-DIMENSIONAL coordinate value position to the particle system in order to disarrange the position of each particle and set the starting position.

let color = new THREE.Color('#ffffff');
   let material = new THREE.PointsMaterial({
       size: 0.2.map: texture,
       depthTest: false.transparent: true
   });
    particleSystem= new THREE.Group();
   let allCount = 0
   for (let i = 0; i < object.children.length; i++) {
       let name = object.children[i].name
       let _attributes = object.children[i].geometry.attributes
           let count = _attributes.position.count
           _attributes.positionEnd = _attributes.position.clone()
           _attributes.position1 = _attributes.position.clone()
           for (let i = 0; i < count * 3; i++) {
                _attributes.position1.array[i]= Math.random() * 100 - 50
           }
           let particles = new THREE.Points(object.children[i].geometry, material)
           particleSystem.add(particles)
           allCount += count
    }
   particleSystem.applyMatrix(new THREE.Matrix4().makeTranslation(-5, -5, -10));
Copy the code

6. Transform particle coordinates from position to position1 through Tween animation library

TWEEN’s slow algorithm is used to calculate the coordinate position of each particle for each change, and the time from the initial position to the end position is set to 2s (customized). After each calculation, the position attribute of the Attributes needs to be set to true to remind the scene of the need to update. In the next rendering, Render will render using the latest calculated value.

let pos = { val: 1 }; tween = new TWEEN.Tween(pos).to({ val: 0 }, 2500).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(callback); Tween. OnComplete (function () {console.log(' transition complete')}) tween. Start (); function callback() { let val = this.val; let particles = particleSystem.children; for (let i = 0; i < particles.length; i++) { let _attributes = particles[i].geometry.attributes let name = particles[i].name if (name.indexOf('_') === -1) { let positionEnd =_attributes.positionEnd.array let position1 =_attributes.position1.array let count =_attributes.position.count for (let j = 0; j < count *3; j++) { _attributes.position.array[j] = position1[j] *val + positionEnd[j] * (1 - val) } } _attributes. Position. NeedsUpdate = true / / set update}}Copy the code

7. Add render

Create the container.

Define the Render renderer and set the parameters.

Add the renderer to the container.

Custom render function, in the render function we use tween. update to update the model state.

The custom animate function is called and the requestAnimationFrame method is used to render frame by frame.

let container = document.createElement('div');
    document.body.appendChild(container);
   renderer = new THREE.WebGLRenderer({
       antialias: true.alpha: true
   });
   renderer.setPixelRatio(window.devicePixelRatio);
   renderer.setClearColor(scene.fog.color);
    renderer.setClearAlpha(0.8);
   renderer.setSize(window.innerWidth, window.innerHeight);
   container.appendChild(renderer.domElement); //Add webgl renderer function render () {particleSystem. Rotation. Y + =0.0001;
       TWEEN.update();
       particleSystem.rotation.y += (mouseX + camera.rotation.x) * .00001;
       camera.lookAt(new THREE.Vector3(-10, -5, -10))
       controls.update();
       renderer.render(scene, camera);
    }
   function animate() { //RequestAnimationFrame (animate); render(); }Copy the code

8. Add mouse operation events to achieve Angle control

We can also add mouse operation events to achieve Angle control, where winX and winY are respectively half of the width and height of Window. Of course, specific coordinate positions can be calculated according to their own needs, and the specific effect is shown in the figure below.


document.addEventListener('mousemove', onDocumentMouseMove, false);
   function onDocumentMouseMove(event) {
       mouseX = (event.clientX - winX) / 2;
       mouseY = (event.clientY - winY) / 2;
    }
Copy the code

Third, optimization plan

1. Reduce the number of particles

As the number of particles increases, it will be very time-consuming to calculate the position and size of each particle, which may cause animation lag or page false death. Therefore, we can minimize the number of particles when building the model, which can effectively improve the performance.

In the above example, we change the export scale of the model, you can get different number of particle system, when hundreds of thousands or even millions of particles quantity, in animation loads can feel obviously card phenomenon, this is mainly due to the FPS is lower, the specific contrast effect as shown in the figure below, on the left side of the particle number is 300000, on the right side of the particle number is 60000, It is obvious that the left side of the frame is obvious, and the right side of the frame remains relatively smooth.

2. Use GPU rendering mode

Write slice shader code and use WebGL to provide hardware 3D acceleration for Canvas so that the browser can render the page more smoothly. At present, most devices already support this method, but it should be noted that on low-end devices, due to hardware reasons, the rendering speed may not be as fast as the CPU-based rendering method.

Four,

To sum up, the key to realize particle dynamic effect is to calculate and maintain the position state of each particle, and three.js provides a convenient method for rendering the whole particle scene. When the number of particles is extremely large, to achieve smooth animation effect, we need to pay attention to optimize the code, reduce the calculation, etc., and can also improve the hardware configuration to achieve the effect. The case in this paper shows you how to achieve 3D particle dynamic effects. You can make more cool dynamic effects according to your actual needs.