《WebGL入门指南》——第1章,第1.2节3D图形学——入门

  1. 云栖社区>
  2. 博客>
  3. 正文

《WebGL入门指南》——第1章,第1.2节3D图形学——入门

异步社区 2017-05-02 10:55:00 浏览744
展开阅读全文

本节书摘来自异步社区《WebGL入门指南》一书中的第1章,第1.2节WebGL——一个技术定义,作者 【美】Tony Parisi,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.2 3D图形学——入门
WebGL入门指南
“数学太难了啦!”

——芭比娃娃

也许有点不太好听,但是我必须得说,当我写3D图形的代码的时候,我会和芭比一样,有强烈的欲望想要用疯狂购物来放纵一下自己。因为3D图形编程通常很难,而且需要大量的数学知识。幸运的是,你不需要先成为数学大师再来写WebGL应用;我们会使用各种框架来代替我们去做其中大部分的复杂工作。尽管如此,理解底层的工作原理依然是非常重要的,因此下面我尝试在几页的篇幅内总结出整个3D图形学的基础知识。

1.2.1 3D坐标系
毫无疑问,3D绘制是建立在3D坐标系中的。任何一个熟悉2D笛卡儿坐标系(即绘图纸上的和HTML页面中的窗口坐标)的人,都会知道x坐标和y坐标。这种2D坐标可以用于定义页面中

标签的位置,或者指定在Canvas元素上进行2D绘制的位置。类似地,3D绘制是建立在3D坐标系统中的,除了x轴和y轴,新增加了一个坐标轴z,用于表示深度(即在离屏幕多深多远的地方绘制一个3D物体)。WebGL使用的坐标系可以查看图1-2,x轴方向是水平的从左到右,y轴的方向是垂直的从下到上,z轴的方向是从屏幕里面指向屏幕外面。


c28a9b1d927cea6a7d784d068f6a8dcda1d27194

