天天看點

Three.JS提升學習3:粒子

  • ​​一了解粒子​​
  • ​​使用THREESprite建立簡單粒子​​
  • ​​使用THREEPointCloud處理大量粒子​​
  • ​​給粒子使用樣式​​
  • ​​使用HTML5畫布樣式化粒子​​
  • ​​在THREECanvasRenderer中使用HTML5畫布​​
  • ​​在WebGLRenderer中使用HTML5畫布​​
  • ​​使用紋理樣式化粒子​​
  • ​​使用精靈貼圖​​
  • ​​從進階幾何體建立THREEPointCloud​​

本文學習資源來自《Three.js開發指南》

一、了解粒子

粒子用來模拟很多細小的物體,如雨滴、雪花、煙等。

1. 使用THREE.Sprite建立簡單粒子

關鍵代碼:

function createSprites() {
            var material = new THREE.SpriteMaterial();


            for (var x = -5; x < 5; x++) {
                for (var y = -5; y < 5; y++) {
                    var sprite = new THREE.Sprite(material);
                    sprite.position.set(x * 10, y * 10, 0);
                    scene.add(sprite);
                }
            }
        }      

建立10*10的粒子,一個粒子是一個二維平面,總是面向錄影機。

這些粒子沒有指定屬性,預設渲染成白色方塊。

Three.JS提升學習3:粒子

這裡使用的THREE.Sprite用來建立粒子。THREE.Sprite是THREE.Object3D對象的擴充,也就是說THREE.Mesh的大部分屬性和函數都可用于THREE.Sprite。

當粒子數量非常大時,使用大量THREE.Sprite會遇到性能問題。

2. 使用THREE.PointCloud處理大量粒子

function createParticles() {


            var geom = new THREE.Geometry();
            var material = new THREE.PointCloudMaterial({size: 4, vertexColors: true, color: 0xffffff});

            for (var x = -5; x < 5; x++) {
                for (var y = -5; y < 5; y++) {
                    var particle = new THREE.Vector3(x * 10, y * 10, 0);
                    geom.vertices.push(particle);
                    geom.colors.push(new THREE.Color(Math.random() * 0x00ffff));
                }
            }

            var cloud = new THREE.PointCloud(geom, material);
            scene.add(cloud);
        }      

這裡每個粒子需要建立一個頂點THREE.Vector3對象,并添加到THREE.Geometry中,使用THREE.Geometry和THREE.PointCloudMaterial一起建立THREE.PointCloud,再把雲添加到場景中。

Three.JS提升學習3:粒子

3. 給粒子使用樣式

function createParticles(size, transparent, opacity, vertexColors, sizeAttenuation, color) {


            var geom = new THREE.Geometry();
            var material = new THREE.PointCloudMaterial({
                size: size,
                transparent: transparent,
                opacity: opacity,
                vertexColors: vertexColors,

                sizeAttenuation: sizeAttenuation,
                color: color
            });


            var range = 500;
            for (var i = 0; i < 15000; i++) {
                var particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2);
                geom.vertices.push(particle);
                var color = new THREE.Color(0x00ff00);
                color.setHSL(color.getHSL().h, color.getHSL().s, Math.random() * color.getHSL().l);
                geom.colors.push(color);

            }

            cloud = new THREE.PointCloud(geom, material);
            cloud.name = "particles";
            scene.add(cloud);
        }
                var step = 0;

        function render() {

            stats.update();

            if (controls.rotateSystem) {
                step += 0.01;

                cloud.rotation.x = step;
                cloud.rotation.z = step;
            }


            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }      

書籍官方式示例效果:

Three.JS提升學習3:粒子

3. 使用HTML5畫布樣式化粒子

在THREE.CanvasRenderer中使用HTML5畫布

在WebGLRenderer中使用HTML5畫布

4. 使用紋理樣式化粒子

function createPointCloud(size, transparent, opacity, sizeAttenuation, color) {

            var texture = THREE.ImageUtils.loadTexture("../assets/textures/particles/raindrop-3.png");
            var geom = new THREE.Geometry();

            var material = new THREE.ParticleBasicMaterial({
                size: size,
                transparent: transparent,
                opacity: opacity,
                map: texture,
                blending: THREE.AdditiveBlending,
                sizeAttenuation: sizeAttenuation,
                color: color
            });


            var range = 40;
            for (var i = 0; i < 1500; i++) {
                var particle = new THREE.Vector3(
                        Math.random() * range - range / 2,
                        Math.random() * range * 1.5,
                        Math.random() * range - range / 2);
                particle.velocityY = 0.1 + Math.random() / 5;
                particle.velocityX = (Math.random() - 0.5) / 3;
                geom.vertices.push(particle);
            }

            cloud = new THREE.ParticleSystem(geom, material);
            cloud.sortParticles = true;

            scene.add(cloud);
        }      

5. 使用精靈貼圖

6. 從進階幾何體建立THREE.PointCloud

render();

        // from THREE.js examples
        function generateSprite() {

            var canvas = document.createElement('canvas');
            canvas.width = 16;
            canvas.height = 16;

            var context = canvas.getContext('2d');
            var gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2);
            gradient.addColorStop(0, 'rgba(255,255,255,1)');
            gradient.addColorStop(0.2, 'rgba(0,255,255,1)');
            gradient.addColorStop(0.4, 'rgba(0,0,64,1)');
            gradient.addColorStop(1, 'rgba(0,0,0,1)');

            context.fillStyle = gradient;
            context.fillRect(0, 0, canvas.width, canvas.height);

            var texture = new THREE.Texture(canvas);
            texture.needsUpdate = true;
            return texture;

        }

        function createPointCloud(geom) {
            var material = new THREE.PointCloudMaterial({
                color: 0xffffff,
                size: 3,
                transparent: true,
                blending: THREE.AdditiveBlending,
                map: generateSprite() //把粒子設定成發光點
            });

            var cloud = new THREE.PointCloud(geom, material);
            cloud.sortParticles = true;
            return cloud;
        }

        function createMesh(geom) {

            // assign two materials
            var meshMaterial = new THREE.MeshNormalMaterial({});
            meshMaterial.side = THREE.DoubleSide;

            // create a multimaterial
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial]);

            return mesh;
        }

        function render() {
            stats.update();

            if (controls.rotate) {
                knot.rotation.y = step += 0.01;
            }

            // render using requestAnimationFrame
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }