第4章 三维空间的观察

1、了解两种基本的相机,透视相机和正投影相机

2、学习设置相机的不同参数,使场景显示不同的角度

3、为中级教程相机学习的深入打下基础

1、单反、双反都是相机<

在第一课里,我向您承诺过会对相机进行一些介绍,那么今天就是我履行诺言的时刻了。嘿,这一刻,有点激动,想到相机,大学时,一直想买一个单反,但是要1万多。工作后,当一个月的工资就能买一个单反时,内心充满了骄傲和自豪。所以,各位大大们,技术还是有用的,至少技术可以用来挣钱。

家有万贯,不如一技在手,加油。

对WebGL感兴趣,还不知道如何入门的大大们,看看本教程吧,我有信心看完本教程,特别是看完本教程的中级和高级篇,你应该对3D世界有一个自己的理解了。使用你做的绚丽的demo去找一份不错的工作,就应该没有问题。

那我们今天的主题是三维空间的观察。

1、 认识相机

在Threejs中相机的表示是THREE.Camera,它是相机的抽象基类,其子类有两种相机,分别是正投影相机THREE.OrthographicCamera和透视投影相机THREE.PerspectiveCamera。类图如下所示:

正投影相机有时候也叫正交投影摄像机,下图显示了正交摄像机投影和透视投影之间的差别。

2、 两者的区别

正投影和透视投影的区别是:透视投影有一个基本点,就是远处的物体比近处的物体小。我们看看著名的蒙娜丽莎的微笑就是典型的透视作品:

观察上图,对,没错是凤姐,主要不是叫您看它,是看它后面的树木,它是不是越来越小呢?对,这就是透视。

在工程建筑领域,正投影的例子很多,例如下面就是一个正投影的例子:

其特点是,远近高低比例都相同。

2 正投影相机

下面我们来介绍正投影相机,正投影的构造函数如下所示:

OrthographicCamera( left, right, top, bottom, near, far )

结合下面一个图,我们来看看,各个参数的意思。

介绍参数之前,先假定一个相机中心点,相机中心点可以想成是镜头的中心点。为了让大家能更容易的明白,我还是上一幅图吧,虽然这样会多花我一点时间。

图中红点就是我们假设的相机中心点。下面介绍一下构造函数的参数:

1、 left参数

left:左平面距离相机中心点的垂直距离。从图中可以看出,左平面是屏幕里面的那个平面。

2、 right参数

right:右平面距离相机中心点的垂直距离。从图中可以看出,右平面是屏幕稍微外面一点的那个平面。

3、 top参数

top:顶平面距离相机中心点的垂直距离。上图中的顶平面,是长方体头朝天的平面。

4、 bottom参数

bottom:底平面距离相机中心点的垂直距离。底平面是头朝地的平面。

5、near参数

near:近平面距离相机中心点的垂直距离。近平面是左边竖着的那个平面。

6、far参数

far:远平面距离相机中心点的垂直距离。远平面是右边竖着的那个平面。

有了这些参数和相机中心点,我们这里将相机的中心点又定义为相机的位置。通过这些参数,我们就能够在三维空间中唯一的确定上图的一个长方体。这个长方体也叫做视景体。

投影变换的目的就是定义一个视景体,使得视景体外多余的部分裁剪掉,最终图像只是视景体内的有关部分。

好了,看一个简单的例子:

var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );

scene.add( camera );

这个例子将浏览器窗口的宽度和高度作为了视景体的高度和宽度,相机正好在窗口的中心点上。这也是我们一般的设置方法,基本上为了方便,我们不会设置其他的值。

3、透视投影相机

透视投影是更符合我们视觉的投影,当你凝视一个女人时,就是因为远近高低各不同,女人才显得美丽,叫你看一个正投影的女人,估计连胸部都分不清,那么也没什么看头。

正因为,透视相机这么有魅力,所以在各种应用中运用非常广泛。

透视投影相机的构造函数如下所示:

PerspectiveCamera( fov, aspect, near, far )

我们来欣赏一幅图来看看这个函数的各个参数的意思:

先来明确这个图里涉及的概念。很多作者都认为这些概念很简单,不需要讲解,但是其实正是这些简单的东西,让很多初学者不明白。所以我一直想把这些简单的内容给讲清楚,以至于大家不在这个上面花费过多的时间,毕竟多的时间可以去挣钱,可以去陪女朋友,去做超级奶爸。

1、视角fov:这个最难理解,我的理解是,眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔,但是在180度的时候,往往物体很小,因为他在你的整个可视区域中的比例变小了。

2、近平面near:这个呢,表示你近处的裁面的距离。补充一下,也可以认为是眼睛距离近处的距离,假设为10米远,请不要设置为负值,Three.js就傻了,不知道怎么算了,

3、远平面far:这个呢,表示你远处的裁面,

4、纵横比aspect:实际窗口的纵横比,即宽度除以高度。这个值越大,说明你宽度越大,那么你可能看的是宽银幕电影了,如果这个值小于1,那么可能你看到的是如下的图中的LED屏幕了。

好了,看看下面一个简单的例子:

var camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );

scene.add( camera );

这个例子,很明了,就不在解释了,如有不明白,那请积极问我QQ吧。

4、实例

接下来,结合上面讲的两种相机,我们来看一个实例。这个实例首先使用正投影相机,然后在使用透视相机。先看看正投影相机的效果:

从图中可以看出,它基本上各个方向大小都相同,没有透视的效果。 我们来看看这一段代码,你可以从4-1.html下载本实例。

	<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Three框架</title>
		<script src="js/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>

明白了正投影的效果,我们现在将相机变成透视投影,只要更改上面关于相机的代码,就可以了,这里我们变成如下的代码:

camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);

效果如下:

这是视角为45度的情况,也就是眼睛睁开45度的情况。人类的正常视角是120度左右,但是要集中注意力看清楚东西,那么眼睛的视角在30-40度比较好。

这里我们分别展示视角设置为80度,100度,120度,160度和179度时,看到场景的情况:

80度视角效果图如下:

100度视角效果图如下:

120度视角效果图如下:

160度视角效果图如下:

179度视角效果图如下:

ok,我们已经将主要的视角大小给搞定了。反复对照上面的图,你会发现,视角越大,中间的物体越小,这是因为,视角越大,看到的场景越大,那么中间的物体相对于整个场景来说,就越小了。

你还可以试一试睁大您的眼睛,努力挣得最大,你发现周围的物体看不清了,这就是眼大不清的原理,你无法集中注意力,而且你视图看到你前面的所有物体,你的焦距无法固定,所以场景非常模糊。

虽然你也许感觉不了非常明显,你前面的某一件物体确实缩小了,但在计算机固定大小的屏幕上,显示更多更大的场景,毫无疑问,每一件物体显示是缩小了。

当到达179度的时候,three.js真的傻了,他已经完全不明白你要看什么了,他已经将你要看的场景设为无穷大了,所以每一件物体相对于无穷大来说,基本在屏幕中无法显示了。

ok,讲到这里,这基本是整个网络中讲得最清楚的关于摄像机的教程了。谢谢。刚看投票赞扬我一下吧。

如果通过学习,你觉得本教程不错,大家可以试着支持一下文中一些带**有隆重商业气息**的图片,你的查看等于送我一杯奶茶哦!感谢大家。希望你能看懂这句话,哈哈

5、补充视频

大家除了下载本课的视频外,还可以通过如下的地址看补充课程“相机的up、lookat、position几个向量之间的关系”,这节视频对理解相机的几个关键参数非常有意义。点击这里观看

6、扩展阅读 Babylon中的相机

最近问微软的Babylon.js的同学比较多,Babylon.js的相机相比Three.js更灵活。 有兴趣的同学,可以看一下Babylon.js的相机

给WebGL中文网团队的女程序员"小果妹妹"发一个鸡腿吧,微信扫一扫赞赏,感谢。