图1-2 一个3D坐标系统(https://commons.wikimedia.org/wiki/File: 3D_coordinate_system.svg; 根据Creative Commons Attribution–Shar eAlike 3.0 Unported协议授权使用)

如果你已经非常熟悉2D坐标系,那么我想3D坐标系应该也不是很难理解。不过,从现在开始,事情要变得复杂一些了。

1.2.2 网格、多边形和顶点
有很多种方法来绘制3D图形,最常用的一种方法就是使用网格(Mesh)。网格是由一个或多个多边形组成的物体,各个顶点的坐标(x, y, z)定义了多边形在3D空间中的位置。网格中的多边形通常都是三角形(包含三个顶点)和四边形(包含四个顶点)。3D网格通常也被叫做模型(model)。

图1-3举例说明了一个3D网格。由黑线描边的四边形组成了这个网格,形成了一个脸部的形状(当然在最终的渲染图片中你不会看到这些黑线,这里只是为了解释网格的概念)。网格中的各个顶点的x, y, z的坐标分量只是用于定义形状;而网格表面的其他特性,如颜色和着色,都是由其余的属性来定义的,我们稍后会介绍。


06430dee5c67db4f63131822f43c484f9f3c510a

图1-3 一个3D网格 (http://upload.wikimedia.org/wikipedia/commons/8/88/Blender3D_UVTexTut1.png; 根据Creative Commons Attribution-Share Alike 3.0 Unported 协议授权使用)

1.2.3 材质、纹理和光源
网格表面的其他特性是由除了顶点位置(x, y, z)坐标之外的属性来定义的。网格表面可以简单到只有一种颜色,也可以复杂到是由多个不同的数据来共同决定的,比如说物体如何反射照射到表面上的光,物体的光泽度如何。网格表面同样也可以由一个或多个位图来决定,这就是我们通常所说的纹理映射(texture map),或者简称为纹理。纹理可以定义一个线性表面的外观(就好比把一张图片印在T恤衫上),另外,通过组合多张不同的纹理可以实现更加复杂的效果,例如凹凸效果和辉光效果。在大多数的图形系统中,网格表面的特性被统称为材质(material)。材质通常依赖于一个或多个光源(light)来呈现出外观效果,你也许已经猜到了,这就是我们如何让场景被照亮的。

图1-3中人的头部模型拥有一层紫色的材质,光源则是从模型的左侧照入(注意观察模型右侧脸颊的阴影)。

1.2.4 变换与矩阵
3D网格的形状是由顶点位置决定的。如果每次你想要移动模型都必须重新设定顶点位置,那将会是一件非常可怕和沉闷的事情,特别是当模型会持续穿过整个场景或做其他的动作的时候。因此,大部分的3D系统都支持变换(transform),这是一种不需要遍历每个顶点就可以移动模型的操作,不需要明确的逐个改变每个顶点的位置。变换包括对渲染模型的缩放、旋转、位移操作,而不必手动设定任何顶点的值。

变换通常是由矩阵来操作的,这是一个包含一组数值的数学模型,用于计算顶点的变换位置。如果你和我一样也是一个线性代数迷,那你应该很适应这个方法。如果不是,也别灰心。本书中使用的Three.js工具集可以让我们以黑箱模式操作矩阵:我们只需要告诉程序位移、旋转或者缩放,那么Three.js就会完成相应的操作。

1.2.5 相机、透视、视口和投影
每一个场景在渲染时都需要有一个视点,用户正是从视点的位置去观察场景。3D图形系统通常使用相机(camera)来定义用户与场景的相对位置和朝向,和我们真实世界中的相机一样,3D世界中的相机也具有类似于视野尺寸等属性。视野尺寸决定了透视关系(例如,远处的物体会看起来小一些)。相机的各个属性组合在一起将最终的3D场景渲染图像传送给2D视口(viewport),视口是由浏览器窗口或Canvas元素决定的。

相机永远是由两个矩阵来控制的。第一个矩阵定义了相机的位置和朝向,类似于用于进行变换操作的矩阵(见前文)。第二个矩阵比较特殊,它用于将相机空间的3D坐标转换为视口中的2D绘制空间中的坐标,这就是所谓的投影矩阵(projection matrix)。唉,我就知道讨厌的数学又来了!但大部分的WebGL框架都可以掩盖相机矩阵的底层细节,所以你要做的只是放置相机然后渲染即可。

图1-4很好地解释了相机、视口和投影的核心概念。在图的左下方,会看到一个眼睛的图标,代表相机的位置。红色的向量指向右侧(在图中被标记为x轴),代表相机的指向。蓝色的方块是3D场景中的物体。绿色和红色的矩形分别代表近裁剪面和远裁剪面。这两个平面决定了3D空间的子集的边界,也就是所谓的视锥体(view volume)或视平截头体(view frustum)。只有处于视平截头体内部的物体才可以被渲染到屏幕上。近裁剪面即视口,此平面就是我们最终在屏幕上看到的渲染的2D图像。


3d3ab29972d676c2b4ea7a337f44b489d5e15e15

图1-4 相机、视口和投影(http://obviam.net/index.php/3d-programming-with-android-projections- perspective/),经授权使用

相机是一个非常强大的工具,它决定了观察者和3D场景之间的关系,造成一种仿真感。在动画兵工厂中相机还是一件威力无比的武器,通过移动相机,你可以创造出神奇的荧幕效果,掌控用户的视觉体验。

1.2.6 着色器
这是在总结我们的3D图形学探索旅程之前的最后一个话题:着色器(shader)。为了在最终的图像中渲染模型,开发者必须精确地定义顶点、变换、材质、光源和相机之间的关系和交互。这就是由着色器来完成的。着色器(或称为“可编程着色器”)是一小段程序代码,其中包含了将模型投射到屏幕上的像素算法。着色器通常是由高等级的类C语言编写的,编译并运行在图形处理单元(GPU)中。大部分的现代电脑都配备了GPU,它是一种独立于CPU而专门用于渲染3D图形的处理器。

如果你仔细阅读了我之前提到的WebGL的定义,你也许会注意到我忽略了一部分内容。在科纳斯组织的官方网站上有这么一段话:

它使用OpenGL渲染语言GLSL ES……

在其他许多图形系统中,着色器是一个可选的或比较高级的特性;但与之不同的是,WebGL必须配备着色器。当你编写WebGL程序的时候,必须定义着色器,否则图形是不会显示在屏幕上的。WebGL的实现假定客户端电脑上配备有GPU。GPU可以处理顶点、纹理和其他一点东西;但它对材质、光源和变换却一无所知。把后者这些较高级的信息传递给GPU并最终把它们绘制到屏幕上的转换过程是由着色器来完成的,着色器是由开发者创建的。

所以你现在应该可以理解为什么我不一开始就讨论这个话题:我不想吓到你!着色器编程看起来很吓人,要用类C的语言来写,短时间内看是这样的,而且似乎花这么大的代价来将3D场景转换成最终的2D图像有点得不偿失。但是,请别害怕:许多流行的WebGL框架都内置了着色器,你只需要在代码中嵌入它们即可,这些内置的着色器可以满足你大部分的需求。


da83b57de68ce7ab20a0b9f0abad79fd1a29c318

我想我有必要声明一下,着色器带来的并不只是痛苦和煎熬。它的存在是很有必要的。着色器给予图形开发者完全的能力去操控每一个顶点和像素。这种能力可以创作出许多惊艳的视觉效果,从栩栩如生的CG效果(如图1-1所示的水母)到奇幻的卡通风格。但是强大的能力总是需要更强大的控制者。着色器是一个非常高端的话题,我不想让你在一开始就去攀登这座大山,直到我们已经充分理解了各种知识。这也正是为什么本书中所有的示例都使用了相当简单的着色器。

网友评论

登录后评论
0/500
评论
异步社区
+ 关注