Three.js开发指南---使用构建three.js的基本组件(第二章)

.gui本章的主要内容

  1 场景中使用哪些组件

  2 几何图形和材质如何关联

  3 正投影相机和透视相机的区别

一,Three所需要的基本元素

  场景scene:一个容器,用来保存并跟踪所有我们想渲染的物体

  相机camera:场景scene中保存了所有我们想要渲染的物体,但是这些物体哪些是希望被看到的,由相机来决定,即相机决定了哪些东西将要在屏幕上渲染,场景渲染的时候会自动将camera添加进去

  光源:光源会对物体如何显示,以及生成阴影时物体如何使用产生影响

  渲染器render:负责计算指定相机角度下,浏览器中场景的样子,有给予wenbGL的渲染器,有基于Canvas的渲染器,还有基于SVG的渲染器

  物体:相机的主要渲染对象,Three自带的最基本的物体有球体,平面,坐标轴,方块等

  

二,场景

  2.1   场景是渲染过程中所有物体,光源和相机的容器

  2.2    下面是场景最经常用到的属性和方法

属性/方法 描述
add(object) 向场景中添加对象
children属性 返回一个场景中所有对象的列表,包括相机和光源
getChildByName(name) 通过对象的name属性来获取该对象
remove(object) 删除该场景中的某个对象
traverse(function(object){}) 遍历场景中的所有对象
fog 设置场景的雾化效果(一个物体离相机越远,就越模糊)
overrideMaterial 通过这个属性,可以强制场景中的所有物体使用相同的材质
var scene = new THREE.Scene();//生成一个场景
scene.add(物体);//向该场景中添加物体
scene.add(光源);//向该场景中添加光源
scene.remove(某个物体/某个光源);//移除掉该场景中的某个物体或者某个光源
scene.children();//获取场景中的所有子对象列表
scene.getChildByName(name属性);//根据name属性获取到场景中的某一个对象
scene.children.length;//获取子对象的数量
scene.traverse(function(e){console.log("遍历场景中的的每一个子对象e:",e)});
scene.fog=new THREE.Fog(0xffffff,0.015,100);//设置场景的雾化效果
scene.overrideMaterial=new THREE.MeshLambertMaterial({color:0xffffff});//设置该场景中的所有物体的材质

demo,使用dat.gui图形界面增加立方体,删除立方体,以及计算立方体的个数,以及场景雾化(一个物体离得越远,就越模糊)

<!DOCTYPE html>

<html>

<head>
    <title>1</title>
    <script type="text/javascript" src="three.js"></script>
    <script type="text/javascript" src="dat.gui.js"></script>
    <script type="text/javascript" src="AsciiEffect.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