亲爱的读者,如果你觉得WebGL中文网的课程不错,您可以购买《WebGL中文网视频课程》 课程支持我们哦,购买后记得给我们好评哦!我们强烈建议您不要在iphone上的网易云课堂软件中购买,这样苹果会收取31%左右的服务费,虽然这是明码标价,我们也表示认可和理解,具体选择权在您自己了。

感谢大家的支持,下面是课程的截图之一

[1楼] ade1** 2016-06-27 23:44

请问老师,透视投影相机也是形成一个视景体,并且进行裁剪么?谢谢

WebGL中文网老师回答:

嗯,是的。将不在视景体中的物体裁剪掉,这样才能减少显卡的计算量。

[2楼] hong** 2016-07-22 10:51

讲的非常非常好。

WebGL中文网老师回答:

是吗,哪里,哪里。

[3楼] wzjs** 2016-08-23 14:58

真的讲的很好很好,很清楚

WebGL中文网老师回答:

因为我们知道大家哪些地方不懂啊。哈哈,另外,还有不清楚的同学,可以看补充视频哦。

[4楼] 9756** 2016-09-06 11:27

老师,请问一下:例子中var geometry = new THREE.CylinderGeometry( 70,100,200);

设置了3个参数,而api有6个参数,这个参数分别代表的是哪几个参数呢?

CylinderGeometry(radiusTopradiusBottomheightradiusSegmentsheightSegmentsopenEndedthetaStartthetaLength)。

WebGL中文网老师回答:

不明白position、up、lookat三个向量代表的意思,请看补充视频哦。10分钟即可明白。明白之后,可以购买我们的高级课程继续深入学习哦。

[5楼] ahlo** 2016-09-24 09:07

设置了3个参数,而api有6个参数,这个参数分别代表的是哪几个参数呢?

——前3个,可以不写的参数一定是后面几个,设置了缺省值的参数。


[6楼] shuh** 2016-11-25 17:08

CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded, thetaStart, thetaLength)。

radiusTop: 柱体顶部半径

radiusBottom:柱体底部半径

height:柱体高度

radiusSegments:圆周分段,数字越高柱体越圆滑

heightSegments:高度分段,与上类似

openEnded:是否显示顶盖和底板

theraStart, thetaLength:不明白,一种随时间的变化什么的

[7楼] hero** 2017-01-24 16:37

老师:下面这些属性是什么意思,好像没解释啊

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
});

WebGL中文网老师回答:

看一下补充视频的课程

[8楼] 勿忘初心** 2017-04-19 10:27

越看越有意思

WebGL中文网老师回答:

劳动被大家认可,非常开心

[9楼] Lezi** 2017-05-25 11:11

笔者是兰州人吧!看到了张掖路的万龙

WebGL中文网老师回答:

去过张掖地质公园,:)。你眼力真好。

[10楼] qius** 2017-09-28 18:31

cool

WebGL中文网老师回答:

cool,cool,cool。老师重要的话,帮你说三遍。

[11楼] 飞飞22** 2017-10-19 20:15

老师您好,新版本的库和旧版本的库改了哪一块?为什么引用旧版本的库就可以,新版本的就不行。

WebGL中文网老师回答:

很多同学会问新版本和旧版本的问题,但是这个问题并不能回答。原因是,我们无法阻止api的变化,api变化也是为了给大家提供更好更容易使用的api。一直以来,设计兼容性好的接口,都是开发者很头疼的问题。所以,你问我变化,我不可能把每个版本上百的变化都列举给你。即使列出90到91的100个变化,但是70到91的100个变化,谁来列呢。所以,我们的课程一直以来是交大家原理,如果学习了本课程,大家还不会自己看源码,了解api,举一反三,那么真的没有掌握真本事哦。

[12楼] 张明祖** 2017-11-15 15:20

老师您好,非常感谢老师能提供这么好的文档,在文档中发现一个错别字,最上面,家有万贯不如一技在手下面那段话中  应该是“找到一份不错的好工作”,您写成“一份不做的好工作了”,虽然无伤大雅,但是感觉改了就会更加完美了。

WebGL中文网老师回答:

感谢你的热心,错误已改。

[13楼] wuye** 2017-11-17 10:36

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

});

