1. 程式人生 > >three.js 性能優化的幾種方法

three.js 性能優化的幾種方法

nta back code star 添加 瀏覽器 mit cto position

本篇介紹three.js性能優化的若幹方法。(個人拙見)

three.js性能優化

盡量重用MaterialGeometry

這裏以Material和Geometry為例(使用比較頻繁)



    for (var i = 0; i < 100; i++) {
        var material = new THREE.MeshBasicMaterial();
        var geometry = new THREE.BoxGeometry(10, 10, 10);

        var mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);
    }

改為


    var material = new THREE.MeshBasicMaterial();
    var geometry = new THREE.BoxGeometry(10, 10, 10);

    for (var i = 0; i < 100; i++) {
        var mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);
    }


謹慎的在render()中操作

一般FPS為60也就意味著一秒會執行60次如果render()中有有實例化或是賦值操作很容易會崩潰。

如下:


function render() {
    
    material.map = canvasMap;
    material.map.needsUpdate = true;
    
}

選擇合適的對象

  • THREE.ParticleSystem(粒子系統)代替THREE.Particle(粒子)

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

代替


    var geometry = new THREE.Geometry();
    var material = new THREE.ParticleBasicMaterial();

    for (var x = -5; x < 5; i++) {
        for (var y = -5; y < 5; y++) {
            var particle = new THREE.Vector3(x * 10, y * 10, 0);
            geometry.vertices.push(particle);
        }
    }

    var system = new THREE.ParticleSystem(geometry,material);

    scene.add(system);
    
  • 要操作一組對象時使用 THREE.Object3D
    
    var contain = new THREE.Object3D(); 

    var material = new THREE.MeshBasicMaterial();
    var geometry = new THREE.BoxGeometry(10, 10, 10);

    for (var i = 0; i < 100; i++) {
        var mesh = new THREE.Mesh(geometry, material);
        contain.add(mesh);
    }
    
    contain.rotation.x = Math.PI/3;

  • 網格合並 THREE.GeometryUtils.merge

R60

        var geometry = new THREE.BoxGeometry(5, 5, 5);
        var material = new THREE.MeshBasicMaterial({color: 0xff0000});

        for (var i = 0; i < 100; i++) {

            THREE.GeometryUtils.merge(geometry, new THREE.BoxGeometry(5, 5, 5));
        }

        var mesh = new THREE.Mesh(geometry, material);

        scene.add(mesh);

或是一下方式(geometry有位置信息)

        var geometry = new THREE.BoxGeometry(5, 5, 5);
        var material = new THREE.MeshBasicMaterial({color: 0xff0000});
        
        var mesh = new THREE.Mesh(geometry,material);
        mesh.position.set(10,10,10);
        
        var mGeo = new THREE.BoxGeometry(10, 2, 10);
        
        THREE.GeometryUtils.merge(mGeo, mesh);
   

        scene.add(new THREE.Mesh(mGeo, material));

R80 THREE.GeometryUtils.merge() change to geometry.merge()

            var geometry = new THREE.BoxGeometry(2, 4, 2);
            
            var mGeo = new THREE.BoxGeometry(5, 5, 5);
    
            var matrix = new THREE.Matrix4();
    
            for(var i=0;i<100;i++){
    
                matrix.setPosition(new THREE.Vector3(Math.random()*10,0,Math.random()*10));
                geometry.merge(mGeo, matrix);
            }
   
    
            var mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({color: 0xff0000}));
            scene.add(mesh);

使用Web Workers

web worker 是運行在後臺的 JavaScript,它獨立於其他腳本,不會影響頁面的性能
我們會發現Physijs物理庫就是使用這種方式來保證頁面的性能。

使用之前你可能需要是否支持web worker


if(typeof(Worker)!=="undefined"){}else { }

我們將web worker運行腳本放在一個js文件中。

three_workers.js:

    
    // 添加監聽事件,從主線程接收數據
    self.addEventListener(‘message‘, function(event) {
        
        // 向主線程發送數據
        self.postMessage({
            some_data: ‘‘,
            more_data: ‘‘
          })
        })

主線程.js:

    
    //新建一個 `Web Workers`
    
    var worker = new Worker(‘three_workers.js‘); 
    
    // 添加監聽事件,獲取`Web Workers`傳回數據 
    worker.addEventListener(‘message‘, function (event) { 
    
      var data = event.data;
      
    });
    
    // 向`Web Workers`發送數據
    worker.postMessage({  
      some_data: ‘‘,
      more_data: ‘‘
    });
    
    
   

可以參照:

https://threejs.org/examples/?q=sand#raytracing_sandbox

function timedChunk(items, process, context, callback){
var todo = items.concat(); //create a clone of the original

setTimeout(function(){

    var start = +new Date();

    do {
         process.call(context, todo.shift());
    } while (todo.length > 0 && (+new Date() - start < 50));

    if (todo.length > 0){
        setTimeout(arguments.callee, 25);
    } else {
        callback(items);
    }
}, 25);

}

分時加載

可以參照:

https://www.nczonline.net/blog/2009/08/11/timed-array-processing-in-javascript/

分時加載算法(大數組)

調查顯示100ms內的響應能讓用戶感覺非常流暢。50ms是 Nicholas 針對 JavaScript 得出的最佳經驗值。

setTimeout 延時25ms,25ms 保證主流瀏覽器都順暢。

可以使用類似的方法來優化three.js程序。


//Copyright 2009 Nicholas C. Zakas. All rights reserved.
//MIT Licensed

function timedChunk(items, process, context, callback){
    
    
    var todo = items.concat();   
    
    setTimeout(function(){
        
        var start = +new Date();
        
        
        do {
             process.call(context, todo.shift());
        } while (todo.length > 0 && (+new Date() - start < 50));

        if (todo.length > 0){
            setTimeout(arguments.callee, 25);
        } else {
            callback(items);
        }
    }, 25);
};

程序分析見

使用自定義著色器

以後會有一篇專門講著色器

three.js 性能優化的幾種方法