//var scene
   function init() {
        var scene=new THREE.Scene();//生成一个场景
        //生成一个相机
        var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面
        camera.position.x=-20;
        camera.position.y=40;
        camera.position.z=30;
        camera.lookAt(scene.position);
        //生成一个渲染器
        var render=new THREE.WebGLRenderer();
        render.setClearColorHex(0xEEEEEE);
        render.setSize(window.innerWidth,window.innerHeight);
        render.shadowMapEnabled=true;//允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影

        //生成一个坐标轴,辅助线
        var axes=new THREE.AxisHelper(20);
        //生成一个平面
        var planeGeometry=new THREE.PlaneGeometry(60,20,10,10);//平面
        //生成一个材质
        var planeMaterial=new THREE.MeshLambertMaterial({color:0xffffff});
        //生成一个网格,将平面和材质放在一个网格中,组合在一起,组成一个物体
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);
        plane.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转
        plane.position.x=0;
        plane.position.y=0;
        plane.position.z=0;
        plane.receiveShadow=true;//平面进行接受阴影

        var cubeGeometry=new THREE.CubeGeometry(10,10,10);
        var planeMaterial1=new THREE.MeshLambertMaterial({color:0xff0000});
        /*var cube=new THREE.Mesh(cubeGeometry,planeMaterial1);
        //plane1.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转
        cube.position.x=-4;
        cube.position.y=3;
        cube.position.z=0;
        cube.castShadow=true;//需要阴影,方块进行投射阴影*/

        var spotLight=new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40,60,-10);
        spotLight.castShadow=true;
        //将相机,渲染器,坐标轴,平面都追加到场景中,然后对场景和相机进行渲染
        scene.add(camera);
        scene.add(render);
        scene.add(axes);
        scene.add(plane);
        //scene.add(cube);
        scene.add(spotLight);
        //var effect=new THREE.AsciiEffect(render);
        ///effect.setSize(window.innerWidth,window.innerHeight);
        document.getElementById("WebGL-output").append(render.domElement);

        var controls=new function(){
            this.rotationSpeed=0.02;
            this.numberofObject=scene.children.length;
            this.addCube=function(){
                var cubeSize=Math.ceil(Math.random()*3);
                var cubeGeometry=new THREE.BoxGeometry(cubeSize,cubeSize,cubeSize);
                var cubeMaterial=new THREE.MeshLambertMaterial({color:Math.random()*0xffffff});
                var cube=new THREE.Mesh(cubeGeometry,cubeMaterial);
                cube.castShadow=true;
                cube.name="cube-"+scene.children.length;
                cube.position.x=-30+Math.round(Math.random()*planeGeometry.parameters.width);
                cube.position.y=Math.round(Math.random()*5);
                cube.position.z=-20+Math.round(Math.random()*planeGeometry.parameters.height);
                scene.add(cube);
                this.numberofObject=scene.children.length;
            };
            this.removeCube=function(){
                var allChildren=scene.children;
                var lastChild=allChildren[allChildren.length-1];
                if(lastChild instanceof THREE.Mesh){
                    scene.remove(lastChild);
                    this.numberofObject=scene.children.length;
                }
            };
        };
        var gui=new dat.GUI();
        gui.add(controls,"rotationSpeed",0,0.5);
        gui.add(controls,"addCube");
     gui.add(controls,"removeCube");
        gui.add(controls,"numberofObject").listen();;
        function renderScene(){
            scene.traverse(function (e) {
                if (e instanceof THREE.Mesh && e != plane) {

                    e.rotation.x += controls.rotationSpeed;
                    e.rotation.y += controls.rotationSpeed;
                    e.rotation.z += controls.rotationSpeed;
                }
            });
            requestAnimationFrame(renderScene);
            render.render(scene, camera);
        }     scene.fog=new THREE.Fog(0xffffff,0.015,100);//雾化
        renderScene();
    }

    window.onload = init;

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

三 使用几何和网格对象

  3.1 几何体对象Geometry

  Geometry对象基本上是三维空间中的点集,以及将这些点集链接起来的面组成

    例如:一个方块有8个角,每个角的坐标又是x,y,z的一个组合,这8个点称之为定点

        一个方块有6个侧面,每个面有两个三角面片构成,至于我们是使用四边形来定义一个面还是使用两个三角形来构建一个面,

        如何取舍,基本上在建模的时候是使用四边形,因为它比三角形更容易增强和增强,但是对于渲染和游戏引擎来说,使用三角形则更容易,因为任意一个形状都可以渲染成多个三角形

var vertices = [
            new THREE.Vector3(1,3,1),
            new THREE.Vector3(1,3,-1),
            new THREE.Vector3(1,-1,1),
            new THREE.Vector3(1,-1,-1),
            new THREE.Vector3(-1,3,-1),
            new THREE.Vector3(-1,3,1),
            new THREE.Vector3(-1,-1,-1),
            new THREE.Vector3(-1,-1,1)
        ];
        var faces=[
            new THREE.Face3(0,2,1),
            new THREE.Face3(2,3,1),
            new THREE.Face3(4,6,5),
            new THREE.Face3(6,7,5),
            new THREE.Face3(4,5,1),
            new THREE.Face3(5,0,1),
            new THREE.Face3(7,6,2),
            new THREE.Face3(6,3,2),
            new THREE.Face3(5,7,0),
            new THREE.Face3(7,2,0),
            new THREE.Face3(1,3,4),
            new THREE.Face3(3,6,4)
        ]
        var geom=new THREE.Geometry();
        geom.vertices=vertices;
        geom.faces=faces;
        geom.computeCentroids();/*

computeCentroids这个函数是算geometry中每一个面的重心,无论在平面坐标系还是空间坐标系中,重心可以求坐标的平均值来得到,如A点(X1,Y1,Z1),B点(X2,Y2,Z2)和C点(X3,Y3,Z3),他们形成的三角面的中心是:


重心的横坐标:(X1+X2+X3)/3


重心的纵坐标:(Y1+Y2+Y3)/3


重心的竖坐标:(z1+z2+z3)/3

*/
        geom.mergeVertices();

    

下面的demo的功能

  1 使用顶点和面来构建自己的几何体,

  2 用它来创建网格,

  3 改变顶点,来改变几何体的形状,

  4 geometry的clone方法对上面定义的物体进行复制,然后赋予不同的材质,形成一个新的网格对象

需要注意的点:

  1 three.js假设一个网格几何体在其生命周期内是不会改变,我们可以设置verticeNeedUpdate的值为true,当顶点的值发生改变的时候,就会被更新,

    另外我们还需要调用computeFaceNormals方法重新计算侧面,从而完成整个模型的更新

  2 我们上面使用几何体材质的时候,使用代码语句是new Mesh(几何体,材质),在下面的demo中,我们使用的是var mesh=THREE.SceneUtils.createMultiMaterialObject(geom,materials);

  我们使用的不是单一的材质对几何体进行关联,而是使用的材质数组,即多个材质。因为除了一个可以对光做出反应的材质外,我们还想使用一个线框,可以具体看到顶点和面的位置,

  使用多种材质关联一个几何体的话,就需要使用函数THREE.SceneUtils.createMultiMaterialObject(geom,materials),在这个函数中,不是生成一个Mesh的实例,而是为每个你指定的材质都创建一个实例,然后将这些实例存放在一个组里,

  我们可以使用mesh.children.forEach(function(e){})来遍历每个网格实例

<!DOCTYPE html>

<html>

<head>
    <title>1</title>
    <script type="text/javascript" src="three.js"></script>
    <script type="text/javascript" src="dat.gui.js"></script>
    <script type="text/javascript" src="AsciiEffect.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
//var scene
   function init() {
        var scene=new THREE.Scene();//生成一个场景

        //生成一个相机
        var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面
        camera.position.x=-20;
        camera.position.y=40;
        camera.position.z=30;
        camera.lookAt(scene.position);

        //生成一个渲染器
        var render=new THREE.WebGLRenderer();
        render.setClearColorHex(0xEEEEEE);
        render.setSize(window.innerWidth,window.innerHeight);
        render.shadowMapEnabled=true;//允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影

        //生成一个平面
        var planeGeometry=new THREE.PlaneGeometry(60,20,10,10);//平面
        //生成一个材质
        var planeMaterial=new THREE.MeshLambertMaterial({color:0xffffff});
        //生成一个网格,将平面和材质放在一个网格中,组合在一起,组成一个物体
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);
        plane.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转
        plane.position.x=0;
        plane.position.y=0;
        plane.position.z=0;
        plane.receiveShadow=true;//平面进行接受阴影

        //生成一个光源
        var spotLight=new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40,60,-10);
        spotLight.castShadow=true;

        //生成点和面
        var vertices=[
            new THREE.Vector3(1,3,1),
            new THREE.Vector3(1,3,1),
            new THREE.Vector3(1,-1,1),
            new THREE.Vector3(1,-1,-1),
            new THREE.Vector3(-1,3,-1),
            new THREE.Vector3(-1,3,1),
            new THREE.Vector3(-1,-1,-1),
            new THREE.Vector3(-1,-1,1)
        ];//生成面的参数是顶点集合里面的序列号
        var faces=[
            new THREE.Face3(0,2,1),
            new THREE.Face3(2,3,1),
            new THREE.Face3(4,6,5),
            new THREE.Face3(6,7,5),
            new THREE.Face3(4,5,1),
            new THREE.Face3(5,0,1),
            new THREE.Face3(7,6,2),
            new THREE.Face3(6,3,2),
            new THREE.Face3(5,7,0),
            new THREE.Face3(7,2,0),
            new THREE.Face3(1,3,4),
            new THREE.Face3(3,6,4)

        ];

        //使用上面生成的点和面构建我们自己的几何体
      //computeFaceNormal函数对几何体的各个侧面进行计算,以完成对整个模型的构建
        var geom=new THREE.Geometry();
        geom.vertices=vertices;
        geom.faces=faces;
        geom.computeFaceNormals();

        //生成材质
        var materials=[
            new THREE.MeshLambertMaterial({opacity:0.6,color:0x44ff44,transparent:true}),
            new THREE.MeshBasicMaterial({color:0x000000,wireframe:true})
        ]

        //将上面自定义的几何体与材质关联起来,一个几何体和多个材质进行关联,使用的是方法THREE.SceneUtils.createMultiMaterialObject
        var mesh=THREE.SceneUtils.createMultiMaterialObject(geom,materials);
        mesh.children.forEach(function(e){
            e.castShadow=true;
        });

        //增加gui图形操作界面,
//初始化8个顶点的初始值
        function addControl(x,y,z){
            var controls=new function(){
                this.x=x;
                this.y=y;
                this.z=z;
            }
            return controls;
        }
        var controlPoints=[];
        controlPoints.push(addControl(3,5,3));
        controlPoints.push(addControl(3,5,0));
        controlPoints.push(addControl(3,0,3));
        controlPoints.push(addControl(3,0,0));
        controlPoints.push(addControl(0,5,0));
        controlPoints.push(addControl(0,5,3));
        controlPoints.push(addControl(0,0,0));
        controlPoints.push(addControl(0,0,3));
         //增加gui图形操作界面,gui设置折叠菜单
        var gui=new dat.GUI();
        for(var i=0;i<8;i++){
            var f1=gui.addFolder("vertices"+(i+1));
            f1.add(controlPoints[i],‘x‘,-10,10);
            f1.add(controlPoints[i],‘y‘,-10,10);
            f1.add(controlPoints[i],‘z‘,-10,10);
        }
        gui.add(new function(){
            this.clone=function(){
                var cloneGeometry=mesh.children[0].geometry.clone();//这里的mesh是一个网格集合,里面的子元素都是网格,网格对象又有几何体和材质对象,这里复制的只是网格对象的几何体
                var mesh2=THREE.SceneUtils.createMultiMaterialObject(cloneGeometry,materials);
                mesh2.children.forEach(function(e){
                    e.castShadow=true;
                });
                mesh2.translateX(5);
                mesh2.translateY(5);
                scene.add(mesh2);
            }
        },"clone");

        function renderScene(){
            var vertices=[];
            for(var i=0;i<8;i++){
                vertices.push(new THREE.Vector3(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z));

            }//由于three.js假设一个几何体在其生命周期是不会改变的,//所以这里我们要动态改变几何体的形状,需要在渲染网格对象的时候,//设置几何体的属性verticesNeedUpdate可以刷新,//然后再对侧面进行计算computeFaceNormal,以完成对几何体的重构
            mesh.children.forEach(function(e){
                e.geometry.vertices=vertices;
                e.geometry.verticesNeedUpdate=true;
                e.geometry.computeFaceNormals()
            });

            requestAnimationFrame(renderScene);
            render.render(scene, camera);
        }

        scene.add(camera);
        scene.add(spotLight);
        scene.add(plane);
        scene.add(mesh);
        scene.add(render);
        document.getElementById("WebGL-output").append(render.domElement);
        renderScene();

    }

    window.onload = init;

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

  3.2 网格mesh

  创建一个网格,需要一个几何体和一个或者多个材质,

  上面的demo中,我们已经创建了一个长方体geom,下面我们来创建两个材质

  var materials = [
            new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true}),//朗伯材质,是一种可以对光源做出反应的材质,可以用来创建暗淡的材质
            new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
//这种材质是一种非常简单的材质,不考虑光照影响,使用这种材质网格会被渲染成一些简单的平面多边形,wireframe的值设置为true,可以将材质渲染成线框,对调试有力
        ];

  创建网格的函数:THREE.SceneUtils.createMultiMaterialObject(几何体,材质)

 var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, materials);
//注意这里使用的不是THREE.mesh方法,而是createMultiMaterialObject,该方法为每个你指定的材质(这里是两种不同的材质),都创建一个网格,即创建了两个网格,一个是简单材质,不考虑光照影响,一个是对暗淡光照有反应

  然后我们将上面生成的网格添加到场景中,并通过position(位置),rotation(旋转),scale(比例),translateX/Y/Z(x/y/z轴的平移)来改变其位置和展示的效果

  mesh.translateX(5);
  mesh.translateZ(5);
  mesh.name = "clone";
  scene.remove(scene.getChildByName("clone"));
  scene.add(mesh);

position属性是针对该对象的父对象而言,而父对象一般是指场景,上面的demo中,我们使用createMultiMaterialObject方法其实是创建了一个多材质对象,即不是一个单纯的网格对象,而是一个对象组,每个网格都有两个一模一样的几何体,但是这两个几何体的材质不同,我们可以通过position或者上面别的属性,对其中一个的位置进行改变,这样就可以看到两个独立的对象了

<!DOCTYPE html>

<html>

<head>
    <title>1</title>
    <script type="text/javascript" src="three.js"></script>
    <script type="text/javascript" src="dat.gui.js"></script>
    <script type="text/javascript" src="AsciiEffect.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
//var scene
   function init() {
        var scene=new THREE.Scene();//生成一个场景

        //生成一个相机
        var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面
        camera.position.x=-20;
        camera.position.y=40;
        camera.position.z=30;
        camera.lookAt(scene.position);

        //生成一个渲染器
        var render=new THREE.WebGLRenderer();
        render.setClearColorHex(0xEEEEEE);
        render.setSize(window.innerWidth,window.innerHeight);
        render.shadowMapEnabled=true;//允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影

        //生成一个平面
        var planeGeometry=new THREE.PlaneGeometry(60,20,10,10);//平面
        //生成一个材质
        var planeMaterial=new THREE.MeshLambertMaterial({color:0xffffff});
        //生成一个网格,将平面和材质放在一个网格中,组合在一起,组成一个物体
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);
        plane.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转
        plane.position.x=0;
        plane.position.y=0;
        plane.position.z=0;
        plane.receiveShadow=true;//平面进行接受阴影

        //生成一个光源
        var spotLight=new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40,60,-10);
        spotLight.castShadow=true;

        //生成点和面
        var vertices=[
            new THREE.Vector3(1,3,1),
            new THREE.Vector3(1,3,1),
            new THREE.Vector3(1,-1,1),
            new THREE.Vector3(1,-1,-1),
            new THREE.Vector3(-1,3,-1),
            new THREE.Vector3(-1,3,1),
            new THREE.Vector3(-1,-1,-1),
            new THREE.Vector3(-1,-1,1)
        ];
        var faces=[
            new THREE.Face3(0,2,1),
            new THREE.Face3(2,3,1),
            new THREE.Face3(4,6,5),
            new THREE.Face3(6,7,5),
            new THREE.Face3(4,5,1),
            new THREE.Face3(5,0,1),
            new THREE.Face3(7,6,2),
            new THREE.Face3(6,3,2),
            new THREE.Face3(5,7,0),
            new THREE.Face3(7,2,0),
            new THREE.Face3(1,3,4),
            new THREE.Face3(3,6,4)

        ];

        //使用上面生成的点和面构建我们自己的几何体
        var geom=new THREE.Geometry();
        geom.vertices=vertices;
        geom.faces=faces;
        geom.computeFaceNormals();

        //生成材质
        var materials=[
            new THREE.MeshLambertMaterial({opacity:0.6,color:0x44ff44,transparent:true}),
            new THREE.MeshBasicMaterial({color:0x000000,wireframe:true})
        ]

        //将自定义的几何体与材质关联起来
        var mesh=THREE.SceneUtils.createMultiMaterialObject(geom,materials);
        mesh.children.forEach(function(e){
            e.castShadow=true;
        });

        //增加gui图形操作界面
        function addControl(x,y,z){
            //设置8个顶点最初的值
            //设置网格对象初始的值
            var controls=new function(){
                this.x=x;
                this.y=y;
                this.z=z;
                this.scaleX=1;
                this.scaleY=1;
                this.scaleZ=1;
                this.positionX=1;
                this.positionY=1;
                this.positionZ=1;
                this.rotationX=1;
                this.rotationY=1;
                this.rotationZ=1;
                this.translateX=1;
                this.translateY=1;
                this.translateZ=1;
            }
            return controls;
        }
        var controlPoints=[];
        controlPoints.push(addControl(3,5,3));
        controlPoints.push(addControl(3,5,0));
        controlPoints.push(addControl(3,0,3));
        controlPoints.push(addControl(3,0,0));
        controlPoints.push(addControl(0,5,0));
        controlPoints.push(addControl(0,5,3));
        controlPoints.push(addControl(0,0,0));
        controlPoints.push(addControl(0,0,3));

        var gui=new dat.GUI();
        for(var i=0;i<8;i++){
            var f1=gui.addFolder("vertices"+(i+1));
            //在渲染的时候,使用是controlPoints的x,y,z的值
            f1.add(controlPoints[i],‘x‘,-10,10);
            f1.add(controlPoints[i],‘y‘,-10,10);
            f1.add(controlPoints[i],‘z‘,-10,10);
        }

        var proControls=addControl();//获取gui图形界面的初始值,
        //当这些值发生改变的时候,都放置在proControls中,
        //在后面渲染的时候,直接取proControls里面的值就可以了
        var f2=gui.addFolder("scale");
        f2.add(proControls,‘scaleX‘,0,2);
        f2.add(proControls,‘scaleY‘,0,2);
        f2.add(proControls,‘scaleZ‘,0,2);
        var f3=gui.addFolder("position");
        f3.add(proControls,‘positionX‘,-10,10);
        f3.add(proControls,‘positionY‘,-10,10);
        f3.add(proControls,‘positionZ‘,-10,10);
        var f4=gui.addFolder("rotation");
        f4.add(proControls,‘rotationX‘,-10,10);
        f4.add(proControls,‘rotationY‘,-10,10);
        f4.add(proControls,‘rotationZ‘,-10,10);
        var f5=gui.addFolder("translate");
        f5.add(proControls,‘translateX‘,-10,10);
        f5.add(proControls,‘translateY‘,-10,10);
        f5.add(proControls,‘translateZ‘,-10,10);

        gui.add(new function(){
            this.clone=function(){
                var cloneGeometry=mesh.children[0].geometry.clone();
                var mesh2=THREE.SceneUtils.createMultiMaterialObject(cloneGeometry,materials);
                mesh2.children.forEach(function(e){
                    e.castShadow=true;
                });
                mesh2.translateX(5);
                mesh2.translateY(5);
                scene.add(mesh2);
            }
        },"clone");

        function renderScene(){
            var vertices=[];
            for(var i=0;i<8;i++){
                vertices.push(new THREE.Vector3(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z));

            }
            mesh.children.forEach(function(e){
                e.geometry.vertices=vertices;
                e.geometry.verticesNeedUpdate=true;
                e.geometry.computeFaceNormals();
                //在渲染的时候,取proControls里面的值对网格对象的属性进行设置,如果只针对网格组里面的某个具体网格对象进行属性操作,将这一块的代码注释,将下面注释的代码注销注释即可
               e.scale.set(proControls.scaleX,proControls.scaleY,proControls.scaleZ);
                e.position.set(proControls.positionX,proControls.positionY,proControls.positionZ);
                e.rotation.set(proControls.rotationX,proControls.rotationY,proControls.rotationZ);
                e.translateX(proControls.translateX);
                e.translateY(proControls.translateY);
                e.translateZ(proControls.translateZ);

            });

            /*mesh.children[0].scale.set(proControls.scaleX,proControls.scaleY,proControls.scaleZ);            mesh.children[0].position.set(proControls.positionX,proControls.positionY,proControls.positionZ);            mesh.children[0].rotation.set(proControls.rotationX,proControls.rotationY,proControls.rotationZ);            mesh.children[0].translateX(proControls.translateX);            mesh.children[0].translateY(proControls.translateY);            mesh.children[0].translateZ(proControls.translateZ);*/

            requestAnimationFrame(renderScene);
            render.render(scene, camera);
        }

        scene.add(camera);
        scene.add(spotLight);
        scene.add(plane);
        scene.add(mesh);
        scene.add(render);
        document.getElementById("WebGL-output").append(render.domElement);
        renderScene();

    }

    window.onload = init;

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

由于这里的网格对象是一个网格组,所以可以只针对该网格组合里某个具体的网格对象进行操作

三    相机

  3.1    three.js有两种相机:正投影相机和透视相机

  3.2    透视图

    下面是一个透视图,也就是最自然的视图,正如下图所示,距离视角(相机)越远的物体,被渲染的越小

var camera=new THREE.PerspectiveCamera(视场,长宽比,近面,远面);
//生成一个透视相机,设置该透视相机的视场,长宽比,近面,远面
camera.position.x=120;
camera.position.y=60;
camera.position.z=180;
//设置该相机的位置
camera.lookAt(scene.position);
//设置相机的聚焦位置,一般情况下为场景的中心,即scene.position,也可以设置其他的坐标(x,y,z)

  3.3    正投影相机:所有的方块渲染出来的尺寸都一样,对象和相机之间的距离不会影响渲染的效果

var camera=new THREE.OrthographicCamera(左边界,右边界,上边界,下边界,近面,远面);
//生成一个透视相机,设置该透视相机的视场,长宽比,近面,远面
camera.position.x=120;
camera.position.y=60;
camera.position.z=180;
//设置该相机的位置
camera.lookAt(scene.position);
//设置相机的聚焦位置,一般情况下为场景的中心,即scene.position,也可以设置其他的坐标(x,y,z)
<!DOCTYPE html>

<html>

<head>
    <title>1</title>
    <script type="text/javascript" src="three.js"></script>
    <script type="text/javascript" src="dat.gui.js"></script>
    <script type="text/javascript" src="AsciiEffect.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
//var scene
   function init() {
        var scene=new THREE.Scene();//生成一个场景

        //生成一个相机
        //var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面
        var camera=new THREE.OrthographicCamera(window.innerWidth/-16,window.innerWidth/16,window.innerHeight/16,window.innerHeight/-16);
        camera.position.x=-20;
        camera.position.y=40;
        camera.position.z=30;
        camera.lookAt(scene.position);

        //生成一个渲染器
        var render=new THREE.WebGLRenderer();
        render.setClearColorHex(0xEEEEEE);
        render.setSize(window.innerWidth,window.innerHeight);
        render.shadowMapEnabled=true;//允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影

        //生成一个平面
        var planeGeometry=new THREE.PlaneGeometry(60,20,10,10);//平面
        //生成一个材质
        var planeMaterial=new THREE.MeshLambertMaterial({color:0xffffff});
        //生成一个网格,将平面和材质放在一个网格中,组合在一起,组成一个物体
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);
        //plane.rotation.x=-0.5*Math.PI;//将平面沿着x轴进行旋转
        plane.position.x=0;
        plane.position.y=0;
        plane.position.z=0;
        plane.receiveShadow=true;//平面进行接受阴影

        //生成一个光源
        var spotLight=new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40,60,-10);
        spotLight.castShadow=true;

        //生成点和面
        var vertices=[
            new THREE.Vector3(1,3,1),
            new THREE.Vector3(1,3,1),
            new THREE.Vector3(1,-1,1),
            new THREE.Vector3(1,-1,-1),
            new THREE.Vector3(-1,3,-1),
            new THREE.Vector3(-1,3,1),
            new THREE.Vector3(-1,-1,-1),
            new THREE.Vector3(-1,-1,1)
        ];
        var faces=[
            new THREE.Face3(0,2,1),
            new THREE.Face3(2,3,1),
            new THREE.Face3(4,6,5),
            new THREE.Face3(6,7,5),
            new THREE.Face3(4,5,1),
            new THREE.Face3(5,0,1),
            new THREE.Face3(7,6,2),
            new THREE.Face3(6,3,2),
            new THREE.Face3(5,7,0),
            new THREE.Face3(7,2,0),
            new THREE.Face3(1,3,4),
            new THREE.Face3(3,6,4)

        ];
        for(var i=0;i<10;i++){
            for(var j=0;j<10;j++){
                //使用上面生成的点和面构建我们自己的几何体
                var geom=new THREE.Geometry();
                geom.vertices=vertices;
                geom.faces=faces;
                geom.computeFaceNormals();

                //生成材质
                var materials=[
                    new THREE.MeshLambertMaterial({opacity:0.6,color:0x44ff44,transparent:true}),
                    new THREE.MeshBasicMaterial({color:0x000000,wireframe:true})
                ]

                //将自定义的几何体与材质关联起来
                var mesh=THREE.SceneUtils.createMultiMaterialObject(geom,materials);
                mesh.children.forEach(function(e){
                    e.castShadow=true;
                });
                mesh.position.set(i*4,2,j*4);
                scene.add(mesh);
            }

        }

        var lookAtGeo=new THREE.SphereGeometry(2);
        var lookAtMesh=new THREE.Mesh(lookAtGeo,new THREE.MeshLambertMaterial({opacity:0.6,color:"red",transparent:true}));

        var controls=new function(){
            this.cameraType="perspective";
            this.switchCamera=function(){
                if(camera instanceof THREE.PerspectiveCamera){
                    camera = new THREE.OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
                    this.cameraType="orthographic";
                    camera.position.x = 30;
                    camera.position.y = 20;
                    camera.position.z = 10;
                }else{
                    camera=new THREE.PerspectiveCamera(90,window.innerWidth/window.innerHeight,0.1,1000);//视场,长宽比,近面,远面
                    camera.position.x = 80;
                    camera.position.y = 20;
                    camera.position.z = 30;
                    this.cameraType="perspective";
                }

                camera.lookAt(scene.position);
            }
        }

        //增加gui图形操作界面
        var gui=new dat.GUI();

        gui.add(controls,"switchCamera");
        gui.add(controls,"cameraType").listen();
        var step=0;
        function renderScene(){
            var vertices=[];
            step+=0.02;
            if(camera instanceof THREE.Camera){
                var x=10+(10*Math.sin(step));
                camera.lookAt(new THREE.Vector3(x,10,0));
                lookAtMesh.position.copy(new THREE.Vector3(x,10,0))
            }
            requestAnimationFrame(renderScene);
            render.render(scene, camera);
        }
        scene.add(lookAtMesh);
        scene.add(camera);
        scene.add(spotLight);
        //scene.add(plane);
        scene.add(mesh);
        scene.add(lookAtMesh);
        scene.add(render);
        document.getElementById("WebGL-output").append(render.domElement);
        renderScene();

    }

    window.onload = init;

</script>
</body>
</html>
时间: 2024-09-28 17:37:59

Three.js开发指南---使用构建three.js的基本组件(第二章)的相关文章

《node.js开发指南》读后感

<node.js开发指南>这部只有180多页的书,我花了一个多月的业余时间算是粗略看完了.中间因为公司项目的加班,中断了几次.大大拖累进度,现在空出来时间,写一点自己的小小感想吧. 先从缺点开始: 我认为最大缺点就是老了.node是一个快速变化的东东,这本书上的内容,在现在的node上出现了很大的分叉.比如,书中提到安装node的时候,使用系统的apt-get或yum工具安装.可是这样安装之后的node.js的终端工具是nodejs,而不是node.这个就导致了一个新的问题,在这本书中的后一节

使用Nodejs创建基本的网站 Microblog--《Node.js开发指南》 3

使用cluster模块 创建cluster.js,调用app.js var cluster = require('cluster'); var os = require('os'); //获取CPU数量 var numCPUs = os.cpus().length; var workers = {}; if(cluster.isMaster) {   //主进程分支   cluster.on('exit', function (worker) {     //当一个工作进程结束时,重启工作进程

电子书 Node.js开发指南.pdf

<图灵原创:Node.js开发指南>首先简要介绍Node.js,然后通过各种示例讲解Node.js的基本特性,再用案例式教学的方式讲述如何用Node.js进行Web开发,接着探讨一些Node.js进阶话题,最后展示如何将一个Node.js应用部署到生产环境中. <图灵原创:Node.js开发指南>面向对Node.js感兴趣,但没有基础的读者,也可供已了解Node.js,并对Web前端/后端开发有一定经验,同时想尝试新技术的开发者参考. 限个人学习使用,不得用于商业用途,请在下载后2

《Three js开发指南》 PDF

电子版仅供预览及学习交流使用,下载后请24小时内删除,支持正版,喜欢的请购买正版书籍:<Three js开发指南> pdf下载地址:链接: https://pan.baidu.com/s/1uyX24NV833ZNRqXuIHHlig 密码: qasg 原文地址:https://www.cnblogs.com/wsg25/p/9575583.html

Node.js开发入门—notepad++ for Node.js

对于Node.js开发,论IDE的话,Webstorm是不二的选择,但它是收费的(可免费使用30天).一开始,我们先将就一下,使用notepad++来编写Node.js应用.这样做还有一大好处:没有关于Node.js的代码高亮和自动补全,可以更好地敦促我们使用在线API文档记忆各种类库API.死磕自己吧,enjoy it. notepad++的安装与配置 到"https://notepad-plus-plus.org/download/v6.8.2.html"这里下载吧,6.8.2版本

Node.js 开发指南笔记

第一章:node简介 介绍了node是什么:node.js是一个让javascript运行在服务器端的开发平台, node能做些什么:[书上的] 具有复杂逻辑的网站 基于社交网络的大规模Web应用 Web Socket服务器 TCP/UDP套接字应用程序 命令行工具 交互式终端程序 带有图形用户界面的本地应用程序 单元测试工具 客户端Javascript编译器 node能做些什么:[网上比较好的一段说明]: NodeJS的作者说,他创造NodeJS的目的是为了实现高性能Web服务器,他首先看重的

【读书笔记】Node.js开发指南

一:Node.js是什么? 正如当年为了统一 JavaScript 语言标准,人们制定了 ECMAScript 规范一样,如今为了统一 JavaScript 在浏览器之外的实现, CommonJS 诞生了. CommonJS 试图定义一套普通应用程序使用的API,从而填补 JavaScript 标准库过于简单的不足. CommonJS 的终极目标是制定一个像 C++ 标准库一样的规范,使得基于 CommonJS API 的应用程序可以在不同的环下运行,就像用 C++ 编写的应用程序可以使用不同的

【Node.js开发指南 BYVoid】3.1 开始使用 Node.js编程

3.1.1 Hello World 打开vscode, 输入console.log("helloworld"); 新建保存文件名为helloworld.js 打开终端,进入helloword.js所在的目录(shift+右键空白处,在此处打开命令行),执行 node helloworld.js 常用输出指令 console.log console.error console.log是最常用的指令,和C语言中的printf功能类似,也可以接受任意多个参数,支持%d %s变量的引用 3.1

NODE.JS开发指南学习笔记

1.Node.js是什么 Node.js是一个让JS运行在服务器端的开发平台,它可以作为服务器向用户提供服务.Node.js中的javascript只是Core javascript,或者说是ECMAJavaScript的一个实现.2.Node.js能做什么 JS是为客户端为生,而Node.js是为网络而生.利用它可以轻松的开发出很多网站.社交应用.服务器等等. Node.js内建有一个HTTP服务器支持,可以实现一个网站和服务器的组合.3.异步式I/O和事件驱动 Node.js最大的特点就是采