这个部分的camera.position是指相机放置的位置

camera.up是指相机已哪个方向为上方 根据右手坐标原理 可进行旋转模拟

camera.lookAt 是指相机看向哪个点

新版本的three.js的camera.lookAt的参数设置方式有些变化,需要把之前的那种参数设置形式改变成为camera.lookAt(x,y,z)。

[14楼] gosa** 2017-11-24 15:07

好通俗好易懂~~感谢~~

WebGL中文网老师回答:

一个人说本套课程易懂,是拖,问题是很多人都是课程易懂,那么是真的易懂了。有没有学了很久WebGL还没成为高手的同学,有,来这里看一下课程吧。

[15楼] Yiyu** 2018-03-13 13:42

老师您好,您注释的 这一段是做什么的呢?

camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 10, 1000 );

WebGL中文网老师回答:

这就是大名鼎鼎的正投影相机的定义代码,代码中现在使用的透视相机哦!

[16楼] lirc** 2018-04-09 15:51

正投影的时候改变fov的值图像没有变化啊

[17楼] lirc** 2018-04-09 15:53

正投影的时候是没办法改变fov的对么

[18楼] wesl** 2018-04-10 17:49

少了一句话理解的并不太顺利,正交相机所在的位置就像是一个坐标(x,y)的原点,所以,左侧为负值,下面的也为负值。开始我也没理解为啥会有负值。。。现在理解了

[19楼] Eval** 2018-06-13 11:50

老师你好,请问一下补充视频为什么访问不到呢?404..

WebGL中文网老师回答:

在vip课程中可以看到。感谢成为vip会员。hewebgl.com/paytip

[20楼] kuid** 2018-08-03 16:05

老师您好,新版的threeJs是不是不再支持cylinder圆柱体的绘制了?

WebGL中文网老师回答:

支持的,就是函数变了而已,原理没有变。

[21楼] xuli** 2018-08-08 15:13

你还可以试一试睁大您的眼睛,努力挣得最大,你发现周围的物体看不清了,这就是眼大不清的原理,你无法集中注意力,而且你视图看到你前面的所有物体,你的焦距无法固定,所以场景非常模糊。

---

这段话是有问题,fov越大,相机拍摄的东西越多,但是屏幕大小是固定的,因此呈现出来的图像会变小。

[22楼] llbu** 2018-08-13 14:24

补充视频打不开,只有我一个人遇到这个问题吗?

WebGL中文网老师回答:

免费视频已经移到网易云课堂,欢迎观看。https://study.163.com/course/courseMain.htm?courseId=1005166007&share=2&shareId=400000000417018

[23楼] 1229** 2018-09-13 08:11

老师你好,我想问一下可以实现用户对立体几何的任意切割吗?这个要学到哪个程度?

WebGL中文网老师回答:

可以的,这是计算机图形学的几何运算,你还需要学习更多的知识。加油。

[24楼] Grou** 2018-11-26 22:00

<head><title>挺棒!</title></head>
<body><p>看到蒙拉丽莎图的时候,下意识的回到主页看了一下四位老师的照片,发现都很帅,就放心了!</p></body>

[25楼] 1024** 2018-11-29 10:59

教程很好,但是讲解的时候能不能不要带入个人感情,教程就是教程,不是来听你个人感慨

[26楼] jiad** 2018-12-28 23:12

我反而很喜欢老师的个人感情体现在文字里,教学不应该是枯燥无味的,无形之中可以让学者有带入感。

[27楼] feng** 2019-04-15 10:55

原来“睁大你的眼睛看清楚”是错误的!

[28楼] zf_j** 2019-09-11 17:37

还可以做超级辣妈!

[29楼] Bill** 2020-07-09 09:50

刚注册账号。受教了, 3d技术近些年这么火, 不得不来学习。附带问一句:您是把女人都看透了?

[30楼] teng** 2022-10-26 09:31

http://www.hewebgl.com/video/2

补充视频看不了了

提问或评论

登陆后才可留言或提问哦:) 登陆 | 注册 登陆后请返回本课提问
用户名
密   码
验证码