粒子和粒子系統


1.粒子材質和粒子幾何體

    創建粒子系統的點,可以存放在Geometry幾何體中。使用Geometry的vertices保存點、colors保存點的顏色。但我們必須使用粒子的專用材質對象PointCloudMaterial(原名叫做ParticleBasicMaterial)設置材質。包含的屬性如下列表:

    名稱/描述

    color/PointCloud對象中所有粒子的顏色。如果vertexColors設置為true,而且也指定了幾何體的colors屬性,那么該屬性被忽略

    map/可以在粒子上應用某種材質。例如可以讓粒子看起來像雪花

    size/粒子大小

    sizeAttenuation/如果設置為false,所有粒子都有擁有相同的尺寸。如果為true,粒子的大小取決於離相機的遠近

    vertexColors/如果設置為true,並且幾何體的colors數組也有值,那就使用顏色數組中的值

    opacity/跟transparent屬性一起使用,用來設置粒子的透明度

    transparent/如果為true,那么opacity設置有效

    blending/渲染粒子時的融合方式

    fog/是否采用場景的霧化效果

    把點vertex和顏色color都附加到Geometry對象中后,使用PointCloud(原ParticleSystem對象)創建幾何粒子系統。如下面的例子:

function createParticle(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);

            }

2.使用Canvas輸出結果作為粒子材質

    和1中的創建PointCloudMaterial相似,只是這里增加了一個屬性map,減少了屬性vertexColors(因為直接使用紋理而不是顏色)。新增了一個map屬性,具體值是調用getTexture函數返回一個Texture對象。創建PointCloudMaterial代碼如下:

var material = new THREE.PointCloudMaterial({
                    size: size,
                    transparent: transparent,
                    opacity: opacity,
                    map: getTexture(),
                    sizeAttenuation: sizeAttenuation,
                    color: color,
                });

    Texture對象可以直接接受一個canvas對象,把canvas的輸出作為紋理。創建Texture代碼如下:

var getTexture = function () {
            var canvas = document.createElement('canvas');
            canvas.width = 32;
            canvas.height = 32;

            var ctx = canvas.getContext('2d');
            // the body
            ctx.translate(-81, -84);

            ctx.fillStyle = "orange";
           ...
            ctx.fill();


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

    需要設置紋理的needsUpdate為true。另外,在創建PointCloud對象時也要額外設置它的sortParticles屬性為true。這樣可以保證粒子在渲染之前沿着屏幕上的z軸排好序。

3.使用外部圖片作為粒子的材質

    和2相似,只不過這里我們在創建紋理時直接如下方式讀取外部圖片作為紋理:

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

    如果我們想模擬下雨的效果,可在創建vertices時,給每個位置指定x和y方向的移動速度。

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);
                    var color = new THREE.Color(0x00ff00);
                    color.setHSL(color.getHSL().h, color.getHSL().s, Math.random() * color.getHSL().l);
                    geom.colors.push(color);
                }

    在渲染的時候,可以沒渲染一次,vertices根據速度移動一次。渲染代碼如下:

if(controls.rotateSystem){
                    var vertices = cloud.geometry.vertices;
                    vertices.forEach(function(vector){
                        vector.y -= vector.velocityY;
                        vector.x += vector.velocityX;

                        if(vector.y <= 0) vector.y = 60;
                        if(vector.x <= -20 || vector.x >= 20) vector.x = -vector.x;
                    });
                }

    另外,在創建PointCloudBasicMaterial時,可以指定depthWrite屬性為false。該屬性決定這個對象是否影響WebGL的深度緩存。設置為false,可以保證各個粒子系統之間不受影響。如果不設置如此,當一個粒子處在另外一個粒子的前面,而后者來自別的例子系統,有時候會看到紋理的黑色背景。

4.使用精靈THREE.Sprite

    THREE.Sprite類可用於如下兩種目的:

    創建一個可以基於屏幕坐標移動、定位和縮放的對象。你可以用它來創建一個平視顯示器(HUD),就像在三維場景上蒙了一層;

    創建一個類似粒子的、可以在三維空間移動的對象,類似使用CanvasRenderer的THREE.Particle。三維場景中的精靈有事有稱作廣告牌。總是相面鏡頭,就像高速公路上的廣告牌總是面向司機。

    使用精靈,需要用到材質對象SpriteMaterial和網格對象Sprite。如果我們要實現一個外部圖片作為紋理,像廣告一樣在屏幕底部左右移動。應該怎樣實現?要使用精靈對象。攝像頭一般使用正射投影。例如:

