three.js中正交和透视投影相机的应用

一个场景之所以会呈现在我们眼前是因为我们具有眼睛,眼睛提供了视觉。换句话说,如果three.js场景中没有这双眼睛,就像电影没有摄像机一样,场景就无法呈现在我们面前?这双眼睛就是相机,可见相机是Three.js场景中不可或缺的一个组件。Three.js库提供了两种不同的相机:正交投影相机和透视投影相机,接下来分别讲解这两种相机以及结合实例的应用。

1 正交投影相机

我们先来看一张示意图:


由图可知正交透视相机总共有6个面,其具备的特点是:场景中远处的物体和近处的物体是一样大的,它并不像我们现实生活中看场景那样,远小近大,而是远近皆一样大;6个面分别为left(左面),right(右面),top(顶面),bottom(底面),near(近面),near(远面),右这六个面组成一个封闭的矩形空间,在这个空间内的一切物体都可见。在设置其参数的时候,下面的关系式一定要成立:

| left / right | = 1,top / buttom | = 1

正交相机的代码实现为:

var camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);

2 投射投影相机

投射投影相机才是现实世界中我们看到的场景的体现:远小近大,即我们所说的透视效果。先来看一张示意图:


如图中所示,透视投影相机一共有4个参数:fov(视场,一个角度值), Horizonta Field of View(横向视场),Vertical

 Field of View(纵向视场),Near plane(近面), Far plane(远面);由这几个因素,构成一个六面体的封闭空间,在这个空间内的一切物体可见。在设置参数时,需满足:

横向视场 纵向视场 = 浏览器窗口的宽/浏览器窗口的高。

其代码实现为:

var camera = new THREE.PerspectiveCamera(fov, window.innerWidth/window.innerHeight, near, far);

3 实例

这里实现两种相机的应用,里面添加了一个简单的交互条,实现的效果如下图:



本例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>threejs-camera</title>
    <style>
        body{
            font-family: Monospace;
            backgroud: #f0f0f0;
            margin: 0px;
            overflow: hidden;
        }
    </style>
</head>
<body>
<script type="text/javascript" src="build/three.js"></script>
<script type="text/javascript" src="js/Detector.js"></script>
<script type="text/javascript" src="js/libs/dat.gui.min.js"></script>
<script type="text/javascript">

    //检测webgl的支持情况
    if(!Detector.webgl) {Detector.addGetWebGLMessage();}
    var container;
    var scene, camera, renderer;


    window.onload = function main(){
        //添加一个div元素
        container  = document.createElement('div');
        document.body.appendChild(container);

        //创建新场景
        scene = new THREE.Scene();

        //渲染
        //antialias:true增加抗锯齿效果
        renderer = new THREE.WebGLRenderer({antialias:true});
        renderer.setClearColor(new THREE.Color(0x3399CC));//设置窗口背景颜色为黑
        renderer.setSize(window.innerWidth, window.innerHeight);//设置窗口尺寸
        //renderer关联到container,这个过程类似于获取canvas元素
        container.appendChild(renderer.domElement);

        perCamera();
        light();
        myScene();
        render();
    };

    //创建一个透视相机
    function perCamera(){
        camera = new THREE.PerspectiveCamera(25,
            window.innerWidth/window.innerHeight, 1, 1000);
        camera.position.set(150, 180, 100);//设置相机位置
        camera.lookAt(scene.position);//让相机指向场景中心
    }

    //创建一个正交投影相机
    function orthCamera(){
        camera = new THREE.OrthographicCamera(window.innerWidth/-14.5,window.innerWidth/14.5,
           window.innerHeight/14.5,window.innerHeight/-14.5,-100,400);
        camera.position.set(150,180, 100);//设置相机坐标
        camera.lookAt(scene.position);//让相机指向场景中心
    }
    //灯光
    function light(){
        //自然光
        var ambientLight = new THREE.AmbientLight( 0x606060 );
        scene.add( ambientLight );

        //平行光源
        var directionalLight = new THREE.DirectionalLight( 0xffffff );
        directionalLight.position.set( 1, 1.75, 0.5 ).normalize();
        scene.add( directionalLight );
    }
    //创建一个立体场景
    function myScene(){
        //创建平面
            var planeGeo = new THREE.PlaneGeometry(100,100,10,10);//创建平面
            var planeMat = new THREE.MeshLambertMaterial({  //创建材料
                color:0x999999,
                wireframe:false
            });
            var planeMesh = new THREE.Mesh(planeGeo, planeMat);//创建网格模型
            planeMesh.position.set(0, 0, -20);//设置平面的坐标
            planeMesh.rotation.x = -0.5 * Math.PI;//将平面绕X轴逆时针旋转90            scene.add(planeMesh);//将平面添加到场景中
        //创建立方体
            var cubeGeo1 = new THREE.CubeGeometry(20, 40, 20, 5, 5, 5);//创建立方体
            var cubeMat1 = new THREE.MeshLambertMaterial({//创建材料
                color:0x333333,
                wireframe:false
            });
            var cubeMesh1 = new THREE.Mesh(cubeGeo1, cubeMat1);//创建立方体网格模型
            cubeMesh1.position.set(15, 10, 0);//设置立方体的坐标
            scene.add(cubeMesh1);//将立方体添加到场景中

            var cubeGeo2 = new THREE.CubeGeometry(20, 40, 20, 5, 5, 5);//创建立方体
            var cubeMat2 = new THREE.MeshLambertMaterial({//创建材料
            color:0x333333,
            wireframe:false
            });
            var cubeMesh2 = new THREE.Mesh(cubeGeo2, cubeMat2);//创建立方体网格模型
            cubeMesh2.position.set(-25, 16, 0);//设置立方体的坐标
            scene.add(cubeMesh2);//将立方体添加到场景中

            var cubeGeo3 = new THREE.CubeGeometry(20, 40, 20, 5, 5, 5);//创建立方体
            var cubeMat3 = new THREE.MeshLambertMaterial({//创建材料
            color:0x333333,
            wireframe:false
            });
            var cubeMesh3 = new THREE.Mesh(cubeGeo3, cubeMat3);//创建立方体网格模型
            cubeMesh3.position.set(10, 20, -40);//设置立方体的坐标
            scene.add(cubeMesh3);//将立方体添加到场景中
    }

    //添加交互工具条
    var controls = new function(){
        this.相机 = false;
    };

    var gui = new dat.GUI();
    gui.add(controls, '相机', ["透视投影相机","正交投影相机"]).onChange(function(e){
        switch (e) {
            case "正交投影相机":
                orthCamera();
                break;
            case "透视投影相机":
                perCamera();
                break;
        }
    });

    function render(){
        renderer.render(scene, camera);
        requestAnimationFrame(render);
    }
</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_37338983/article/details/78691705