学习3D图形引擎中使用的基本数学
目录
(您需要Visual Studio来编译项目。)
介绍
本文将通过删除GPU层抽象并仅使用CPU来帮助您了解3D引擎中使用的3D数学。
而且,为什么不呢,要制作一个基于体素(voxel)3D引擎。
体素(voxel)只是空间中的一个点,就像构成材料的原子一样,这是我自己的定义,对于其他引擎,体素(voxel)定义为像素体积,就像在Minecraft/Roblox中一样,但我不使用此定义。
使用代码
首先,我们需要先问几个问题:
- 什么是空间(space)?
- 什么是轴(axis)?
- 什么是维(dimension)?
- 什么是平面(plane)?
- 什么是三角函数(trigonometric functions)?
- 什么是向量(vector)?
- 什么是旋转矩阵(rotation matrix)?
- 什么是旋转(rotation)和平移(translation)?
现在让我们为这些问题提供答案:
space是由点定义的,数学上由构成空间尺寸的唯一dimensions中的若干axes定域(plane由2轴=2D空间形成)。
Trigonometric functions是sin(θ)和cos(θ)等函数,其中θ表示围绕轴的角度并在2D平面中绘制一个圆。
rotation matrix是由trigonometric functions组成的一组方程。
vector是空间中的方向(类似于GPS),是点通过rotation matrix转换(算术运算符)的结果。
该点由旋转矩阵驱动到空间中,以便到达trigo函数内部的角度所指定的方向。
1D space用一个方向上的单线/ axis表示:----------------------------
要在此轴上移动对象,公式为:
x'=Dot.x + x 向右移动
x'=Dot.x-x 向左移动
-3 -2 -1 0 +1 +2 +3
X--|---|---|---|---|---|---|--
translation在一行,1D空间中完成,因此我们可能在X-axis<font color="#007000" face=""Segoe UI",Arial,Sans-Serif">.</font>上有1 translation。
2D space只是1D space,另一条线在X-axis的90°方向上,Y代表它:
要在此2D space中添加一个对象,我们需要为该对象的每个点设置2个坐标,然后移动该对象,我们像以前一样在x-axis上对translate添加了一个对象。
但是我们也可以围绕2 axis的中心旋转对象,为此,添加是不够的,我们需要调用专门用于rotation计算的数学运算符。
rotation是在平面2D space内完成的,因此,我们有1个rotation可能围绕两个axis的中心。
这些数学运算符被称为三角函数:sin()和cos()占用两条线之间的角度:[中心,对象的点]和x-axis的cos() 和y-axis的sin()。
在视觉上,我们在一个点0°(x = 1,y = 0),我们用+90°(+逆时针的, -表示顺时针)rotation中心,结果是x = 0,y = 1。
找到这个结果的演算是:
x' = x.cos(90) - y.sin(90)
y' = x.sin(90) + y.cos(90)
从头开始检索该方程式非常容易,这就是我所做的,而且令人惊讶的是,我已经看到该方程式是Z旋转矩阵的线性形式。
这是我的操作方式:
- 我们有一个直径为8的2D XY圆。
- 我们设置1个点,旋转它,然后尝试检索其新位置的方程式,一旦我们对几个不同的XY组合进行运算,我们将找到最终方程式。
- 让我们从一个红点P(4,0)开始:
- 现在我们旋转+ 90°(θ)的这一点,并尝试找到其新位置的方程,在视觉上找到的结果为P(0, 4):
X = sin(θ) = 1 ❌
X = cos(θ) = 0 ✔
Y = cos(θ) = 0 ❌
Y = sin(θ) = 1 ❌✔
Y = 4 × sin(θ) = 4 ✔
- 因此,对于P(4, 0)和θ= 90,我们有:
X = cos(θ)
Y = 4 × sin(θ)
- 尝试对P(4, 0)的任何其他角度以及Y为零的不同X值(对此使用mathsisfun),您会发现相同的方程式,对于X为4x,但不会改变最终方程式:
X' = 4 × cos(θ) = X × cos(θ)
Y' = 4 × sin(θ) = X × sin(θ)
- 现在我们将红点设置为P(0, 4):
- 我们将此点旋转+ 90°,在视觉上结果为P(-4, 0):
X = cos(θ) = 0 ❌
X = sin(θ) = 1 ❌✔
X = 4 × -sin(θ) = -4 ✔
Y = sin(θ) = 1 ❌
Y = cos(θ) = 0 ✔
- 因此,对于P(0, 4)和θ= 90,我们有:
X = 4 × -sin(θ)
Y = cos(θ)
- 尝试使用P(0, 4)的任何其他角度以及X值为零的不同Y值,您会发现相同的方程式,其中Y的角度为4×,但不会改变最终方程式:
X = 4 × -sin(θ) = Y × -sin(θ)
Y = 4 × cos(θ) = Y × cos(θ)
- 现在让我们总结一下:
_____ ________________ ________________
| | | |
| | P(X, 0) | P(0, Y) |
|_____|________________|________________|
| | | |
| θ | X = X × cos(θ) | X = Y × -sin(θ)|
| | Y = X × sin(θ) | Y = Y × cos(θ)|
|_____|________________|________________|
如我们所见,不同的XY组合生成不同的方程式,因此让我们对设置为0以上的X和Y进行操作:
- 因此,我们将红点设置为P(2, 4×√3/2):
- 现在我们将这个点旋转+ 30°,在视觉上找到的结果是P(0, 4):
X = sin(θ) = 0.5 ❌
X = cos(θ) = √3/2 ❌
Y = sin(θ) = 0.5 ❌
Y = cos(θ) = √3/2 ❌
我们有一个问题,三角函数都不起作用,因此我们需要在仍然使用sin()和cos()的同时找到解决方案。
让我们回顾一下之前找到的等式:
_____ ________________ ________________
| | | |
| | P(X, 0) | P(0, Y) |
|_____|________________|________________|
| | | |
| θ | X = X × cos(θ) | X = Y × -sin(θ)|
| | Y = X × sin(θ) | Y = Y × cos(θ)|
|_____|________________|________________|
这些是我们拥有的奇特方程,如果我们有P(X, Y),它应该是两个方程的混合:
X' = X × cos(θ) X = Y × -sin(θ)
Y' = X × sin(θ) Y = Y × cos(θ)
X' = X × cos(θ) Y × -sin(θ)
Y' = X × sin(θ) Y × cos(θ)
让我们看看添加是否有效:
X' = X × cos(θ) + Y × -sin(θ)
X × cos(θ) - Y × sin(θ)
Y' = X × sin(θ) + Y × cos(θ)
X = 2 × cos(θ) - 4×√3/2 × sin(θ) = 0 ✔
Y = 2 × sin(θ) + 4×√3/2 × cos(θ) = 4 ✔
完美,此方程式有效,因此最后,XY平面上的最终方程式为:
X' = X × cos(θ) - Y × sin(θ)
Y' = X × sin(θ) + Y × cos(θ)
但是,让我们消除对P(X, 0)和P(0, Y)的疑问:
- 对于P(4, 0),我们应用+ 90°旋转,在视觉上找到的结果为P(0, 4):
X' = 4 × cos(θ) - 0 × sin(θ) = 0 ✔
Y' = 4 × sin(θ) + 0 × cos(θ) = 4 ✔
- 对于P(0, 4),我们应用+ 90°旋转,在视觉上找到的结果是P(-4, 0):
X' = 0 × cos(θ) - 4 × sin(θ) = -4 ✔
Y' = 0 × sin(θ) + 4 × cos(θ) = 0 ✔
很好,一切正常,您可以使用自己的XY和角度值测试此方程式,以验证其是否正常运行。
这个方程是还令人惊讶地(如前面所述)的只是线性形式Z旋转(XZ平面旋转矩阵) 矩阵,乘以点叫vector,其中Z是两者axis的中心)
Rotation matrix on z: Vector:
_______________ _______________ _______________ _______________
| | | | | |
| cos(θz) | -sin(θz) | 0 | | x |
|_______________|_______________|_______________| |_______________|
| | | | | |
| sin(θz) | cos(θz) | 0 | × | y |
|_______________|_______________|_______________| |_______________|
| | | | | |
| 0 | 0 | 1 | | z |
|_______________|_______________|_______________| |_______________|
3D space是2D space与另一个叫Z轴,并在XY计平面90°上。
可能的移动是translation(加法方程)和rotation(sin和cos)。
但现在rotations的次数是3,围绕Z,围绕X和围绕Y。
因为如前所述,旋转是在2D平面上进行的,但是现在我们混合使用3x 2D space/plane:
- X/Y,Y/Z和Z/X。
因此,我们需要收集所有rotation矩阵并使用它们。
X旋转矩阵(XY平面旋转矩阵)
_______________ _______________ _______________
| | | |
| 1 | 0 | 0 |
|_______________|_______________|_______________|
| | | |
| 0 | cos(θx) | -sin(θx) |
|_______________|_______________|_______________|
| | | |
| 0 | sin(θx) | cos(θx) |
|_______________|_______________|_______________|
Y旋转矩阵(YZ平面旋转矩阵)
_______________ _______________ _______________
| | | |
| cos(θy) | 0 | -sin(θy) |
|_______________|_______________|_______________|
| | | |
| 0 | 1 | 0 |
|_______________|_______________|_______________|
| | | |
| sin(θy) | 0 | cos(θy) |
|_______________|_______________|_______________|
Z旋转矩阵(XZ平面旋转矩阵)
_______________ _______________ _______________
| | | |
| cos(θz) | -sin(θz) | 0 |
|_______________|_______________|_______________|
| | | |
| sin(θz) | cos(θz) | 0 |
|_______________|_______________|_______________|
| | | |
| 0 | 0 | 1 |
|_______________|_______________|_______________|
但是我们有一个问题,如果这样做,我们将无法一起围绕XYZ axis旋转一个对象,它是一个axis 上的rotation ,其他角度设置为“零”,因为它们不在所选矩阵中。
为了解决这个问题,我们需要通过将XYZ矩阵相乘来形成1个单个矩阵(mul的顺序问题)。
XYZ旋转矩阵(XY YZ XZ平面旋转矩阵)
______________________________ ______________________________ ____________________
| | | |
| cos(θy) × cos(θz) | cos(θy) × -sin(θz) | -sin(θy) |
|______________________________|______________________________|____________________|
| | | |
| -sin(θx) × sin(θy) × cos(θz) | sin(θx) × sin(θy) × sin(θz) | -sin(θx) × cos(θy) |
| + cos(θx) × sin(θz) | + cos(θx) × cos(θz) | |
|______________________________|______________________________|____________________|
| | | |
| cos(θx) × sin(θy) × cos(θz) | cos(θx) × sin(θy) × -sin(θz) | cos(θx) × cos(θy) |
| + sin(θx) × sin(θz) | + sin(θx) × cos(θz) | |
|______________________________|______________________________|____________________|
现在,我们只需要将这个rotation matrix(基于对象的角度)乘以物体的vector点,就可以在XYZ axes周围对物体进行rotate。
Obj Vec: Rotation Matrix:
_____ ______________________________ ______________________________ ____________________
| | | | | |
| x | | cos(θy) × cos(θz) | cos(θy) × -sin(θz) | -sin(θy) |
|_____| |______________________________|______________________________|____________________|
| | | | | |
| y | × | -sin(θx) × sin(θy) × cos(θz) | sin(θx) × sin(θy) × sin(θz) | -sin(θx) × cos(θy) |
| | | + cos(θx) × sin(θz) | + cos(θx) × cos(θz) | |
|_____| |______________________________|______________________________|____________________|
| | | | | |
| z | | cos(θx) × sin(θy) × cos(θz) | cos(θx) × sin(θy) × -sin(θz) | cos(θx) × cos(θy) |
| | | + sin(θx) × sin(θz) | + sin(θx) × cos(θz) | |
|_____| |______________________________|______________________________|____________________|
现在快要完成了,我们需要创建一个摄像机以能够导航到场景中。
相机由3 vectors定义:Forward,Right 和Up:
X Y Z
Right/Left (1, 0, 0)
Up/Down (0, 1, 0)
Forward/Backward (0, 0,-1)
然后,将这3个vectors分别乘以rotation matrix(基于相机的角度),因为我们需要它们中的每一个都能够移动相机Forward/Backward/Right/Left/Up/Down。
并且,将结果添加到对象向量。
例如:如果按W,使用Forward vector
如果按S,使用-Forward vector
如果按D,使用Right vector
Object Vector: Forward Vector:
__________________ __________________
| | | |
| x | | x |
|__________________| |__________________|
| | | |
| y | + | y |
|__________________| |__________________|
| | | |
| z | | z |
|__________________| |__________________|
Object Vector: Forward Vector:
__________________ __________________
| | | |
| x | | x |
|__________________| |__________________|
| | | |
| y | - | y |
|__________________| |__________________|
| | | |
| z | | z |
|__________________| |__________________|
Object Vector: Right Vector:
__________________ __________________
| | | |
| x | | x |
|__________________| |__________________|
| | | |
| y | + | y |
|__________________| |__________________|
| | | |
| z | | z |
|__________________| |__________________|
最后,我们将另一个rotation matrix(基于相机的角度)与来自对象的每个vector点相乘,以便能够根据相机角度移动对象(通过鼠标移动进行修改)。
上一篇: 数据库大量数据导出导入
下一篇: 初尝微信小程序2-基本框架