1
0
mirror of https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git synced 2025-08-23 12:45:29 +08:00

More tweaks

This commit is contained in:
Meow J
2015-08-06 02:18:16 +08:00
parent 1eebbf8c06
commit c27ac565ce

View File

@@ -16,37 +16,37 @@
## 向量(Vector) ## 向量(Vector)
向量最最基本的定义就是一个方向。或者更正式的说,向量有一个方向(Direction)大小(Magnitude也叫做强度或长度)。你可以把向量想成一个藏宝图上的指示“向左走10步向北走3步然后向右走5步”这里的“左”是方向“10步”是向量的长度。藏宝图上的方向包含3个向量。向量可以在任意**维度**(Dimension)上但是我们通常只使用2至4维。如果一个向量有2个维度它表示一个平面的方向(想象一下2D的图像)当它有3个维度的时候它可以表达一个3D世界的方向。 向量最最基本的定义就是一个方向。或者更正式的说,向量有一个**方向(Direction)**和**大小(Magnitude也叫做强度或长度)**。你可以把向量想成一个藏宝图上的指示“向左走10步向北走3步然后向右走5步”“左”是方向“10步”是向量的长度。你可以发现,这个藏宝图的指示一共有3个向量。向量可以在任意**维度**(Dimension)上但是我们通常只使用2至4维。如果一个向量有2个维度它表示一个平面的方向(想象一下2D的图像)当它有3个维度的时候它可以表达一个3D世界的方向。
下面你会看到3个向量每个向量在图像中都用一个箭头(x, y)表示。我们在2D图片中展示这些向量因为这样子会更直观. 你仍然可以把这些2D向量当做z坐标为0的3D向量。由于向量表示的是方向起始于何处**并不会**改变它的值。下图我们可以看到向量![](../img/trans/v_red.png)和![](../img/trans/w_blue.png)是相等的,尽管他们的起始点不同: 下面你会看到3个向量每个向量在图像中都用一个箭头(x, y)表示。我们在2D图片中展示这些向量因为这样子会更直观. 你仍然可以把这些2D向量当做z坐标为0的3D向量。由于向量表示的是方向起始于何处**并不会**改变它的值。下图我们可以看到向量![](../img/trans/v_red.png)和![](../img/trans/w_blue.png)是相等的,尽管他们的起始点不同:
![](http://learnopengl.com/img/getting-started/vectors.png) ![](http://learnopengl.com/img/getting-started/vectors.png)
数学家喜欢把向量表示为一个字符头上像这样![](../img/trans/v_black.png)有个横。当用在公式中时它们通常是这样的: 数学家喜欢在字母上面加一横表示向量,比如说![](../img/trans/v_black.png)。当用在公式中时它们通常是这样的:
![](../img/trans/transformations1.png) ![](../img/trans/transformations1.png)
由于向量是一个方向,所以有些时候会很难形象地将它们用位置(Position)表示出来。我们通常设定这个方向的原点为(0,0,0),然后指向对应坐标的点,使其变为位置向量(Position Vector)来表示(你也可以把起点设置为其他的点,然后说:这个向量从这个点起始指向另一个点)。位置向量(3, 5)的在图像中起点是(0, 0),指向(3, 5)。我们可以使用向量在2D或3D空间中表示方向**与**位置. 由于向量是一个方向,所以有些时候会很难形象地将它们用位置(Position)表示出来。我们通常设定这个方向的原点为(0,0,0),然后指向对应坐标的点,使其变为**位置向量(Position Vector)**来表示(你也可以把起点设置为其他的点,然后说:这个向量从这个点起始指向另一个点)。位置向量(3, 5)的在图像中起点是(0, 0),指向(3, 5)。我们可以使用向量在2D或3D空间中表示方向**与**位置.
和普通数字一样,我们也可以用向量进行多种运算(其中一些你可能已经知道了)。 和普通数字一样,我们也可以用向量进行多种运算(其中一些你可能已经知道了)。
### 向量标量运算 ### 向量标量运算(Scalar Vector Operations)
**标量(Scalar)**只是一个数字(或者说是仅有一个分量的矢量)。当把一个向量加/减/乘/除一个标量,我们可以简单的把向量的每个分量分别进行该运算。对于加法来说会像这样: **标量(Scalar)**只是一个数字(或者说是仅有一个分量的矢量)。当把一个向量加/减/乘/除一个标量,我们可以简单的把向量的每个分量分别进行该运算。对于加法来说会像这样:
![](../img/trans/transformations2.png) ![](../img/trans/transformations2.png)
其中的+可以是+-,·或÷,其中·是乘号。注意-和÷运算时不能颠倒,颠倒的运算是没有定义的(标量-/÷矢量) 其中的+可以是+-,·或÷,其中·是乘号。注意-和÷运算时不能颠倒,因为颠倒的运算是没有定义的(标量-/÷矢量)
### 向量取反 ### 向量取反(Vector Negation)
对一个向量取反会将其方向逆转。一个指向东北的向量的相反数是指向西南的向量。我们在一个向量的每个分量前加负号从而实现取反(或者说用-1数乘该向量): 对一个向量取反会将其方向逆转。一个指向东北的向量取反后就指向西南方向了。我们在一个向量的每个分量前加负号就可以实现取反(或者说用-1数乘该向量):
![](../img/trans/transformations3.png) ![](../img/trans/transformations3.png)
### 向量加减 ### 向量加减
向量的加法可以被定义为是分量的相加,即将一个向量中的每一个分量加上另一个向量的对应分量: 向量的加法可以被定义为是**分量的(Component-wise)**相加,即将一个向量中的每一个分量加上另一个向量的对应分量:
![](../img/trans/transformations4.png) ![](../img/trans/transformations4.png)
@@ -64,7 +64,7 @@
### 长度(Length) ### 长度(Length)
我们使用勾股定理(Pythagoras theorem)来获取向量的长度(大小). 如果你把向量的x与y分量画出来该向量会形成一个以x与y分量为边的三角形: 我们使用**勾股定理(Pythagoras Theorem)**来获取向量的长度/大小. 如果你把向量的x与y分量画出来该向量会形成一个以x与y分量为边的三角形:
![](http://learnopengl.com/img/getting-started/vectors_triangle.png) ![](http://learnopengl.com/img/getting-started/vectors_triangle.png)
@@ -80,13 +80,13 @@
结果是4.47。 结果是4.47。
有一个特殊类型向量叫做**单位向量(Unit Vector)**。单位向量有一个特别的性质——它的长度是1。我们可以用任意向量的每个分量除以向量的长度得到单位向量![](../img/trans/n_unit.png) 有一个特殊类型向量叫做**单位向量(Unit Vector)**。单位向量有一个特别的性质——它的长度是1。我们可以用任意向量的每个分量除以向量的长度得到它的单位向量![](../img/trans/n_unit.png)
![](../img/trans/transformations8.png) ![](../img/trans/transformations8.png)
我们把这种方法叫做一个向量的**标准化(Normalizing)**。单位向量头上有一个小屋顶,特别是在我们只关心方向不关系长度的时候,它变得很有用(如果我们改变向量的长度,它的方向并不会改变)。 我们把这种方法叫做一个向量的**标准化(Normalizing)**。单位向量头上有一个^样子的记号,并且它会变得很有用,特别是在我们只关心方向不关系长度的时候(如果我们改变向量的长度,它的方向并不会改变)。
### 向量与向量相乘 ### 向量相乘(Vector-vector Multiplication)
两个向量相乘是一种很奇怪的情况。普通的乘法在向量上是没有定义的,因为它在视觉上是没有意义的,但是有两种特定情境,当需要乘法时我们可以从中选择:一个是**点乘(Dot Product)**,记作![](../img/trans/v.k.png),另一个是**叉乘(Cross Product)**,记作![](../img/trans/vxk.png)。 两个向量相乘是一种很奇怪的情况。普通的乘法在向量上是没有定义的,因为它在视觉上是没有意义的,但是有两种特定情境,当需要乘法时我们可以从中选择:一个是**点乘(Dot Product)**,记作![](../img/trans/v.k.png),另一个是**叉乘(Cross Product)**,记作![](../img/trans/vxk.png)。
@@ -100,7 +100,7 @@
![](../img/trans/transformations10.png) ![](../img/trans/transformations10.png)
现在点乘**只**和两个向量的角度有关。你也许记得当90度的余弦是00度的余弦是1。使用点乘可以很容易测试两个向量是否正交(Orthogonal)或平行(正交意味着两个向量互为直角)。你可能想要了解更多的关于正弦或余弦的知识,我推荐你看[可汗学院](https://www.khanacademy.org/math/trigonometry/basic-trigonometry/basic_trig_ratios/v/basic-trigonometry)的基础三角学视频。 现在点乘**只**和两个向量的角度有关。你也许记得当90度的余弦是00度的余弦是1。使用点乘可以很容易测试两个向量是否正交(Orthogonal)或平行(正交意味着两个向量互为**直角**)。你可能想要了解更多的关于正弦或余弦的知识,我推荐你看[可汗学院](https://www.khanacademy.org/math/trigonometry/basic-trigonometry/basic_trig_ratios/v/basic-trigonometry)的基础三角学视频。
!!! Important !!! Important
@@ -152,7 +152,7 @@
![](../img/trans/transformations17.png) ![](../img/trans/transformations17.png)
### 矩阵与标量相乘 ### 矩阵的数乘(Matrix-scalar Products)
和矩阵与标量的加减一样,矩阵与标量之间的乘法也是矩阵的每一个元素分别乘以该标量。下面的例子展示了乘法的过程: 和矩阵与标量的加减一样,矩阵与标量之间的乘法也是矩阵的每一个元素分别乘以该标量。下面的例子展示了乘法的过程:
@@ -162,7 +162,7 @@
到目前为止都还好,我们的例子都不复杂。不过矩阵与矩阵的乘法就不一样了。 到目前为止都还好,我们的例子都不复杂。不过矩阵与矩阵的乘法就不一样了。
### 矩阵与矩阵相乘 ### 矩阵相乘(Matrix-matrix Multiplication)
矩阵之间的乘法不见得有多复杂,但的确很难让人适应。矩阵乘法基本上意味着遵照规定好的法则进行相乘。当然,相乘还有一些限制: 矩阵之间的乘法不见得有多复杂,但的确很难让人适应。矩阵乘法基本上意味着遵照规定好的法则进行相乘。当然,相乘还有一些限制:
@@ -195,7 +195,7 @@
## 矩阵与向量相乘 ## 矩阵与向量相乘
到目前通过这些教程我们已经相当了解向量了。我们用向量来表示位置、颜色和纹理坐标。让我们进到兔子洞更深处向量基本上就是一个N×1矩阵N是向量分量的个数(也叫N维向量)。如果你仔细思考这个问题会很有意思。向量和矩阵一样都是一个数字序列但是它只有1列。所以这个新信息能如何帮助我们如果我们有一个M×N矩阵我们可以用这个矩阵乘以我们的N×1向量因为我们的矩阵的列数等于向量的行数所以它们就能相乘。 到目前,通过这些教程我们已经相当了解向量了。我们用向量来表示位置、颜色和纹理坐标。让我们进到兔子洞更深处:向量基本上就是一个**N×1**矩阵N是向量分量的个数(也叫**N维(N-dimensional)**向量)。如果你仔细思考这个问题会很有意思。向量和矩阵一样都是一个数字序列但是它只有1列。所以这个新信息能如何帮助我们如果我们有一个M×N矩阵我们可以用这个矩阵乘以我们的N×1向量因为我们的矩阵的列数等于向量的行数所以它们就能相乘。
但是为什么我们关心矩阵是否能够乘以一个向量有很多有意思的2D/3D变换本质上都是矩阵而矩阵与我们的向量相乘会变换我们的向量。假如你仍然有些困惑我们看一些例子你很快就能明白了。 但是为什么我们关心矩阵是否能够乘以一个向量有很多有意思的2D/3D变换本质上都是矩阵而矩阵与我们的向量相乘会变换我们的向量。假如你仍然有些困惑我们看一些例子你很快就能明白了。
@@ -229,7 +229,7 @@
### 平移(Translation) ### 平移(Translation)
平移是在原来向量的基础上加上另一个的向量从而获得一个在不同位置的新向量的过程,这样就基于平移向量**移动(Move)**了向量。我们已经讨论了向量加法,所以你应该不会陌生。 **平移(Translation)**是在原来向量的基础上加上另一个的向量从而获得一个在不同位置的新向量的过程,这样就基于平移向量**移动(Move)**了向量。我们已经讨论了向量加法,所以你应该不会陌生。
和缩放矩阵一样在4×4矩阵上有几个特别的位置用来执行特定的操作对于平移来说它们是第四列最上面的3个值。如果我们把缩放向量表示为![](../img/trans/t1t2t3.png)我们就能把平移矩阵定义为: 和缩放矩阵一样在4×4矩阵上有几个特别的位置用来执行特定的操作对于平移来说它们是第四列最上面的3个值。如果我们把缩放向量表示为![](../img/trans/t1t2t3.png)我们就能把平移矩阵定义为:
@@ -241,8 +241,9 @@
**齐次坐标(Homogeneous coordinates)** **齐次坐标(Homogeneous coordinates)**
向量的w分量也叫齐次坐标从齐次坐标得到3D坐标我们可以把x、y和z坐标除以w坐标。我们通常不会注意这个问题因为w分量通常是1.0。使用齐次坐标有几点好处它允许我们在3D向量上进行平移(如果没有w分量我们是不能平移向量的)下一章我们会用w值创建3D图像。 向量的w分量也叫**齐次坐标**。想要从齐次坐标得到3D坐标我们可以把x、y和z坐标除以w坐标。我们通常不会注意这个问题因为w分量通常是1.0。使用齐次坐标有几点好处它允许我们在3D向量上进行平移(如果没有w分量我们是不能平移向量的)下一章我们会用w值创建3D图像。
如果一个向量的齐次坐标是0这个坐标就是方向向量(Direction Vector)因为w坐标是0这个向量就不能平移(译注:这也就是我们说的不能平移一个方向)。
如果一个向量的齐次坐标是0这个坐标就是**方向向量(Direction Vector)**因为w坐标是0这个向量就不能平移(译注:这也就是我们说的不能平移一个方向)。
有了平移矩阵我们就可以在3个方向(x、y、z)上移动物体,它是我们的变换工具箱中非常有用的一个变换矩阵。 有了平移矩阵我们就可以在3个方向(x、y、z)上移动物体,它是我们的变换工具箱中非常有用的一个变换矩阵。
@@ -255,15 +256,17 @@
!!! Important !!! Important
大多数旋转函数需要用弧度制的角,但是角度制的角也可以很容易地转化为弧度制: 大多数旋转函数需要用弧度制的角,但是角度制的角也可以很容易地转化为弧度制:
弧度转角度:角度 = 弧度 * (180.0f / PI)
度转度:度 = 度 * (PI / 180.0f) -度转度:度 = 度 * (180.0f / PI)
- 角度转弧度:弧度 = 角度 * (PI / 180.0f)
PI约等于3.14159265359。 PI约等于3.14159265359。
转半圈会向右旋转360/2 = 180度向右旋转1/5圈表示向右旋转360/5 = 72度。这表明2D空间的向量![](../img/trans/v_red.png)是由![](../img/trans/k_green.png)向右旋转72度得到的 转半圈会向右旋转360/2 = 180度向右旋转1/5圈表示向右旋转360/5 = 72度。这表明2D空间的向量![](../img/trans/v_red.png)是由![](../img/trans/k_green.png)向右旋转72度得到的
![](http://learnopengl.com/img/getting-started/vectors_angle.png) ![](http://learnopengl.com/img/getting-started/vectors_angle.png)
在3D空间中旋转需要一个角**和**一个旋转轴(Rotation Axis)。物体会沿着给定的旋转轴旋转特定角度。如果你想要更形象化的描述可以试试向下看着一个特定的旋转轴同时将你的头部旋转一定角度。比如2D向量在3D空间中旋转时我们把旋转轴设为z轴(尝试想象这种情况)。 在3D空间中旋转需要一个角**和**一个**旋转轴(Rotation Axis)**。物体会沿着给定的旋转轴旋转特定角度。如果你想要更形象化的描述可以试试向下看着一个特定的旋转轴同时将你的头部旋转一定角度。比如2D向量在3D空间中旋转时我们把旋转轴设为z轴(尝试想象这种情况)。
使用三角学就能把一个向量变换为一个经过旋转特定角度的新向量。这通常是使用一系列正弦和余弦各种巧妙的组合得到的(一般简称sin和cos)。当然,讨论如何生成变换矩阵超出了这个教程的范围。 使用三角学就能把一个向量变换为一个经过旋转特定角度的新向量。这通常是使用一系列正弦和余弦各种巧妙的组合得到的(一般简称sin和cos)。当然,讨论如何生成变换矩阵超出了这个教程的范围。
@@ -285,7 +288,7 @@
![](../img/trans/transformations29.png) ![](../img/trans/transformations29.png)
在数学上讨论如何生成这样的矩阵仍然超出了本节内容。但是记住,即使这样一个矩阵也不能完全解决万向节死锁问题(尽管会极大地避免)。避免万向节死锁的真正解决方案是使用四元数(Quaternion),它不仅安全,而且计算更加友好。有关四元数会在后面的教程中讨论。 在数学上讨论如何生成这样的矩阵仍然超出了本节内容。但是记住,即使这样一个矩阵也不能完全解决万向节死锁问题(尽管会极大地避免)。避免万向节死锁的真正解决方案是使用**四元数(Quaternion)**,它不仅安全,而且计算更加友好。有关四元数会在后面的教程中讨论。
### 矩阵的组合 ### 矩阵的组合
@@ -379,7 +382,7 @@ GLuint transformLoc = glGetUniformLocation(ourShader.Program, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans)); glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
``` ```
我们首先请求uniform变量的地址然后用有`Matrix4fv`后缀的`glUniform`函数把矩阵数据发送给着色器。第一个参数你现在应该很熟悉了它是uniform的地址(Location)。第二个参数告诉OpenGL我们将要发送多少个矩阵目前是1。第三个参数询问我们我们是否希望对我们的矩阵进行置换(Transpose)也就是说交换我们矩阵的行和列。OpenGL开发者通常使用一种内部矩阵布局叫做以列为主顺序的(Column-major Ordering)布局。GLM已经是用以列为主顺序定义了它的矩阵所以并不需要置换矩阵我们填`GL_FALSE`、最后一个参数是实际的矩阵数据但是GLM并不是把它们的矩阵储存为OpenGL所希望的那种因此我们要先用GLM的自带的函数`value_ptr`来变换这些数据。 我们首先请求uniform变量的地址然后用有`Matrix4fv`后缀的`glUniform`函数把矩阵数据发送给着色器。第一个参数你现在应该很熟悉了它是uniform的地址(Location)。第二个参数告诉OpenGL我们将要发送多少个矩阵目前是1。第三个参数询问我们我们是否希望对我们的矩阵进行置换(Transpose)也就是说交换我们矩阵的行和列。OpenGL开发者通常使用一种内部矩阵布局叫做**以列为主顺序的(Column-major Ordering)**布局。GLM已经是用以列为主顺序定义了它的矩阵所以并不需要置换矩阵我们填`GL_FALSE`、最后一个参数是实际的矩阵数据但是GLM并不是把它们的矩阵储存为OpenGL所希望的那种因此我们要先用GLM的自带的函数`value_ptr`来变换这些数据。
我们创建了一个变换矩阵在顶点着色器中声明了一个uniform并把矩阵发送给了着色器着色器会变换我们的顶点坐标。最后的结果应该看起来像这样 我们创建了一个变换矩阵在顶点着色器中声明了一个uniform并把矩阵发送给了着色器着色器会变换我们的顶点坐标。最后的结果应该看起来像这样