three.js學習筆記 (2) -- 基於getImageData和three.js的粒子化圖形


一:利用HTML5 canvas的新屬性 getImageData。

getImageData(image.x,image.y,image.w,image.h);
//image.x 開始復制的左上角位置的 x 坐標。
//image.y 開始復制的左上角位置的 y 坐標。
//image.w 將要復制的矩形區域的寬度。
//image.h 將要復制的矩形區域的高度。

這樣即可得到canvas指定區域的RGBA值。

其中,width、height是讀取圖像像素信息完整區域的寬度和高度,data是一個Uint8ClampedArray類型的一維數組,包含了整個圖片區域里每個像素點的RGBA的整型數據。這里必須要理解這個數組所保存像素信息的排序規則,請看下圖描述的data數組:

圖像中第i行第j列的R、G、B、A像素信息就是

Rij = [(j-1)*imageData.width + (i-1)]*4 

Gij = [(j-1)*imageData.width + (i-1)]*4 + 1;

Bij = [(j-1)*imageData.width + (i-1)]*4 + 2;

Aij = [(j-1)*imageData.width + (i-1)]*4 + 3 ;

而制作粒子化圖行的原理就是,得到先把圖片用drawImage渲染在canvas上,把有顏色的像素用數組存起來,然后隨機挑選100像素進行展示,形成粒子化圖形。

    //計算並保存坐標
    function calculate() {
        var len = image.imageData.length;
        //只保存100行,100列的像素值
        var cols = 150,//
            rows = 150;//
        //設成150行,100列后每個單元的寬高
        var s_width = parseInt(image.w/cols),   
            s_height = parseInt(image.h/rows);
        var pos = 0; //數組中的位置
        // var par_x, par_y;  //粒子的x,y坐標
        var data = image.imageData.data;  //像素值數組
        console.log(image.imageData)
        for(var i = 0; i < cols; i++) {
            for(var j = 0; j < rows; j++) {
                //計算(i,j)在數組中的R的坐標值
                pos = (j*s_height*image.w + i*s_width)*4;//相當於如果照片的width=1000,只保存100行像素,那么數組應該是10個像素為一個數組
                //判斷像素透明度值是否符合要求
                if(data[pos+3] > 100){
                    var particle = {
                        //x,y值都隨機一下,在自己划分的區域內隨機變動20一下像素
                        x: image.x + i*s_width + Math.random()*20,
                        y: image.y + j*s_height + Math.random()*20    
                    }
                    // 根據圖像不同的色值來設定粒子色值
                    if(data[pos+1] < 175 && data[pos+2] < 10) {
                        particle.fillStyle = '#ffa900';
                    } else if(data[pos+1] < 75 && data[pos+1] > 50) {
                        particle.fillStyle = '#ff4085';
                    } else if(data[pos+1] < 220 && data[pos+1] > 190) {
                        particle.fillStyle = '#00cfff';
                    } else if(data[pos+1] < 195 && data[pos+1] > 175) {
                        particle.fillStyle = '#9abc1c';
                    }
                    //符合要求的粒子保存到數組里
                    particles.push(particle);
                }
            }
        }
    }

效果圖:

 

二:利用three.js制作粒子化圖形。

查看官網,一番研究之后,利用three生成粒子化圖形主要分為兩種方法:Sprite和Points。

1、首先看看threejs官網對sprite的解釋:

A sprite is a plane that always faces towards the camera, generally with a partially transparent texture applied.

 原理:生成一個5*5*5的立方體粒子化圖形,只需要在特定位置生成5*5*5=250個粒子即可。然后給這250個粒子添加動畫效果。

                // 創建粒子
                function creatParticle(){
                    let plus_or_minus;//0代表負方向,1代表正方向
                    let particle = 5;//立方體的長寬高
                    let dis_particle = 5;//粒子之間的距離
                    let random_num = 100;//粒子隨機的最大距離
                        //新建5*5*5個粒子
                        for (let x = -particle; x < particle; x++) {
                            for (let y = -particle; y < particle; y++) {
                                for(let z = -particle; z < particle; z++){
                                    //初始化的時候隨機分配粒子,plus_or_minus代表往哪一個方向
                                    plus_or_minus = Math.floor(Math.random()*2);

                                    let sprite = new THREE.Sprite(material);
                                    finPosition = {   
                                            x:x * dis_particle,
                                            y:y * dis_particle,
                                            z:z * dis_particle
                                            };
                                    plus_or_minus == 0?sprite.position.set(-Math.random()*random_num, -Math.random()*random_num, -Math.random()*random_num):sprite.position.set(Math.random()*random_num, Math.random()*random_num, Math.random()*random_num); 
                                    positionStart.push(sprite.position); //添加初始位置數組                                    
                                    spriteList.push(finPosition);//添加至最終位置數組
                                    scene.add(sprite);
                                }
                            }
                        }

 效果圖:

 

2、首先看看threejs官網對Points的解釋:

A class for displaying points. The points are rendered by the WebGLRenderer using gl.POINTS.

 

     let geometry = new THREE.SphereGeometry( 30, 50, 50 ,0 ,Math.PI * 3,0 ,Math.PI * 3);
     let spriteMap = new THREE.TextureLoader().load( './img/sprite.png' );
     let material = new THREE.PointsMaterial( { 
              map:spriteMap
          } ) ;
     let mesh = new THREE.Points( geometry, material );
     scene.add(mesh);

但是有一個缺點:這個方法只能直接渲染,我暫時還沒有找不到動畫進行渲染。

所以我稍稍做了一點修改,先用初始化一個SphereGeometry,geometry.vertices是生成這個球體所有點的坐標集合,知道了坐標之后,用sprite進行渲染,方法和上面的正方體一樣,即可有動畫進入效果。

     let geometry = new THREE.SphereGeometry( 30, 50, 50 ,0 ,Math.PI * 3,0 ,Math.PI * 3);
     let spriteMap = new THREE.TextureLoader().load( './img/sprite.png' );
     let material = new THREE.PointsMaterial( { 
              map:spriteMap
      } ) ;
     let mesh = new THREE.Points( geometry, material );
                    
     for (let x = 0; x < geometry.vertices.length; x++) {
            let sprite = new THREE.Sprite(material);
            sprite.position.set(geometry.vertices[x].x, geometry.vertices[x].y, geometry.vertices[x].z);
            scene.add(sprite);
       }

 效果圖:

三:demo的打開方式

Node.js has a simple HTTP server package. To install:

npm install http-server -g

To run (from your local directory):

http-server . -p 8000

 

github地址:傳送門

參考資料:Three.js 粒子系統學習小記:禮花效果實現https://www.qcloud.com/community/article/376875

     打造高大上的Canvas粒子動畫http://mp.weixin.qq.com/s/prH1fc83Ro6gE2qvhdnWuw

僅供學習,如有不當或需改進之處,請君指出,感謝萬分!!!


免責聲明!

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



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