照相机又分为正交投影照相机与透视投影照相机javascript
举个简单的例子来讲明正交投影与透视投影照相机的区别。使用透视投影照相机得到的结果是相似人眼在真实世界中看到的有“近大远小”的效果(以下图中的(a));css
而使用正交投影照相机得到的结果就像咱们在数学几何学课上老师教咱们画的效果,对于在三维空间内平行的线,投影到二维空间中也必定是平行的(以下图中的(b))。html
(a)透视投影,(b)正交投影java
那么,你的程序须要正交投影仍是透视投影的照相机呢?git
通常说来,对于制图、建模软件一般使用正交投影,这样不会由于投影而改变物体比例;而对于其余大多数应用,一般使用透视投影,由于这更接近人眼的观察效果。固然,照相机的选择并无对错之分,你能够更具应用的特性,选择一个效果更佳的照相机。github
正交投影照相机(Orthographic Camera)设置起来较为直观,它的构造函数是:canvas
THREE.OrthographicCamera(left, right, top, bottom, near, far)
这六个参数分别表明正交投影照相机拍摄到的空间的六个面的位置,这六个面围成一个长方体,咱们称其为视景体(Frustum)。只有在视景体内部(下图中的灰色部分)的物体才可能显示在屏幕上,而视景体外的物体会在显示以前被裁减掉。app
为了保持照相机的横竖比例,须要保证(right - left)
与(top - bottom)
的比例与Canvas宽度与高度的比例一致。框架
near
与far
都是指到照相机位置在深度平面的位置,而照相机不该该拍摄到其后方的物体,所以这两个值应该均为正值。为了保证场景中的物体不会由于太近或太远而被照相机忽略,通常near
的值设置得较小,far
的值设置得较大,具体值视场景中物体的位置等决定。dom
下面,咱们经过一个具体的例子来解释正交投影照相机的设置。
设置照相机:
var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10); camera.position.set(0, 0, 5); scene.add(camera);
在原点处建立一个边长为1
的正方体,为了和透视效果作对比,这里咱们使用wireframe
而不是实心的材质,以便看到正方体后方的边:
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true }) ); scene.add(cube);
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <script type="text/javascript" src="libs/three.js"></script> <script type="text/javascript"> function init() { var renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('mainCanvas') }); renderer.setClearColor(0x000000);
var scene = new THREE.Scene(); // camera // canvas size is 400x300 var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10); camera.position.set(0, 0, 5); //camera.lookAt(new THREE.Vector3(0, 0, 0))经过lookAt函数指定它看着原点方向,这样咱们就能过仰望正方体了;
//注意,lookAt函数接受的是一个THREE.Vector3的实例,所以千万别写成camera.lookAt(0, 0, 0),不然非但不能获得理想的效果,并且不会报错,使你很难找到问题所在。
scene.add(camera); // a cube in the scene var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true }) ); scene.add(cube); // render renderer.render(scene, camera); } </script> </head> <body onload="init()"> <canvas id="mainCanvas" width="400px" height="300px" ></canvas> </body> </html>
获得的效果是:
咱们看到正交投影的结果是一个正方形,后面的边与前面彻底重合了,这也就是正交投影与透视投影的区别所在。
这里,咱们的Canvas宽度是400px
,高度是300px
,照相机水平方向距离4
,垂直方向距离3
,所以长宽比例保持不变。为了试验长宽比例变化时的效果,咱们将照相机水平方向的距离减少为2
:
var camera = new THREE.OrthographicCamera(-1, 1, 1.5, -1.5, 1, 10);
获得的结果是水平方向被拉长了:
接下来,咱们来看看照相机位置对渲染结果的影响。在以前的例子中,咱们将照相机设置在(0, 0, 5)
位置,而因为照相机默认是面向z轴负方向放置的,因此能看到在原点处的正方体。如今,若是咱们将照相机向右移动1
个单位:
var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10); camera.position.set(1, 0, 5);
获得的效果是物体看上去向左移动了:
仔细想一下的话,这也不难理解。就比如你人往右站了,看起来物体就相对往左移动了。
那么,正交投影照相机在设置时,是否须要保证left
和right
是相反数呢?若是不是,那么会产生什么效果呢?下面,咱们将本来的参数(-2, 2, 1.5, -1.5, 1, 10)
改成(-1, 3, 1.5, -1.5, 1, 10)
,即,将视景体设置得更靠右:
var camera = new THREE.OrthographicCamera(-1, 3, 1.5, -1.5, 1, 10); camera.position.set(0, 0, 5);
获得的结果是:
细心的读者已经发现,这与以前向右移动照相机获得的效果是等价的。
到如今为止,咱们使用照相机都是沿z轴负方向观察的,所以看到的都是一个正方形。如今,咱们想尝试一下仰望这个正方体。咱们已经学会设置照相机的位置,不妨将其设置在(4, -3, 5)
处:
camera.position.set(4, -3, 5);
可是如今照相机沿z轴负方向观察的,所以观察不到正方体,只看到一片黑。咱们能够经过lookAt
函数指定它看着原点方向:
camera.lookAt(new THREE.Vector3(0, 0, 0));
这样咱们就能过仰望正方体啦:
不过必定要注意,lookAt
函数接受的是一个THREE.Vector3
的实例,所以千万别写成camera.lookAt(0, 0, 0)
,不然非但不能获得理想的效果,并且不会报错,使你很难找到问题所在。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Three框架</title> <script src="libs/Three.js"></script> <style type="text/css"> div#canvas-frame { border: none; cursor: pointer; width: 100%; height: 600px; background-color: #EEEEEE; } </style> <script> var renderer; function initThree() { width = document.getElementById('canvas-frame').clientWidth; height = document.getElementById('canvas-frame').clientHeight; renderer = new THREE.WebGLRenderer({ antialias : true }); renderer.setSize(width, height); document.getElementById('canvas-frame').appendChild(renderer.domElement); renderer.setClearColor(0xFFFFFF, 1.0); } var camera; function initCamera() { camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000); //camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 10, 1000 ); camera.position.x = 0; camera.position.y = 0; camera.position.z = 600; camera.up.x = 0; camera.up.y = 1; camera.up.z = 0; camera.lookAt({ x : 0, y : 0, z : 0 }); } var scene; function initScene() { scene = new THREE.Scene(); } var light; function initLight() { light = new THREE.AmbientLight(0xFF0000); light.position.set(100, 100, 200); scene.add(light); light = new THREE.PointLight(0x00FF00); light.position.set(0, 0,300); scene.add(light); } var cube; function initObject() { var geometry = new THREE.CylinderGeometry( 70,100,200); var material = new THREE.MeshLambertMaterial( { color:0xFFFFFF} ); var mesh = new THREE.Mesh( geometry,material); mesh.position = new THREE.Vector3(0,0,0); scene.add(mesh); } function threeStart() { initThree(); initCamera(); initScene(); initLight(); initObject(); animation(); } function animation() { changeFov(); renderer.render(scene, camera); requestAnimationFrame(animation); } function setCameraFov(fov) { camera.fov = fov; camera.updateProjectionMatrix(); } function changeFov() { var txtFov = document.getElementById("txtFov").value; var val = parseFloat(txtFov); setCameraFov(val); } </script> </head> <body onload="threeStart();"> <div id="canvas-frame"></div> <div> Fov:<input type="text" value="45" id="txtFov"/>(0到180的值) </div> </body> </html>