关于本文
作者周林,知乎账号eeandrew,擅长Hybrid(HTML5,Android,ReactNative,Nativescript)混合开发和WEBGL技术开发,你可以在知乎上读到我的更多文章。
本文属于着色器的前置必备基础知识,请务必读完本文,才能进行下一阶段的学习。
一. 什么是着色器
简单说来,着色器决定了3D物体每个顶点最终在屏幕上渲染出来的位置和颜色。一个四四方方的正方体,你可以通过操作着色器,让他变成一个以假乱真的足球。一颗静止不动的爱心,你可以通过操作着色器,让它怦然心动起来。
功能越强大,开发越复杂。要玩转着色器,需要你有深厚的相关知识积累,本系列文章会带你从零开始,一步步进阶,最终变成WEBGL开发高手。
二. 矩阵变换
无论是二位还是三维空间,空间中点的变化都可以通过矩阵变换来实现。
常用的空间变换矩阵有
- 平移矩阵
- 缩放矩阵
- 旋转矩阵
1.平移矩阵
我们先考虑二维空间,如果需要让一个点沿x轴移动α距离,沿y轴移动β距离,我们可以这样做:
(x,y) --->(x+α,y+β)
在空间中,(x,y)其实代表了两种含义,一是空间中的点,二是方向。为了区分这两种情况,我们引入第三个变量w。
- w为1,(x,y,1)表示空间中的点
- w为0,(x,y,0)表示空间中的方向
(x,y,1) ---> (x+α,y+β,1)
GPU非常善于矩阵计算,因此,我们尝试将上面的元素矩阵化。
三维空间也可以使用类似的矩阵变换来实现位移的功能。
2.缩放矩阵
二维空间缩放原理
(x,y,1) ---> (x*α,y*β,1)
三维空间缩放原理
(x,y,z,1) ---> (x*α,y*β,z*γ,1)
矩阵化表示
3.旋转矩阵
旋转矩阵比较复杂,详情请参考这里
三. 模型(Model)、观察(View)和投影(Projection)矩阵
现在我们知道了,空间中的平移,缩放,旋转都可以通过矩阵变换来实现,接下来我们看看,矩阵变换如何应用在3D场景中。
在二维场景中,当物体各个顶点的位置确定后,它在屏幕上渲染出的结果也就确定了,不受其他任何因素影响。
然而在三维场景中,仅仅只有物体的顶点位置,还不能确定3D物体在屏幕上的渲染结果,还受到观察者的观察方向,和观察者的投影方式影响。
渲染结果 = 投影矩阵(Project) * 观察矩阵(View) * 模型矩阵(Model)
借用达芬奇的鸡蛋,我们来解释一下上面的概念:
- 模型矩阵
要把鸡蛋放入画布中,鸡蛋就必须遵从画布提供的坐标系。模型矩阵的作用就是把鸡蛋按照三维世界的坐标放置。我们有两个鸡蛋,一个放在画布的中心,一个往在离画布中心20像素的位置,WEBGL通过模型矩阵,把这两个鸡蛋的顶点进行位移,也即是:
模型矩阵 * 顶点位置
-
观察矩阵
仅仅有鸡蛋在三维世界中的坐标位置,还不能决定鸡蛋最后展示出的样子。观察者站在不同的角度,看到鸡蛋的样子可能完全不同,“横看成林侧成峰”,说的就是观察矩阵。
从鸡蛋的正上方看下去,鸡蛋是原型。
从鸡蛋的侧方看,鸡蛋又是不规则的椭圆。
所以我们有:
观察矩阵 * 模型矩阵 * 顶点位置
-
投影矩阵
有了模型矩阵,观察矩阵,我们还是不能确定鸡蛋在画布上的样子,我们还需要知道观察者离鸡蛋的距离以及观察者的视野范围。
两个同样大小的鸡蛋,由于离观察者距离不一样,在画布上最终呈现的鸡蛋大小也不一样
所以,我们有:
渲染结果 = 投影矩阵 * 观察矩阵 * 模型矩阵 * 顶点位置
gl_Position = projectionMatrix * modelViewMatrix * position
下一章,我们会讲解如何在WEBGL中画出上面提到的鸡蛋,敬请期待哦。