var cameraOrtho = new THREE.OrthographicCamera(0, window.innerWidth, window.innerHeight, 0, -10, 10);

    left為0, right為window的width,top為window的height,bottom為0,near為-10, far為10。

    下面的一個方法實現了如何創建Sprite網格對象:

function createSprite(size, transparent, opacity, color, spriteNumber){
                var spriteMaterial = new THREE.SpriteMaterial({
                    transparent: transparent,
                    opacity: opacity,
                    color: color,
                    map: getTexture()
                });

                spriteMaterial.map.offset = new THREE.Vector2(0.2 * spriteNumber, 0);
                spriteMaterial.map.repeat = new THREE.Vector2(1/5, 1);
                spriteMaterial.depthTest = false;

                spriteMaterial.blending = THREE.AdditiveBlending;

                var sprite = new THREE.Sprite(spriteMaterial);
                sprite.scale.set(size, size, size);
                sprite.position.set(100, 50, -10);
                sprite.velocityX = 5;

                sceneOrtho.add(sprite);
            }

    首先創建了一個SpriteMaterial,傳遞的參數和創建粒子參數差不多。創建之后,需要設置map的一些屬性,包括offset和repeat。由於我們使用的圖片是一個橫排包含了五個圖標的壓縮圖片。所以需要指定偏移量offset。offset值從0到1。如果要顯示第三個圖標,那么x偏移量為0.2*2。y偏移量不變。repeat是指重復顯示,x軸重復為1/5是指顯示整個圖片的1/5,y軸重復1次。設置SpriteMaterial,可以使Sprite和其他的粒子系統更好的融合顯示。

    接下來床架Sprite對象,設置它的scale和position屬性,velocityX是我們自定義x軸移動速度的因子。最后,我們還得考慮如何渲染。代碼如下:

function render(){
                stats.update();

                camera.position.y = Math.sin(step += 0.01) * 20;

                sceneOrtho.children.forEach(function(e){
                    if(e instanceof THREE.Sprite){
                        e.position.x = e.position.x + e.velocityX;
                        if(e.position.x > window.innerWidth){
                            e.velocityX = -5;
                            e.material.map.offset.set(1/5 *(controls.sprite % 4), 0);
                        }
                        if(e.position.x < 0){
                            e.velocityX = 5;
                        }
                    }
                });

                requestAnimationFrame(render);

                webGLRenderer.render(scene, camera);
                webGLRenderer.autoClear = false;
                webGLRenderer.render(sceneOrtho, cameraOrtho);
            }

    camera是用來顯示三維圖形的攝像頭,和我們顯示精靈的sceneOrtho互不影響。我們遍歷了sceneOrtho.children集合。如何元素時THREE.Sprite,我們重重新設置position.x,讓Sprite動起來。

   如果要讓兩個場景都渲染出來,我們需要設置WebGLRenderer的autoClear屬性為false。

5.使用THREE.Sprite實現三維效果

    要實現三維效果,可使用THREE.Object3D對象作為Sprite對象的集合。如下所示:

function createSprites(){
                group = new THREE.Object3D();
                var range = 200;
                for(var i = 0; i < 400; i++){
                    group.add(createSprite(10, false, 0.6, 0xffffff, i % 5, range));
                }
                scene.add(group);
            }

    createSprite和4中的createSprite函數顯示,只是多了一個range參數,限制坐標范圍。

6.從高級幾何體中創建粒子系統

    粒子系統所渲染的粒子來自於幾何體的頂點。如果我們提供一個復雜的幾何體,諸如環面紐結或管道,我們可以基於這個幾何體的頂點創建出一個粒子系統。

   首先創建一個復雜幾何體TorusKnotGeometry。創建代碼如下:

var geom = new THREE.TorusKnotGeometry(
                            controls.radius,
                            controls.tube,
                            Math.round( controls.radialSegments),
                            Math.round(controls.tubularSegments),
                            Math.round(controls.p), Math.round(controls.q),
                            controls.heightScale
                        );

    參數這里不再多說了。接下來基於這個幾何體創建粒子對象PointCloud。代碼如下:

function createPointCloud(goem){
            var material = new THREE.PointCloudMaterial({
                color: 0xffffff,
                size: 3,
                transparent: true,
                blending: THREE.AdditiveBlending,
                map: generateSprite()
            });

            var cloud = new THREE.PointCloud(goem, material);
            cloud.sortParticles = true;

            return cloud;
        }

    和創建其他網格相似,字節把復雜幾何體傳遞和材質傳遞給PointCloud的構造函數。這里的generateSprite函數是通過Canvas繪制一個高亮的紋理。紋理的繪制如下:

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;
        }

    通過createradialGradirent函數創建一個從內向外的漸變效果,達到的效果就是一個比較明亮的發光點。運行結果如下:

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM