.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>