three.js 02-05 之相机

59 篇文章 2 订阅
59 篇文章 6 订阅

    前一篇我们介绍了 Three.js 中 Mesh 网格对象的一些常用函数及属性。本篇我们将介绍 Three.js 中有关相机的概念,照例我们先上一个完整的示例,代码如下:

<!DOCTYPE html>
<html>
<head>
    <title>示例 02.05 - 相机</title>
	<script src="../build/three.js"></script>
	<script src="../build/js/controls/OrbitControls.js"></script>
	<script src="../build/js/libs/stats.min.js"></script>
	<script src="../build/js/libs/dat.gui.min.js"></script>
	<script src="../jquery/jquery-3.2.1.min.js"></script>
    <style>
        body {
            /* 设置 margin 为 0,并且 overflow 为 hidden,来完成页面样式 */
            margin: 0;
            overflow: hidden;
        }
		/* 统计对象样式 */
		#Stats-output {
			position: absolute;
			left: 0px;
			top: 0px;
		}
    </style>
</head>
<body>

<!-- 用于 WebGL 输出的 Div -->
<div id="WebGL-output"></div>
<!-- 用于统计 FPS 输出的 Div -->
<div id="Stats-output"></div>

<!-- 运行 Three.js 示例的 Javascript 代码 -->
<script type="text/javascript">

	var scene;
	var camera;
	var render;
	var controls;
	var stats;
	
	var guiParams;
	var gui;
	
	var plane;
	var mesh;
	var centerSphere;

    // 当所有元素加载完毕后,就执行我们 Three.js 相关的东西
    $(function() {
		stats = initStats();
		
		scene = new THREE.Scene();
		camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // 2147483647
		camera.position.set(120, 60, 180);
		render = new THREE.WebGLRenderer( {antialias: true} ); // antialias 抗锯齿
		render.setSize(window.innerWidth, window.innerHeight);
		render.setClearColor(0xEEEEEE, 1.0);
		render.shadowMap.enabled = true; // 允许阴影投射
		$('#WebGL-output')[0].appendChild(render.domElement);
		window.addEventListener('resize', onWindowResize, false);
		var target = new THREE.Vector3(scene.position.x, scene.position.y + 10, scene.position.z);
		controls = new THREE.OrbitControls(camera, render.domElement);
		controls.target = target; // 解决 camera.lookAt(x, y, z) 失效问题
		camera.lookAt(target);
		
		scene.add(new THREE.AxisHelper(20));// 加入坐标轴
		
		// 加入一个平面
		var planeGeometry = new THREE.PlaneGeometry(180, 180);
		var planeMaterial = new THREE.MeshLambertMaterial( {color: 0xFFFFFF} );
		plane = new THREE.Mesh(planeGeometry, planeMaterial);
		plane.rotation.x = -0.5 * Math.PI; // 沿着 X轴旋转-90°
		plane.position.x = 0;
		plane.position.y = 0;
		plane.position.z = 0;
		plane.receiveShadow = true; // 几何平面接收阴影
		scene.add(plane);
		
		// 为相机目标设置一个球
		var centerGeometry = new THREE.SphereGeometry(2);
		var centerMaterial = planeMaterial.clone();
		centerSphere = new THREE.Mesh(centerGeometry, centerMaterial);
		centerSphere.position.set(target.x, controls.target.y, target.z);
		scene.add(centerSphere);
		
		// 加入立方体
		var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        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);
                var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

                cube.position.z = -((planeGeometry.parameters.height) / 2) + 2 + (j * 5);
                cube.position.x = -((planeGeometry.parameters.width) / 2) + 2 + (i * 5);
                cube.position.y = 2;

                scene.add(cube);
            }
        }
		
		// 加入一个环境光源
		var ambientLight = new THREE.AmbientLight(0x292929);
		scene.add(ambientLight);
		
		// 加入一个方向灯灯光源
		// 注:基础材质 MeshBasicMaterial 不会对光源产生反应,因此要改用 MeshLambertMaterial 或 MeshPhongMaterial 材质才有效果
		var directionalLight = new THREE.DirectionalLight(0xffffff, 0.7);
        directionalLight.position.set(-20, 40, 60);
        scene.add(directionalLight);
		
		// 定义 gui 控制参数
		guiParams = new function() {
			this.switchCamera = function () {
				if (camera instanceof THREE.PerspectiveCamera) {
					camera = new THREE.OrthographicCamera(window.innerWidth / -16, window.innerHeight / 16, 
						window.innerHeight / 16, window.innerWidth / -16, 
						-200, 500);
					guiParams.perspective = "Orthographic";
				} else {
					camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
					guiParams.perspective = "Perspective";
				}
				
				var target = scene.position.clone();
				controls = new THREE.OrbitControls(camera, render.domElement);
				target = target;
				camera.position.set(120, 60, 180);
				camera.lookAt(target);
			}
			
			this.perspective = "Perspective";
		}
		
		// 定义 gui 并绑定参数
		gui = new dat.GUI();
		gui.add(guiParams, 'switchCamera');
		gui.add(guiParams, 'perspective').listen();
		
		renderScene();
    });
	
	/** 初始化 stats 统计对象 */
	function initStats() {
		stats = new Stats();
		stats.setMode(0); // 0 为监测 FPS;1 为监测渲染时间
		$('#Stats-output').append(stats.domElement);
		return stats;
	}
	
	/** 渲染场景 */
	function renderScene() {
		stats.update();
		centerSphere.position.set(controls.target.x, controls.target.y, controls.target.z);
		requestAnimationFrame(renderScene);
		render.render(scene, camera);
	}
	
	/** 当浏览器窗口大小变化时触发 */
	function onWindowResize() {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		render.setSize(window.innerWidth, window.innerHeight);
	}

