three.js正交投影照相機

照相機又分爲正交投影照相機與透視投影照相機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寬度與高度的比例一致。框架

nearfar都是指到照相機位置在深度平面的位置,而照相機不該該拍攝到其後方的物體,所以這兩個值應該均爲正值。爲了保證場景中的物體不會由於太近或太遠而被照相機忽略,通常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);

獲得的效果是物體看上去向左移動了:

[+]查看原圖

仔細想一下的話,這也不難理解。就比如你人往右站了,看起來物體就相對往左移動了。

那麼,正交投影照相機在設置時,是否須要保證leftright是相反數呢?若是不是,那麼會產生什麼效果呢?下面,咱們將本來的參數(-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>

相關文章
相關標籤/搜索