在水平任意轴上旋转 3D 点

Rotating 3D points across a horizontal arbitrary axis

我有一个 3D 引擎,我正在开发所有图形的软件渲染,主要是为了更深入地了解事物的工作原理。

现在我拥有我需要的一切(基于地图的坐标系、3D 坐标系、多线程纹理引擎、多相机透视功能、块级 collision/hit 检测、射弹和简单的粒子引擎), 蹩脚的物理学, 等等)

我构建了所有内容并将旋转数学保持在最低限度,因为我一直在尝试同时学习三角(我知道你要说什么,但不要告诉你自己,我是一个很棒的人程序员,不是数学家;哈哈)...

但是......我就是做不对,几天后它让我抓狂。我一直在研究、阅读和编码,但我就是想不通。

这是我当前的旋转函数,它在 Y 轴上顺时针旋转节点。

Public Function RotatePoints(nodeCollection() As Point3d, centerPoint As Point, angleInDegrees As Double) As Point3d()
    For l = 0 To nodeCollection.Count - 1
        Dim angleInRadians As Double = angleInDegrees * (Math.PI / 180)
        Dim cosTheta As Double = Math.Cos(angleInRadians)
        Dim sinTheta As Double = Math.Sin(angleInRadians)

        Dim pointToRotate As New Point
        pointToRotate.X = nodeCollection(l).X
        pointToRotate.Y = nodeCollection(l).Y

        Dim key As New Point
        key.X = CInt(cosTheta * (pointToRotate.X - centerPoint.X) - sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X)
        key.Y = CInt(sinTheta * (pointToRotate.X - centerPoint.X) + cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)

        With nodeCollection(l)
            .X = key.X
            .Y = key.Y
        End With
    Next

    Return nodeCollection
End Function

我的目标是让对象围绕视图透视轴水平旋转。类似于您在游戏中环顾四周,世界围绕您左右移动。

我不在乎是什么编程语言响应,我能流利地使用很多语言,但我不擅长触发:(

我一直在尝试在没有帮助的情况下做到这一点,但我被卡住了,编程语法中通常不提供滚转、俯仰和偏航的计算,而且理解起来令人窒息,这就是我的全部原因我在做这个 --- 学习。

如果你想要完整的 3D 旋转,你将不得不查看 旋转矩阵

如果您正在使用 3D 引擎,则必须学习如何使用它。一开始可能有点印象深刻,但并不难。

https://en.wikipedia.org/wiki/Rotation_matrix https://en.wikipedia.org/wiki/Transformation_matrix

使用矩阵,您可以以各种可能的方式操纵对象: 规模 回转 翻译

您首先需要学习如何将矩阵(通常是 4x4,您可以搜索为什么会找到答案)与其他矩阵和向量相乘。

这样,对于你世界中的每个对象,你将存储每个顶点的位置(一个绝对位置,基于对象原点),然后你将存储一个转换矩阵(缩放、旋转和平移(=位置) 世界中的对象)。最后,您将拥有一个相机矩阵,这将使您能够在相机的相反方向和位置上移动世界,使相机看起来像是在移动。

所以:

假设我们的对象只是一个点。

对象:

• 顶点 [1, 2, -1, 1](x、y、z 和 w 通常等于 1)

• 缩放矩阵(假设在 y 上缩放 x2.0)

[1, 0, 0, 0]
[0, 2, 0, 0]
[0, 0, 1, 0]
[0, 0, 0, 1]

• 旋转矩阵(假设z上90°,我们看看wiki然后走)

c = cos(90°) and s = sin(90°)

[ c, s, 0, 0]   [ 0, 1, 0, 0]
[-s, c, 0, 0]   [-1, 0, 0, 0]
[ 0, 0, 1, 0] = [ 0, 0, 1, 0]
[ 0, 0, 0, 1]   [ 0, 0, 0, 1]

• 平移矩阵(假设为 -2、1、4)

 [1, 0, 0, -2]
 [0, 1, 0,  1]
 [0, 0, 1,  4]
 [0, 0, 0,  1]

现在我们只需要将所有的组合起来就得到一个新的点:

T * R * S

[1, 0, 0, -2]   [ 0, 1, 0, 0]   [1, 0, 0, 0]
[0, 1, 0,  1]   [-1, 0, 0, 0]   [0, 2, 0, 0]
[0, 0, 1,  4] * [ 0, 0, 1, 0] * [0, 0, 1, 0]
[0, 0, 0,  1]   [ 0, 0, 0, 1]   [0, 0, 0, 1]

=

[ 0, 1, 0,-2]   [1, 0, 0, 0]   [ 0, 2, 0,-2]
[-1, 0, 0, 1]   [0, 2, 0, 0]   [-1, 0, 0, 1]
[ 0, 0, 1, 4] * [0, 0, 1, 0] = [ 0, 0, 1, 4]
[ 0, 0, 0, 1]   [0, 0, 0, 1]   [ 0, 0, 0, 1]

这是我们的对象矩阵。

现在我们只需要将我们的顶点乘以它就可以得到它在世界中的位置:

[ 0, 2, 0,-2]   [ 1]   [2]
[-1, 0, 0, 1]   [ 2]   [0]
[ 0, 0, 1, 4] * [-1] = [3]
[ 0, 0, 0, 1]   [ 1]   [1]

给出 (2, 0, 3, 1) 点。


现在我们将计算相机矩阵,以将它的变换应用于世界。

您需要向量计算(如叉积或点积)

https://en.wikipedia.org/wiki/Cross_product

https://en.wikipedia.org/wiki/Dot_product

https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm

你的相机有 2 个点,第一个是它的位置,另一个是 "look at" 点。

有了它,您可以计算这些值:

zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)

[ xaxis.x        ,  yaxis.x        ,  zaxis.x        , 0]
[ xaxis.y        ,  yaxis.y        ,  zaxis.y        , 0]
[ xaxis.z        ,  yaxis.z        ,  zaxis.z        , 0]
[-dot(xaxis, eye), -dot(yaxis, eye), -dot(zaxis, eye), 1]

这里你有你的相机矩阵,你只需要将它应用到你的世界的每个顶点就大功告成了。

我不记得那个公式是否适用透视。

如果你什么都自己做,你还需要处理裁剪(当一个点在相机后面时,处理透视时数学就被打破了)。

还要记住矩阵相乘的顺序,请看:

Cam * Translation * Rotation * Scale * Point

点总是最后一个(矩阵数学,sry),最接近它的矩阵最先应用到它,所以这里我们首先在点上应用缩放,然后是旋转,然后是平移,最后是相机定位.

祝你好运。