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

时间:2017-03-21 04:57:26

标签: c# c++ 3d game-engine trigonometry

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

现在我拥有我需要的一切(基于地图的坐标系,3D坐标系,多线程纹理引擎,多摄像机视角功能,块级碰撞/命中检测,弹丸和简单粒子引擎),糟糕的物理等等。)

我构建了所有内容并将旋转数学保持在最低限度,因为我一直在尝试学习触发器(我知道你会说什么,但保留给自己,我是一个优秀的程序员,不是数学家;哈哈)....

然而......我只是无法把它弄好,经过几天后它让我疯了。我一直在研究,阅读和编​​码,我无法理解。

这是我当前的旋转功能,它在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

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

enter image description here

我不在乎编程语言的反应是什么,我很流利,但我很尴尬:(

我一直试图在没有帮助的情况下做到这一点,但是我被困住了,滚动,俯仰和偏航的计算通常不会在编程语法中提供,并且令人窒息地理解,这就是我正在做的全部原因这---学习。

1 个答案:

答案 0 :(得分:0)

如果您想要完整的3D旋转,则必须查看旋转矩阵

如果您正在使用3D引擎,则必须学习如何使用它。起初它可能有点令人印象深刻,但并不是那么困难。

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

使用矩阵,您可以尽可能地操纵对象: 规模 回转 翻译

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

对于你世界的每个物体,你将存储earch顶点的位置(绝对位置,基于物体原点),然后你将存储一个变换矩阵(比例,旋转和平移(=位置)世界上的对象)。最后,您将拥有一个相机矩阵,这将使您能够在相机的相反方向和位置移动世界,使其看起来像相机正在移动。

所以:

让我们说我们的目标只是一个点。

对象:

•顶点[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分,第一个是它的位置,另一个是“看”点。

用它可以计算出这些值:

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),并且最接近它的矩阵是第一个应用于它的矩阵,所以这里我们首先对点应用Scale,然后是Rotation,然后是Translation,最后是Camera定位。

祝你好运。