正交投影摄像机和透视投影摄像机
区别
正交投影摄像机:
所有物体被渲染出来的尺寸是一样的,没有近大远小之分。因为对象相对于摄像机的距离对渲染的结果是没有影响的。常用于二维游戏中。
透视投影摄像机:
透视试图,近大远小。更贴近真实世界。
属性
正交投影摄像机Orthographic Camera:
构造函数:
THREE.OrthographicCamera(left, right, top, bottom, near, far)
参数 | 描述 |
---|---|
left(左边界) | 可视范围的左平面,渲染部分的左边界。 |
right(右边界) | 可渲染区域的另一边界 |
top(上边界) | 可渲染区域的最上面 |
bottom(下边界) | 可渲染区域的最下面 |
near(近面距离) | 基于摄像机所处的位置,从这一点开始渲染 |
far(远面距离) | 基于摄像机所处的位置,渲染场景到这一点结束 |
zoom(变焦) | 放大和缩小场景(默认值为1,小于1—缩小,大于1—放大,负数场景会上下颠倒) |
透视投影摄像机PerspectiveCamera:
构造函数:
THREE.PerspectiveCamera(fov,aspect,near,far,zoom)
参数 | 描述 |
---|---|
fov | 视场。摄像机能够看到的那部分场景。一般计算机不能完全显示能够看到的景象,所以一般会选择较小的区域。推荐默认值:50 |
aspect(长宽比) | 渲染结果的横向尺寸和纵向尺寸的比值。推荐默认值:window.innerWidth/window.innerHeight |
near(近面距离) | 定义从距离摄像机多近的距离开始渲染。推荐默认值:0.1 |
far(远面距离) | 定义了摄像机从它所处的位置能够看多远。推荐默认值:100 |
zoom(变焦) | 放大和缩小场景(默认值为1,小于1—缩小,大于1—放大,负数场景会上下颠倒) |
实例
需求
在Three.js中改变摄像机,通过点击按钮SwitchCamera时,透视摄像机变成正交摄像机。
过程
- 构建基本场景(scene,camera,renderer,plane,spotLight,ambientLight)
- 添加立方体(平铺整个平面)
- 添加初始化性能插件、dat.GUI简化实验流程
- 添加用户交互插件
- 窗口触发函数(页面响应式布局)
结果
完整代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name=viewport
content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui">
<script type="text/javascript" src="libs/three/three.js"></script>
<script type="text/javascript" src="libs/three/controls/TrackballControls.js"></script>
<script type="text/javascript" src="libs/three/geometries/ConvexGeometry.js"></script>
<script type="text/javascript" src="libs/three/geometries/QuickHull.js"></script>
<script type="text/javascript" src="libs/three/geometries/ParametricGeometries.js"></script>
<script type="text/javascript" src="libs/util/Stats.js"></script>
<script type="text/javascript" src="libs/util/dat.gui.js"></script>
<script type="text/javascript" src="libs/three/controls/OrbitControls.js"></script>
<script type="text/javascript" src="js/util.js"></script>
<script type="text/javascript" src="04-01.js"></script>
<link rel="stylesheet" href="css/default.css">
<title>Title</title>
<style>
html, body {
margin: 0;
height: 100%;
}
</style>
<script></script>
</head>
<body onload="draw()">
</body>
</html>
//初始化场景
var scene;
function initScene() {
scene = new THREE.Scene();
}
//摄像机
var camera;
function initCamera() {
//初始化摄像机为透视摄像机,设置fov(视场)、aspect(长宽比)、near(近面距离)、far(远面距离)
camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000);
//摄像机的位置
camera.position.set(120,60,180);
//摄像机所指向的位置
camera.lookAt(scene.position);
}
//渲染器
var renderer;
function initRender(){
//创建渲染器
renderer = new THREE.WebGLRenderer();
//颜色
renderer.setClearColor(new THREE.Color(0x000000));
//大小
renderer.setSize(window.innerWidth,window.innerHeight);
//将渲染的结果添加到HTML框架的body中
document.body.appendChild(renderer.domElement);
}
//平面
var plane;
//平面Geometry
var planeGeometry = new THREE.PlaneGeometry(180,180);
function initPlane(){
//平面的材质
var planeMaterial = new THREE.MeshLambertMaterial({
color: 0xffffff,
});
plane = new THREE.Mesh(planeGeometry, planeMaterial);
//旋转平面水平放置
plane.rotation.x = -0.5*Math.PI;
//设置平面位置
plane.position.set(0,0,0);
//将平面添加至场景
scene.add(plane);
}
//光源
var light;
function initLight(){
//场景添加一个环境光
scene.add(new THREE.AmbientLight(0x292929));
//添加平行光
light = new THREE.DirectionalLight(0xffffff,0.7);
light.position.set(-20,40,60);
scene.add(light);
}
//方块
var cube;
function initCube(){
//方块大小
var cubeGeometry = new THREE.BoxGeometry(4,4,4);
//两个for循环添加立方体平铺整个平面
for(var j=0;j<(planeGeometry.parameters.height/5);j++){
for(var i=0;i<planeGeometry.parameters.width/5;i++){
var rnd = Math.random()*0.75+0.25;
var cubeMaterial = new THREE.MeshLambertMaterial();
cubeMaterial.color = new THREE.Color(rnd,0,0);
cube = new THREE.Mesh(cubeGeometry,cubeMaterial);
//立方体的位置
cube.position.set(
-((planeGeometry.parameters.width)/2)+2+(i*5),
2,
-((planeGeometry.parameters.height)/2)+2+(j*5));
//添加至场景中
scene.add(cube);
}
}
}
//初始化性能插件
var stats;
function initStats(){
stats = new Stats();
document.body.appendChild(stats.domElement);
}
//使用dat.GUI简化实验流程
var trackballControls;
var controls;
function initControls(){
controls = new function(){
this.perspective = "Perspective";
this.switchCamera = function (){
//if语句判断当前相机类型
if(camera instanceof THREE.PerspectiveCamera){
camera = new THREE.OrthographicCamera(window.innerWidth/-16, window.innerWidth/16, window.innerHeight/16, window.innerHeight/-16, -200,500);
camera.position.set(120,60,180);
camera.lookAt(scene.position);
//摄像机控制函数
initInteraction();
this.perspective = "Orthographic";
}
else{
camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);
camera.position.set(120,60,180);
camera.lookAt(scene.position);
initInteraction();
this.perspective = "Perspective";
}
};
};
var gui = new dat.GUI();
gui.add(controls,'switchCamera');
gui.add(controls,'perspective').listen();
//gui窗口的位置设置
//gui.domElement.style.position = 'absolute';
//gui.domElement.style.right = '300px';
//gui.domElement.style.top = 0;
}
//摄像机控制函数
//用户交互插件 鼠标左键按住旋转,右键按住平移,滚轮缩放
var interaction;
function initInteraction() {
//轨道控制器
interaction = new THREE.OrbitControls( camera, renderer.domElement );
//是否可以缩放
interaction.enableZoom = true;
//是否自动旋转
interaction.autoRotate = true;
//是否开启右键拖拽
interaction.enablePan = true;
}
//窗口触发函数
function onWindowResize(){
//更新相机的长宽比aspect属性
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
//对于渲染器,需要改变它的尺寸大小
renderer.setSize(window.innerWidth,window.innerHeight);
}
function render(){
//告诉摄像机使用指定的摄像机渲染场景
renderer.render(scene,camera);
}
function animate(){
//更新控制器
render();
//更新性能插件
stats.update();
requestAnimationFrame(animate);
}
function draw(){
initScene();
initCamera();
initRender();
initPlane();
initLight();
initCube();
initControls();
initInteraction();
initStats();
animate();
window.onresize = onWindowResize;
}
总结
正交投影摄像机和透视投影摄像机的切换,首先用instanceof判断目前摄像机是否是透视摄像机
如果是透视投影摄像机,则用 camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far)
设置为正交投影摄像机,反之亦然
后续可以继续设置摄像机的位置,对准场景中心。