ThreeJs - 160万个三角形组成的正方体

效果图如下:代码如下(代码还需要优化,暂时能实现效果就行)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>160万个几何体</title>
    <style>
        body{
            color: #cccccc;
            font-family: monospace;
            font-size: 13px;
            text-align: center;

            background-color: #FF8C00;
            margin: 0px;
            overflow: hidden;
        }

        #info{
            position: absolute;
            top: 0px;
            width: 100%;
            padding: 5px;
        }

        a{
            color: cornflowerblue;
        }
    </style>
</head>
<body>
    <div id="container"></div>
    <div id="info">WEBGL_ThreeJs:高性能渲染保持高帧数</div>

    <script src="../../js/three.js"></script>
    <script src="../../js/Stats.js"></script>
    <script src="../../js/WEBGL.js"></script>
    <script>
        //检测浏览器是否支持webgl
        if( !WEBGL.isWebGLAvailable() ){
            var warning = WEBGL.getWebGLErrorMessage();
            document.getElementById('container').appendChild(warning);
        }

        //执行函数
        initAll();
        animate();

        //声明常量
        var container,states;
        var renderer,camera,scene;
        var mesh;
        
        //初始化容器
        function initContainer() {
            container = document.getElementById("container");
        }

        //初始化相机
        function initCamera() {
            camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,1,3500);
            //相机位置
            camera.position.x = 0;
            camera.position.y = 0;
            camera.position.z = 2800;
            //相机快门座标
            camera.up.x = 0;
            camera.up.y = 1;
            camera.up.z = 0;
            //镜头的朝向
            camera.lookAt(0,0,1);
        }
        //初始化场景
        function initScene() {
            scene = new THREE.Scene();
            scene.fog = new THREE.Fog(0x050505,2000,3500);
        }

        //初始化灯光
        function initLight() {
            //环境光
            var lightAm = new THREE.AmbientLight(0x444444,1.0);
            scene.add(lightAm);

            //方向光
            var lightDi1 = new THREE.DirectionalLight(0xffffff,0.5);
            lightDi1.position.set(1,1,1);
            scene.add(lightDi1);

            var lightDi2 = new THREE.DirectionalLight(0xffffff,1.5);
            lightDi2.position.set(0,-1,0);
            scene.add(lightDi2);
        }

       function initObject() {
           //定义三角形
           var triangles = 160000;
           //模型多,使用buffer更高效
           var geometry = new THREE.BufferGeometry();
           //形成三角形的点的个数,
           var positions = new Float32Array(triangles*3*3);
           //每个顶点一个法向量,也可以每个面一个法向量
           var normals = new Float32Array(triangles*3*3);
           //每个顶点一个颜色
           var colors = new Float32Array(triangles*3*3);
           //实例化颜色
           var color = new THREE.Color();

           //正方体的边长为800
           var n = 800;
           //正方体边长的一半
           var n2 = n/2;
           //三角形边长
           var d = 12;
           //三角形边长的一半
           var d2 = d / 2;

           //声明三角形顶点的位置
           var pA = new THREE.Vector3();
           var pB = new THREE.Vector3();
           var pC = new THREE.Vector3();

           //a-b\c-b的两条线
           var ab = new THREE.Vector3();
           var cb = new THREE.Vector3();

           for(var i = 0; i < positions.length; i += 9){
               //随机每个座标的位置
               var x = Math.random() * n - n2;
               var y = Math.random() * n - n2;
               var z = Math.random() * n - n2;

               //随机每个点的位置
               var ax = x + Math.random() * d -d2;
               var ay = y + Math.random() * d -d2;
               var az = z + Math.random() * d -d2;

               var bx = x + Math.random() * d -d2;
               var by = y + Math.random() * d -d2;
               var bz = z + Math.random() * d -d2;

               var cx = x + Math.random() * d -d2;
               var cy = y + Math.random() * d -d2;
               var cz = z + Math.random() * d -d2;

               positions[ i ]    = ax;
               positions[ i + 1] = ay;
               positions[ i + 2] = az;

               positions[ i + 3] = bx;
               positions[ i + 4] = by;
               positions[ i + 5] = bz;

               positions[ i + 6] = cx;
               positions[ i + 7] = cy;
               positions[ i + 8] = cz;

               //座标放入vector中
               pA.set(ax,ay,az);
               pB.set(bx,by,bz);
               pC.set(cx,cy,cz);

               //使用向量的减法算出ab\cb向量
               ab.subVectors(pA,pB);
               cb.subVectors(pC,pB);

               //计算出垂直于屏幕的向量,也称之为法线。根据ab、cb计算,返回值会赋给被调用的函数名(用词不太对)
               cb.cross(ab);
               //法线的归一化(按比例缩短到单位长度,方向不变,也就是说不管这条线有多长,都缩短到1,方向不变)
               cb.normalize();

               //法线
               var nx = cb.x;
               var ny = cb.y;
               var nz = cb.z;

               normals[ i ] = nx;
               normals[ i + 1 ] = ny;
               normals[ i + 2 ] = nz;

               normals[ i + 3 ] = nx;
               normals[ i + 4 ] = ny;
               normals[ i + 5 ] = nz;

               normals[ i + 6 ] = nx;
               normals[ i + 7 ] = ny;
               normals[ i + 8 ] = nz;

               //颜色
               var vx = ( x / n ) + 0.5;
               var vy = ( y / n ) + 0.5;
               var vz = ( z / n ) + 0.5;
               //设置RGB通道值
               color.setRGB(vx , vy , vz);

               colors[ i ] = color.r;
               colors[ i + 1 ] = color.g;
               colors[ i + 2 ] = color.b;

               colors[ i + 3 ] = color.r;
               colors[ i + 4 ] = color.g;
               colors[ i + 5 ] = color.b;

               colors[ i + 6 ] = color.r;
               colors[ i + 7 ] = color.g;
               colors[ i + 8 ] = color.b;
           }

           //把值添加到geometry中
           geometry.addAttribute('position',new THREE.BufferAttribute(positions,3));
           geometry.addAttribute('normal',new THREE.BufferAttribute(normals,3));
           geometry.addAttribute('color',new THREE.BufferAttribute(colors,3));


           //计算几何体的外边界球,可用作物体的碰撞或相交
           geometry.computeBoundingSphere();

           var material = new THREE.MeshPhongMaterial({
               color:0xaaaaaa , specular:0xffffff , shininess:250,
               side:THREE.DoubleSide , vertexColors:THREE.VertexColors
           });

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

        //初始化渲染器
        function initRenderer() {
            renderer = new THREE.WebGLRenderer({
                antialias:false
            });
            //设置渲染器的大小
            renderer.setSize(window.innerWidth,window.innerHeight);
            //清理颜色
            renderer.setClearColor(scene.fog.color);
            //设置设备像素比
            renderer.setPixelRatio(container.devicePixelRatio);
            //渲染到容器中
            container.appendChild(renderer.domElement);

            //gamma矫正,使画面看起来舒服
            renderer.gammaInput = true;
            renderer.gammaOutput = true;

            //性能监视器
            states = new Stats();
            states.domElement.style.position = 'absolute';
            states.domElement.style.top = '0';
            container.appendChild(states.domElement);

            //容器视图调整大小时执行函数
            window.addEventListener('resize',onContainerResite,false);
        }
        
        //视图改变大小时被执行的函数
        function onContainerResite() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize(window.innerWidth , window.innerHeight);
        }
        
        //循环渲染
        function animate() {
            requestAnimationFrame(animate);
            render();
            states.update();
        }
        
        function render() {
            var time = Date.now() * 0.001;

            mesh.rotation.x = time * 0.25;
            mesh.rotation.y = time * 0.25;

            renderer.render(scene , camera);
        }


        //执行所有函数
        function initAll() {
            initContainer();
            initCamera();
            initScene();
            initLight();
            initObject();
            initRenderer();
        }
        

    </script>
</body>
</html>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章