Three.js其它功能

一、任意剪裁平面 

通过任意剪裁平面,可以展示物体x剖面效果,下面的示例为展示一个球体剖面,核心代码如下所示:

  1     ...//此处省略了定义变量的代码,读者可以查看源代码进行学习
        2     var clipPlanes = [                                              //定义剪裁平面
        3              new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ),   //设置 yOz面
        4              new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 0 ), //设置 xOz面
        5              new THREE.Plane( new THREE.Vector3( 0, 0, - 1 ), 0 ), //设置 xOy面
        6     ];
        7     ...//此处省略了初始化场景,添加灯光,设置标签等部分的代码,读者可自行查看随书源代码
        8     function addGeometry(){//添加几何对象的方法
        9         var texture=["", "img/1.png", "img/1.png", "img/1.png", "img/1.png", "img/1.png
        10        ", "img/1.png", "img/1.png", "img/1.png", "img/earth.png"];  //定义纹理数组
        11        var myColor=["", "#e8cd66", "#e4c133", "#ce9b32", "#cd9a2f", "#c98f24", "#c3760a
        12        ", "#c34900", "#ae1601", "#ffffff"];                         //定义颜色数组
        13        group=new THREE.Group();                      //定义对象组合
        14        for(var i=1; i<10; i++){                        //创建10个球体
        15             var geometry = new THREE.SphereGeometry( i / 2, 48, 24 ); //创建球体
        16             var material = new THREE.MeshLambertMaterial({             //定义材质
        17                 color: new THREE.Color( myColor[i] ),                  //设置颜色
        18                 side: THREE.DoubleSide,               //设置球体内外双面纹理贴图
        19                 clippingPlanes: clipPlanes,          //设置剪裁面
        20                 clipIntersection: true,               //开启任意剪裁平面
        21                 map: THREE.ImageUtils.loadTexture(texture[i])  //设置纹理
        22             });
        23             group.add( new THREE.Mesh( geometry, material ) ); //将球体添加进对象组合
        24        }
        25        scene.add(group);                                        //将对象组合添加进场景
        26    }

            ❑ 第2~6行代码中的new THREE.Plane(normal : Vector3, constant : Float)方法为创建平面的方法,其中参数normal是一个三维向量,表示平面的法向量,默认值为(1,0,0);参数constant是一个浮点型数,表示原点到平面的距离,默认值为0。
        ❑ 第8~26行的代码创建了一个被剪裁掉1/8的地球模型,并且能够看到地球模型的内部结构。该地球模型绘制了10个半径依次增大的球,让处于里面的每一个球都贴上不同颜色的纹理,最外层的球贴上地球表面的纹理。最后就能模拟出地球和地心的效果。
        说明:在上述代码中首先定义了平面数组,然后在创建球体的材质中开启任意剪裁平面。在绘制球体时,剪裁面法向量的负方向区域为剪裁区域,3个剪裁面的法向量负方向组成了空间剪裁区域,最后绘制球体时位于空间剪裁区域内的部分将不可见。

二、 单个物体的多个实例

        在一些场景,某个物体可能会多次重复出现。如果场景中多次重复的物体是obj等格式的模型文件,为了提高场景的渲染速度,可以使用单个物体多次绘制的方式来提高场景的渲染速度和流畅性。
        示例:场景由500个茶壶按照一定的组合搭建而成。具体代码如下:

 function getColor(){                            //随机创建十六进制颜色方法
        2         var colorElements = "0,1,2,3,4,5,6,7,8,9, a, b, c, d, e, f"; //定义十六进制颜色字符串
        3         var colorArray = colorElements.split(", "); //切分颜色字符串
        4         var color ="#";                             //定义十六进制颜色的第一个字符
        5         for(var i =0; i<6; i++){
        6              color+=colorArray[Math.floor(Math.random()*16)];    //得到随机颜色值
        7         }
        8         return color;                               //返回颜色值
        9     }
        10    function getPostion() {                        //生成随机位置
        11        var postion=new THREE.Vector3();          //定义空间点坐标
        12        postion.x=Math.random()*1000;              //随机生成点的 x值
        13        postion.y=Math.random()*1000;              //随机生成点的 y值
        14        postion.z=Math.random()*1000;              //随机生成点的 z值
        15        return postion;                            //返回点坐标
        16    }
        17    function addMesh(){                            //创建物体的方法
        18        var jsLoader=new THREE.JSONLoader();      //定义js文件加载器
        19        jsLoader.load('obj/1.js', function (object) {     //加载茶壶模型的js文件
        20             object.computeBoundingBox();                  //设置茶壶模型的边界框
        21             geometrySize = object.boundingBox.getSize(); //获取茶壶模型尺寸值
        22             var objTemp=object.clone();                   //复制茶壶模型
        23             for ( var i = 0; i < meshCount; i ++ ) {     //将茶壶绘制499次
        24                 material=new THREE.MeshLambertMaterial({color:getColor()});
                          //材质随机颜色
        25                 var object = new THREE.Mesh( objTemp, material ); //创建茶壶物体对象
        26                 object.rotation.set(Math.random()*Math.PI, Math.random()*//设置旋转角度
        27                 Math.PI, Math.random()*Math.PI);
        28                 object.position.set(getPostion().x, getPostion().y, getPostion().z);
                          //设置位置
        29                 object.material = material.clone();      //复制茶壶物体对象的材质
        30                 scene.add( object );                      //将茶壶物体对象添加进场景
        31             }
        32             mesh=new THREE.Mesh(objTemp, material);       //创建原点处的茶壶对象
        33             mesh.rotation.x=-Math.PI*0.5;                //将茶壶绕 x轴旋转90°
        34             scene.add(mesh);                             //将茶壶添加进场景
35        })
        36    }


        ❑ 第1~9行为随机生成十六进制颜色的方法。通过随机数方式随机地从表示颜色的字符数组中取值,然后组合成一个完整的颜色字符串,最后将颜色字符串返回。
        ❑ 第10~16行为随机生成茶壶初始位置点的方法。由于是用随机数乘以一个常数给出的x、y、z轴坐标,所以每一个点的位置都在边长等于该常数的正方体区域内。
        ❑ 第17~36行为创建茶壶物体的方法。首先定义js文件的加载器并加载茶壶模型文件,并将茶壶几何体进行复制,再用for循环方式来创建多个茶壶网格对象并添加到场景中,同时,在创建每个茶壶网格对象时设置了不同的旋转角度和初始位置点。
        说明: 在模型加载完成之后,返回一个对象,它属于几何体对象,包含几何体的顶点数据、顶点索引数据、UV坐标数据等信息。这时便可以不用反复加载模型文件以获取对象,直接一次加载后重复使用几何体对象去创建网格对象,即可实现单个物体的多次绘制。

三、 高真实感的水面

      经常需要高真实感的水面,包括真实的水面波纹和真实的水面倒影等。在Three.js引擎中要想实现这种高真实的水面是非常简单的。Three.js引擎提供了Water类,下面通过示例说明。

(1)场景搭建,包括二十面体的创建、天空盒的加载和水面的搭建等。首先介绍的是场景的初始化,包括初始化场景基本组件、向场景中添加物体、向场景中添加天空盒、添加鼠标控制,以及添加窗口变化监听等,具体代码如下:

  1     var water;                                                  //水面
        2     var sphere;                                                 //球体
        3     var sphereAngle=0;                                          /球运动的角度
        4     ......//此处省略了声明其他变量的代码,读者可自行查看随书源代码
        5     function init() {                                           //初始化场景
        6         initScene();                                            //初始化场景的基本组建
        7         addMesh();                                              //添加物体
        8         setSkybox();                                            //添加天空盒
        9         addLight();                                             //添加光源
        10        addControls();                                          //添加鼠标控制
        11        addSupport();                                           //添加FPS状态监测
        12        renderScene();                                          //渲染场景
        13        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        14        window.addEventListener( 'resize', onWindowResize, false ); //窗口变化监听
        15    }
        16    function addSupport() {                                     //添加FPS状态监测
        17        stats=new Stats();                                      //创建状态监测对象
        18        container.appendChild( stats.dom );
        19    }
        20    function addControls() {                                    //添加鼠标控制
        21        var controls = new THREE.OrbitControls( camera, renderer.domElement );         //添加鼠标控制
        22        controls.enablePan = true;                             //是否可以平移
        23        controls.enableZoom =true;                             //是否可以缩放
        24        controls.maxPolarAngle = Math.PI*4/9;                   /控制角度
        25    }
        26    function initScene() {                                       //初始化场景的基本组件
        27        scene = new THREE.Scene();                              //创建场景对象
        28        container = document.getElementById( "container" );
        29        renderer = new THREE.WebGLRenderer({ antialias: true } ); //创建渲染器对象
        30        renderer.setClearColor(new THREE.Color(0x979797));       //设置背景颜色
        31        renderer.setSize(window.innerWidth, window.innerHeight); //设置渲染窗口的大小
        32        camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.
                  innerHeight, 0.1, 5000);
        33        camera.position.set(8,3,0);                 //设置摄像机位置
        34        camera.lookAt( scene.position );            //设置摄像机观察目标的位置
        35    }

        ❑ 第1~14行为声明变量和初始化场景。初始化场景包括初始化场景的基本组件和向场景添加物体、天空盒、光照、鼠标控制和FPS状态监测以及渲染场景。其中,添加光照的代码与前面案例的相似,在此不在赘述。
        ❑ 第16~19行为添加鼠标控制以及FPS状态监测的代码。在添加鼠标控制方法中,开启对场景平移和旋转的控制,并将旋转角度控制在一定范围内。
        ❑ 第26~35行为初始化场景的基本组件,包括创建场景对象、渲染器对象,设置背景颜色和渲染窗口的大小,创建摄像机并指定摄像机的位置和观察位置。

(2)介绍添加天空盒的方法,包括加载立方体纹理,创建立方体着色器对象,创建着色器材质,创建立方体几何对象和网格对象并将网格对象添加进场景,具体代码如下:

1    function setSkybox() {                                      //添加天空盒
        2        var cubeTextureLoader = new THREE.CubeTextureLoader(); //创建立方体纹理加载对象
        3        cubeTextureLoader.setPath( 'img/' );                   //设置加载路径
        4        var cubeMap = cubeTextureLoader.load( [        5             'skycubemap_left.jpg', 'skycubemap_right.jpg',    //立方体左面和右面的图片
        6             'skycubemap_up.jpg', 'skycubemap_down.jpg',       //立方体上面和下面的图片
        7             'skycubemap_back.jpg', 'skycubemap_front.jpg',    //立方体后面和前面的图片
        8        ] );
        9        var cubeShader = THREE.ShaderLib[ 'cube' ];            //创建立方体着色器对象
        10       cubeShader.uniforms[ 'tCube' ].value = cubeMap;      //传入立方体纹理
        11       var skyBoxMaterial = new THREE.ShaderMaterial( {     //创建着色器材质
        12            fragmentShader: cubeShader.fragmentShader,       //立方体片元着色器
        13            vertexShader: cubeShader.vertexShader,            //立方体顶点着色器
        14            uniforms: cubeShader.uniforms,                    //立方体着色器的一致变量
        15            side: THREE.BackSide                              //背面绘制
        16       } );
        17       var skyBoxGeometry = new THREE.BoxBufferGeometry(500, 500, 500); //创建立方体几何体
        18       var skyBox = new THREE.Mesh( skyBoxGeometry, skyBoxMaterial ); //创建网格对象
        19       scene.add( skyBox );                                   //将天空盒添加进场景
        20   }

说明:上面是向场景中添加天空盒的代码。首先需要创建立方体纹理加载对象,并加载天空盒的6张图片。接下来创建材质对象并将其传入立方体着色器、立方体纹理以及开启背面绘制。最后创建立方体几何体对象,创建天空盒网格对象以及将其添加进场景。

(3)介绍添加物体和渲染场景的方法。添加物体的方法包括向场景中添加二十面体,向场景中添加地板,向场景中添加水面以及设置水面的颜色、流动方向和水面反射程度等。渲染场景的方法主要是控制二十面体的运动并请求绘制下一帧画面,具体代码如下:

    1     function addMesh(){
        2         var geometry = new THREE.IcosahedronGeometry(2, 1 );   //创建一个二十面体
        3         for ( var i = 0, j = geometry.faces.length; i < j; i ++ ) {
        4              geometry.faces[ i ].color.setHex( Math.random() * 0xffffff );
                      //对每个面随机指定颜色
        5         }
        6         var material = new THREE.MeshStandardMaterial( {       //创建材质
        7              vertexColors: THREE.FaceColors,                     //顶点颜色
        8              roughness: 0.0,                                      //粗糙度
        9              flatShading: true,                       //平滑着色
        10        } );
        11        sphere = new THREE.Mesh( geometry, material );         //创建二十面体网格对象
        12        scene.add( sphere );                                     //向场景添加网格对象
        13        var groundGeometry = new THREE.PlaneBufferGeometry( 20, 20); //地板几何体
        14        var groundMaterial = new THREE.MeshStandardMaterial( { roughness: 0.8,
                  metalness: 0.4 } );
        15        var ground = new THREE.Mesh( groundGeometry, groundMaterial ); //创建地板网格对象
        16        ground.rotation.x = Math.PI * - 0.5;                   //绕 x轴逆向旋转90°
        17        var textureLoader = new THREE.TextureLoader();        //创建纹理加载对象
        18        textureLoader.load( 'img/teture.png', function( map ) {
        19             map.wrapS = THREE.RepeatWrapping;             //S轴的纹理拉伸方式
        20             map.wrapT = THREE.RepeatWrapping;             //T轴的纹理拉伸方式
        21             map.anisotropy =16;                           //最大各异向程度
        22             map.repeat.set( 5, 5 );                       //S轴和 y轴的重复次数
        23             groundMaterial.map = map;                     //传入纹理
        24             scene.add( ground );                          //将地板网格对象添加进场景
        25        } );
        26        var waterGeometry = new THREE.PlaneBufferGeometry(20, 20); //创建水面几何体
        27        water = new THREE.Water( waterGeometry, {              //创建水面网格对象
        28             color: '#ffffff',                                   //水的颜色
        29             scale: 0,                                           //纹理坐标放大倍数
        30             flowDirection: new THREE.Vector2( 4, 4 ),         //流动方向
        31             textureWidth: 1024,                                //纹理宽度
        32             textureHeight: 1024,                               //纹理高度
        33             reflectivity:0.5                                    //水面反射影像的程度
        34        } );
        35        water.position.y =1;                                    //水面的 y坐标
        36        water.rotation.x = Math.PI * - 0.5;                    //绕 x轴逆向旋转90°
        37        scene.add( water );                                     //向场景中添加水面
        38    }
        39    function renderScene() {                                    //渲染场景的方法
        40        requestAnimationFrame(renderScene);                    //请求绘制下一帧
        41        render();
        42    }
        43    function render() {                                   //实际渲染的方法
        44        sphere.position.y=2+3*Math.cos(sphereAngle);    //二十面体的运动,改变 y轴坐标
        45        sphereAngle+=0.02;                               //增加运动角度
        46        stats.update();                                   //FPS状态更新
        47        renderer.render( scene, camera );                //渲染场景
        48    }

        ❑ 第2~12行为向场景添加二十面体的方法。在创建了二十面几何体后,遍历二十面体的各个面并分别赋予不同的颜色。接着创建材质并设置顶点颜色和粗糙程度以及是否平滑着色,然后创建二十面体网格对象并将其添加进场景。
        ❑ 第13~25行为向场景添加地板网格对象的代码。创建地板几何体后,创建纹理加载对象并加载纹理和设置纹理、S轴和T轴的拉伸方式以及最大各异向程度等。在纹理加载完毕后,将地板网格对象添加进场景。
        ❑ 第26~37行代码为创建水面网格对象并将其添加进场景。在创建水面网格对象时,设置了水的颜色、纹理坐标放大倍数、流动方向,以及水面反射影像的程度等属性。
        ❑ 第39~48行为渲染场景的方法。在实际渲染场景的方法中,通过改变运动角度和改变二十面体的y坐标,可不断更新FPS的状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值