[ThreeJs学习笔记]2.Threejs卡顿优化-释放显卡缓存

做项目的过程中,遇到了很多的卡顿问题,最后经由暮志未晚 https://www.wjceo.com/ 群内各个大佬的指点,明白释放缓存的重要性,在这里作为一篇小笔记记录在这里

1.删除场景中的物体时,记得同时调用dispose方法来清空显存占用

/**
     * 清空当前obj对象的缓存
     * @param mesh  mesh对象
     * */
    function clearCache(mesh) {
        let mesh ;
        mesh.geometry.dispose();
        mesh.material.dispose();
    }

上述方法中,需要传入一个参数,该参数可以是一个mesh对象,也可以是一个object3D对象及其子类,然后将其内部的geometry,material(若有texture对象也需要把texture清除)使用.dispose()方法,清空它们在显卡中的缓存

可以在chrome中,按下Shitft+Esc检测显卡缓存
在这里插入图片描述

简单的小示例代码,主要用于测试清空缓存的效果
测试过程:
1.changeSphere方法中注释掉
clearCache(list[i])
这一行后,每次切换球体,都会导致显卡内存成倍增加,切换几次后,浏览器崩溃
2.使用了clearCache()清空缓存后,显卡内存不再增加

这里就不上图了,可以自行下来做测试

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../three.js-master/build/three.js"></script>
    <!--引入跟随鼠标移动事件的JS -->
    <script src="../three.js-master/examples/js/controls/OrbitControls.js"></script>
    <!--引入编辑框,屏幕右上角-->
    <script src="../three.js-master/examples/js/libs/dat.gui.min.js"></script>
    <style>
        body{
        }
    </style>
</head>
<body>
<input type="button" value="刷新当前页面球体" onclick="changeSphere()">
<script>
    //声明全局的场景, 相机,渲染器,灯光
    var scene,camera,renderer,light;
    function init() {
        //创建场景
        scene = new THREE.Scene();

        //创建相机
        camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,2000);
        camera.position.z = 335;
        camera.position.y =158;
        camera.position.x =114;
        camera.rotation.set(-0.24,0.01,0);

        //创建灯光
        light = new THREE.PointLight(0xffffff,1);
        //将灯光添加到相机中
        camera.add(light);
        //将相机添加进场景
        scene.add(camera);

        //创建渲染器,                       设定背景透明
        renderer = new THREE.WebGLRenderer({alpha:true});
        //设定渲染器大小
        renderer.setSize(window.innerWidth*0.75,window.innerHeight*0.75);
        //将渲染器放到<body></body>中
        document.body.appendChild(renderer.domElement);

    }

    //在场景中添加1000个球体
    var list = [];
    function initMesh(){
        for(let i =0;i<1000;i++){
            let geometry = new THREE.SphereGeometry(5,16,16);
            let material = new THREE.MeshLambertMaterial({color:0xffffff*Math.random(),wireframe:true});
            let mesh = new THREE.Mesh(geometry,material);
            mesh.position.x = Math.random()*2000-1000;
            mesh.position.y = Math.random()*2000-1000;
            mesh.position.z = Math.random()*2000-1000;
            list[i]= mesh;
            scene.add(list[i]);
        }

    }
    //对应按钮的事件,清空所有当前的球体,重新生成1000个新的球体
    function changeSphere() {
        for(let i =0;i<list.length;i++){
            let geometry = new THREE.SphereGeometry(5,16,16);
            let material = new THREE.MeshLambertMaterial({color:0xffffff*Math.random(),wireframe:true});
            let mesh = new THREE.Mesh(geometry,material);
            mesh.position.x = Math.random()*2000-1000;
            mesh.position.y = Math.random()*2000-1000;
            mesh.position.z = Math.random()*2000-1000;
           // clearCache(list[i]);  //取消该行注释后,每次切换新的球体时,显卡缓存会被清理
            scene.remove(list[i]);
            list[i] = mesh;
            scene.add(list[i]);
        }
    }


    //orbit相机视角控制器
    function initOrbit(){
        var orbit = new THREE.OrbitControls(camera,renderer.domElement);
        renderer.render(scene,camera);
    }

    //执行动作之后,将移动结果展现出来
    function animate(){
        renderer.render(scene,camera);
        requestAnimationFrame(animate);
    }

    /**
     * 清空当前obj对象的缓存
     * @param object object3D对象或mesh对象
     * */
    function clearCache(object) {
        let  mesh = object;
        mesh.geometry.dispose();
        mesh.material.dispose();
    }

    /**
     * 清空渲染器缓存,该demo中无需使用
     */
    function clearRenderer(){
        renderer.dispose();
        renderer.forceContextLoss();
        renderer.context = null;
        renderer.domElement = null;
        renderer = null;
    }

    //当窗口加载完成时,执行上述所有方法
    window.onload = function start(){
        init();
        initMesh();
        initOrbit();
        animate();
    }
</script>
</body>
</html>

2.切换页面时,清空当前页面缓存

笔者在Vue+threejs的项目中,使用了组件切换,页面并没有刷新,但是每次都会重载一次场景,致使场景异常的卡顿,所以在每次切换组件后,调用了下列方法来清空上一个组件中的缓存,使得项目大幅度优化

在上述代码中,有一段方法并未在该示例中使用,这段代码就是用来清空渲染器缓存

function clearRenderer(){
        renderer.dispose();
        renderer.forceContextLoss();
        renderer.context = null;
        renderer.domElement = null;
        renderer = null;
    }

该方法会将显存中,当前页面所有的显存清除,当你要清空当前画布,生成新的画布时调用,会清空上一个画布所占用的显卡缓存,从而优化整体项目