</script>
</body>
</html>
通过浏览器观察时,默认使用的相机叫透视相机,这是一种最自然的相机。正如你所看到的那样,离相机越远的方块被渲染得越小。通过右上角的 switchCamera 工具,我们可以来在 Three.js 支持的两种相机中回切换。Three.js 中的另一种相机叫正投影相机,在这种相机下,场景中所有的方块渲染出来的尺寸看起来都一样大,对象和相机之间的距离不会影响物体的渲染结果。这种相机通常用在二维游戏或 2.5D 地图中。
    我们先来看看透视相机 PerspectiveCamera,它的常用参数如下表所示:

参数描述
fov (视野)fov 表示视野(field of view)。这是从相机位置能够看到的部分场景。例如,人类有差不多180°的视野;而一些鸟类拥有差不多完整的360°的视野;
但是由于计算机显示器不能完全显示我们所看到的景象,所以一般会选择较小的区域。多数游戏会选择60°到90°左右的视野。推荐默认值:45°
aspect (宽高比)这是渲染结果输出区的横向宽度与纵向高度的比值。我们的例子中使用了整个窗口作为输出界面。推荐默认值:window.innerWidth / window.innerHeight
near (近面)near 属性定义的是从距离相机多近的地方开始渲染场景。一般情况下我们会为这个属性设置一个很小的值,从而可以渲染从相机位置可以
看到的几乎所有的物体。推荐默认值:0.1
far (远面)far 属性定义的是相机可以从它所处的位置看多远。如果我们把这个属性设置得太低,那么场景中的一部分可能不会被渲染;如果太高,在某些情况
下又会影响渲染的效率。推荐默认值:1000
下图很好地展示了这些属性:


    接下来我们看看正投影相机 OrthographicCamera,它的常用参数如下表所示:

参数描述
left (左边界)这个属性是可视范围的左平面。可以把它当做是可渲染部分的左侧面边界。如果把它设为 -100,那么就不会看到任何比这个左侧面更远的对象
right (右边界)跟 left 属性同理
top (上边界)跟 left 属性同理
bottom (下边界)跟 left 属性同理
near (近面)基于相机所在的位置,从这一点开始渲染场景
far (远面)基于相机所在的位置,场景一直渲染到这一点
下图很好地展示了这些属性:


    一般情况下,在没有明确指出相机的目标时,相机会指向场景的中心,用坐标表示就是 position(0, 0, 0)。但我们也可以轻松改变相机所看到的目标位置,即通过执行 camera.lookAt(x, y, z); 代码来达到目的。我们的示例中则使用了另一种写法,即:camera.lookAt(new THREE.Vector3(x, y, z)); 同样可以实现相同的目的。另外,我们还在场景中央添加了一个球体,来始终指向相机的目标。

未完待续···

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值