OpenGL - 在Lookat点周围旋转相机而不使用GLU函数

时间:2017-10-02 18:18:58

标签: vb.net opengl math

背景

我认为我已经掌握了创建OpenGL环境的基础知识。我可以渲染简单的对象,可以处理照明等。我正在尝试创建一个测试环境,我可以像FPS游戏风格一样移动。我希望能够朝着我正在看的方向向前和向后“行走”。

我的其他方法如何完成

我已经开发了一个向前和向后的功能,但旋转相机时遇到了一些困难。我有一些似乎有用的变量。我有cam.lookat,这是我的相机看到的点,cam.position这是我的相机所在的点,距离是两者之间的计算(在我的情况下我保持不变)。

所以我可能会完全错误,但这是我到目前为止所做的:

我在初始加载时调用的setupviewport sub:

Private Sub SetupViewport()
    Dim w As Integer = GLcontrol1.Width
    Dim h As Integer = GLcontrol1.Height

    Dim perspective1 As Matrix4 = cam.GetViewMatrix() * Matrix4.CreatePerspectiveFieldOfView(1.3F, GLcontrol1.Width / CSng(GLcontrol1.Height), 0.1F, 2000.0F)

    GL.MatrixMode(MatrixMode.Projection)
    GL.LoadIdentity()
    GL.Ortho(0, w, h, 0, -1, 1)
    GL.LoadMatrix(perspective1)
    GL.MatrixMode(MatrixMode.Modelview)
    GL.LoadIdentity()
    GL.Viewport(0, 0, w, h)
    GL.Enable(EnableCap.DepthTest)
    GL.DepthFunc(DepthFunction.Less)

End Sub

以下是每帧更改调用的Paint事件:

Private Sub GlControl1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs)

    GL.Clear(ClearBufferMask.ColorBufferBit)
    GL.Clear(ClearBufferMask.DepthBufferBit)
    GL.DepthMask(True)
    GL.Enable(EnableCap.DepthTest)
    GL.ClearDepth(1.0F)

    GL.MatrixMode(MatrixMode.Modelview)
    GL.LoadIdentity()

    Dim lightColor0 As Single() = {light_intensity, light_intensity, light_intensity, 1.0F}
    Dim lightPos0 As Single() = {cam.Position.X, cam.Position.Y, cam.Position.Z, 1.0F}

    GL.Light(LightName.Light0, LightParameter.Diffuse, lightColor0)
    GL.Light(LightName.Light0, LightParameter.Position, lightPos0)
    GL.Enable(EnableCap.Light0)

    Dim mat_specular As Single() = {1.0F, 1.0F, 1.0F, 1.0F}
    Dim mat_shininess As Single() = {50.0F}

    GL.Material(MaterialFace.Front, MaterialParameter.Specular, mat_specular)
    GL.Material(MaterialFace.Front, MaterialParameter.Shininess, mat_shininess)

    draw_extras()

    GL.Flush()
    GLcontrol1.SwapBuffers()

End Sub

我构建“前进和后退”子的方式如下:

Private Sub move_forward_and_back(ByVal forward As Boolean, ByVal delta As Single)
    'change the distance between camera and lookat
    'distance = old distance
    Dim curdistance As Single = Sqrt((cam.Position.X - cam.lookat.X) ^ 2 + (cam.Position.Y - cam.lookat.Y) ^ 2 + (cam.Position.Z - cam.lookat.Z) ^ 2)
    'curdistance = distance
    Dim deltadistance As Single = 0.1
    Dim newdistance As Single = deltadistance

    'The formula to use for the new point is Xnew = +/-((X2-X1)/Dold)*Dnew+X2
    'This formula results with two possible points because of the +/-
    'Both points are calculated and then evaluated
    Dim newcamx As Single = 0
    Dim newcamy As Single = 0
    Dim newcamz As Single = 0

    Dim newlookatx As Single = 0
    Dim newlookaty As Single = 0
    Dim newlookatz As Single = 0

    Dim newx1 As Single = (((cam.Position.X - cam.lookat.X) / curdistance) * newdistance) + cam.Position.X
    Dim newy1 As Single = (((cam.Position.Y - cam.lookat.Y) / curdistance) * newdistance) + cam.Position.Y
    Dim newz1 As Single = (((cam.Position.Z - cam.lookat.Z) / curdistance) * newdistance) + cam.Position.Z
    Dim newdistance1 As Single = Math.Sqrt((newx1 - cam.lookat.X) ^ 2 + (newy1 - cam.lookat.Y) ^ 2 + (newz1 - cam.lookat.Z) ^ 2)

    Dim newx2 As Single = (-((cam.Position.X - cam.lookat.X) / curdistance) * newdistance) + cam.Position.X
    Dim newy2 As Single = (-((cam.Position.Y - cam.lookat.Y) / curdistance) * newdistance) + cam.Position.Y
    Dim newz2 As Single = (-((cam.Position.Z - cam.lookat.Z) / curdistance) * newdistance) + cam.Position.Z
    Dim newdistance2 As Single = Math.Sqrt((newx2 - cam.lookat.X) ^ 2 + (newy2 - cam.lookat.Y) ^ 2 + (newz2 - cam.lookat.Z) ^ 2)

    'The one with the greater distance is considered the one to use for "moving away"
    'The one with the less distance is considered the one to use for "moving towards"

    If forward = True Then 'use one with less distance
        If newdistance1 > newdistance2 Then
            newcamx = newx2
            newcamy = newy2
            newcamz = newz2
        Else
            newcamx = newx1
            newcamy = newy1
            newcamz = newz1
        End If
    Else 'use one with greater distance
        If newdistance1 < newdistance2 Then
            newcamx = newx2
            newcamy = newy2
            newcamz = newz2
        Else
            newcamx = newx1
            newcamy = newy1
            newcamz = newz1
        End If
    End If

    'newcamx, newcamy, and newcamz are calculated for where the camera needs to move to

    'need to move lookat the same distance in the same direction
    If forward = True Then
        newdistance = curdistance + delta
    Else
        newdistance = curdistance - delta
    End If

    newx1 = (((cam.Position.X - cam.lookat.X) / curdistance) * newdistance) + cam.Position.X
    newy1 = (((cam.Position.Y - cam.lookat.Y) / curdistance) * newdistance) + cam.Position.Y
    newz1 = (((cam.Position.Z - cam.lookat.Z) / curdistance) * newdistance) + cam.Position.Z
    newdistance1 = Math.Sqrt((newx1 - cam.lookat.X) ^ 2 + (newy1 - cam.lookat.Y) ^ 2 + (newz1 - cam.lookat.Z) ^ 2)

    newx2 = (-((cam.Position.X - cam.lookat.X) / curdistance) * newdistance) + cam.Position.X
    newy2 = (-((cam.Position.Y - cam.lookat.Y) / curdistance) * newdistance) + cam.Position.Y
    newz2 = (-((cam.Position.Z - cam.lookat.Z) / curdistance) * newdistance) + cam.Position.Z
    newdistance2 = Math.Sqrt((newx2 - cam.lookat.X) ^ 2 + (newy2 - cam.lookat.Y) ^ 2 + (newz2 - cam.lookat.Z) ^ 2)

    If forward = True Then 'we want the one that is smaller
        If newdistance1 < newdistance2 Then
            newlookatx = newx1
            newlookaty = newy1
            newlookatz = newz1
        Else
            newlookatx = newx2
            newlookaty = newy2
            newlookatz = newz2
        End If

    Else
        If newdistance1 < newdistance2 Then
            newlookatx = newx1
            newlookaty = newy1
            newlookatz = newz1
        Else
            newlookatx = newx2
            newlookaty = newy2
            newlookatz = newz2
        End If

    End If

    'now simply assign values

    cam.Position.X = newcamx
    cam.Position.Y = newcamy
    cam.Position.Z = newcamz

    cam.lookat.X = newlookatx
    cam.lookat.Y = newlookaty
    cam.lookat.Z = newlookatz

    newdistance = Sqrt((cam.Position.X - cam.lookat.X) ^ 2 + (cam.Position.Y - cam.lookat.Y) ^ 2 + (cam.Position.Z - cam.lookat.Z) ^ 2)

End Sub

我只是根据恒定的距离计算相机位置点并知道相机的外观。这是作为计算而不是矩阵来完成的,这有望成为良好的实践。

现在所有这些工作都很顺利,但我提供它作为我如何处理我的环境的背景

问题

我正在尝试基于两个角度创建旋转相机功能。它应该保持距离和cam.position恒定,同时只改变cam.lookat点。到目前为止我所拥有的:

Private Sub rotate_camera(ByVal deltaangle1 As Single, ByVal deltaangle2 As Single)

    Dim curdistance As Single = Sqrt((cam.Position.X - cam.lookat.X) ^ 2 + (cam.Position.Y - cam.lookat.Y) ^ 2 + (cam.Position.Z - cam.lookat.Z) ^ 2)

    angle1 += deltaangle1
    angle2 += deltaangle2

    If angle1 >= 360 Then
     angle1 = angle1 - 360
     End If
     If angle2 >= 360 Then
     angle2 = angle2 - 360
     End If
     If angle1 < 0 Then
     angle1 = angle1 + 360
     End If
     If angle2 < 0 Then
    angle2 = angle2 + 360
     End If

    deltax = distance * Sin(deltaangle1 * (PI / 180)) * Cos(deltaangle2 * (PI / 180))
    deltay = distance * Sin(deltaangle1 * (PI / 180)) * Sin(deltaangle2 * (PI / 180))
    deltaz = distance * Cos(deltaangle1 * (PI / 180))
    deltaz = Sqrt((distance ^ 2) - (deltax ^ 2) - (deltay) ^ 2) * zsign

    'now simply assign values

    cam.lookat.X = cam.lookat.X + deltax
    cam.lookat.Y = cam.lookat.Y + deltay
    cam.lookat.Z = cam.lookat.Z + deltaz

    'distance = Sqrt((cam.Position.X - cam.lookat.X) ^ 2 + (cam.Position.Y - cam.lookat.Y) ^ 2 + (cam.Position.Z - cam.lookat.Z) ^ 2)

End Sub

所以我有三个问题:

  1. 我的deltay总是积极的。 我的公式没有方向我如何在公式中包含delta是正面还是负面?
  2. 在类似的线条上,似乎有一个180度的反射点,旋转方向反转。我应该如何考虑这种反思?
  3. 在稍微不同的音符上,我的相机的正X轴似乎与负世界X轴一致。我该如何解决?如何在旋转相机的同时保持我的cam.position和cam.lookat?
  4. 我知道这里有很多东西要读,但我希望这些问题是基本的。我提供了足够的细节,因为如果我完全偏离左侧场地,我可以调整其他方法。

    每个问题更新并在下面回答

    所以感谢你们迄今为止提供的所有帮助!我认为我大多在那里。我仍然有这一行使用最终矩阵:

    Dim perspective1 As Matrix4 = cam.GetViewMatrix() * Matrix4.CreatePerspectiveFieldOfView(1.3F, GLcontrol1.Width / CSng(GLcontrol1.Height), 0.1F, 2000.0F)
    

    但我已经使用以下建议更改了cam.getviewmatrix函数:

    Public Function GetViewMatrix() As Matrix4
    Dim myforwardvector As Vector3
        Dim rotational_matrix_y As Matrix3
        Dim rotational_matrix_x As Matrix3
        Dim rotational_matrix_z As Matrix3
        Dim upvector As Vector3
    
    
        If invert_z = False Then
            upvector = Vector3.UnitZ
        Else
            upvector = -Vector3.UnitZ
        End If
    
        rotational_matrix_x.M11 = 1
        rotational_matrix_x.M12 = 0
        rotational_matrix_x.M13 = 0
        rotational_matrix_x.M21 = 0
        rotational_matrix_x.M22 = Cos(theida * (PI / 180))
        rotational_matrix_x.M23 = -Sin(theida * (PI / 180))
        rotational_matrix_x.M31 = 0
        rotational_matrix_x.M32 = Sin(theida * (PI / 180))
        rotational_matrix_x.M33 = Cos(theida * (PI / 180))
    
        rotational_matrix_y.M11 = Cos(theida * (PI / 180))
        rotational_matrix_y.M12 = 0
        rotational_matrix_y.M13 = Sin(theida * (PI / 180))
        rotational_matrix_y.M21 = 0
        rotational_matrix_y.M22 = 1
        rotational_matrix_y.M23 = 0
        rotational_matrix_y.M31 = -Sin(theida * (PI / 180))
        rotational_matrix_y.M32 = 0
        rotational_matrix_y.M33 = Cos(theida * (PI / 180))
    
        rotational_matrix_z.M11 = Cos(theida * (PI / 180))
        rotational_matrix_z.M12 = -Sin(theida * (PI / 180))
        rotational_matrix_z.M13 = 0
        rotational_matrix_z.M21 = Sin(theida * (PI / 180))
        rotational_matrix_z.M22 = Cos(theida * (PI / 180))
        rotational_matrix_z.M23 = 0
        rotational_matrix_z.M31 = 0
        rotational_matrix_z.M32 = 0
        rotational_matrix_z.M33 = 1
    
        Dim rotational_matrix As Matrix3
        rotational_matrix = Matrix3.Mult(Matrix3.Mult(rotational_matrix_x, rotational_matrix_y), rotational_matrix_z)
    
        myforwardvector = multiply_matrix3_by_vector3(rotational_matrix, myforwardvector)
    
        lookat = multiply_vector3_by_scalar(myforwardvector, distance)
        Return Matrix4.LookAt(Position, lookat, upvector)
    End Function
    

    当我更改theida时,环境的加载有效,但我的环境没有任何变化。我调用我的SetupViewPort刷新矩阵并像平常一样重新绘制它。我在矩阵创建中遗漏了什么?

    这是当前按住仅增加我的偏航的按钮时发生的事情(只是更改X矩阵)。请记住,一个球体位于(0,0,0):

    enter image description here

    基于第二个答案的改进

    My new ViewMatrix function is as follows:
    
        Dim view_matrix As Matrix4 = Matrix4.LookAt(Position, lookat, up_vector)
    
        'transform to x axis first
        view_matrix = view_matrix * Get_Transform_Matrix(-Position.X, 0, 0)
        'rotate around x axis
        view_matrix = view_matrix * Get_Rotational_Matrix("x", yaw)
        'trnsform back
        view_matrix = view_matrix * Get_Transform_Matrix(Position.X, 0, 0)
    
        'transform to y axis first
        view_matrix = view_matrix * Get_Transform_Matrix(0, -Position.Y, 0)
        'rotate around y axis
        view_matrix = view_matrix * Get_Rotational_Matrix("y", pitch)
        'trnsform back
        view_matrix = view_matrix * Get_Transform_Matrix(Position.Y, 0, 0)
    
        'transform to z axis first
        view_matrix = view_matrix * Get_Transform_Matrix(0, -Position.Z, 0)
        'rotate around z axis
        view_matrix = view_matrix * Get_Rotational_Matrix("z", roll)
        'trnsform back
        view_matrix = view_matrix * Get_Transform_Matrix(Position.Z, 0, 0)
    
    
        Return view_matrix
    

    我的Get_Rotational_Matrix函数,用于检索用于给定旋转的正确矩阵:

    Public Function Get_Rotational_Matrix(ByVal matrix_name As String, ByVal angle As Single) As OpenTK.Matrix4
        'yaw = x, pitch = y, z = roll
        Dim rotational_matrix_ As Matrix4
        Select Case matrix_name
            Case "x"
                rotational_matrix_.M11 = 1
                rotational_matrix_.M12 = 0
                rotational_matrix_.M13 = 0
                rotational_matrix_.M14 = 0
                rotational_matrix_.M21 = 0
                rotational_matrix_.M22 = Cos(angle * (PI / 180))
                rotational_matrix_.M23 = -Sin(angle * (PI / 180))
                rotational_matrix_.M24 = 0
                rotational_matrix_.M31 = 0
                rotational_matrix_.M32 = Sin(angle * (PI / 180))
                rotational_matrix_.M33 = Cos(angle * (PI / 180))
                rotational_matrix_.M34 = 0
                rotational_matrix_.M41 = 0
                rotational_matrix_.M42 = 0
                rotational_matrix_.M43 = 0
                rotational_matrix_.M44 = 1
            Case "y"
                rotational_matrix_.M11 = Cos(angle * (PI / 180))
                rotational_matrix_.M12 = 0
                rotational_matrix_.M13 = Sin(angle * (PI / 180))
                rotational_matrix_.M14 = 0
                rotational_matrix_.M21 = 0
                rotational_matrix_.M22 = 1
                rotational_matrix_.M23 = 0
                rotational_matrix_.M24 = 0
                rotational_matrix_.M31 = -Sin(angle * (PI / 180))
                rotational_matrix_.M32 = 0
                rotational_matrix_.M33 = Cos(angle * (PI / 180))
                rotational_matrix_.M34 = 0
                rotational_matrix_.M41 = 0
                rotational_matrix_.M42 = 0
                rotational_matrix_.M43 = 0
                rotational_matrix_.M44 = 1
            Case "z"
                rotational_matrix_.M11 = Cos(angle * (PI / 180))
                rotational_matrix_.M12 = -Sin(angle * (PI / 180))
                rotational_matrix_.M13 = 0
                rotational_matrix_.M14 = 0
                rotational_matrix_.M21 = Sin(angle * (PI / 180))
                rotational_matrix_.M22 = Cos(angle * (PI / 180))
                rotational_matrix_.M23 = 0
                rotational_matrix_.M24 = 0
                rotational_matrix_.M31 = 0
                rotational_matrix_.M32 = 0
                rotational_matrix_.M33 = 1
                rotational_matrix_.M34 = 0
                rotational_matrix_.M41 = 0
                rotational_matrix_.M42 = 0
                rotational_matrix_.M43 = 0
                rotational_matrix_.M44 = 1
        End Select
        '
        Return rotational_matrix_
    
    End Function
    

    这似乎很棒!最后一个问题,如何将旋转应用到up_vector以便我可以跟踪它?请注意我的新方法永远不会改变它。

2 个答案:

答案 0 :(得分:0)

我认为您应该有一个私人会员,您可以在其中存储您的前向媒介。指向相机前方的方向。在开始时,您应该在z方向上查看,例如它可以是myForwardvector = vec3(0,0,1)

您还应将距离存储到您瞄准的点。 所以lookAt的位置应该变成:

vec3 position = myForwardVector * radius;

现在,当您想根据输入,鼠标等旋转前向矢量时...

您可以使用spherical coordinates

enter image description here

其中theta是左/右(偏航)和Phi上/下(俯仰)旋转时的角度。卷不用于fps。

如果你想使用matrice,你可以从一个小例子开始,然后实现偏航运动。

这就是thoose matrices的样子:

enter image description here

使用中间的那个并用你的偏航角替换θ。

现在每次进行一次动作都会改变你的forwardVector:

myForwardVector = Rotationmatrice * myForwardVector;
myLookAtMatrice = glm::lookat(myCameraPos, myFowardVector * radius, upVector)

希望它有所帮助,

请注意,您将使用相同的方法更新upVector。

答案 1 :(得分:0)

@DraykoonD答案很好。但似乎你对几何学有点困惑。所以,这里有一些解释:

如果您的物品无法移动,您只需要步骤:相机和投影。

摄像机

转换相机意味着翻译和/或旋转它。这两种运动通常都是由一个唯一的矩阵表示,通常称为“#34; lookAt&#34;矩阵。
如果使用矩阵,那么C= R*T就是操作(lookAt C = Rotation * Translation,按此顺序,而不是T * R)

<强>翻译
虽然T非常简单,但您可能希望用自己的代码替换矩阵运算。类似的东西:

camera.x = camera.x + deltaX
camera.y = camera.x + deltaY
camera.z = camera.x + deltaZ

请注意,deltas不是必需的,因为用户可能会立刻在1/2/3轴上移动。

如果您想要在当前方向(目标方向)上移动相机stepSize,而不是上述方法,那么在该方向上获取单位矢量并计算增量并使用他们和以前一样:

vx = target.x - camera.x
vy = target.y - camera.y
vz = target.x - camera.z
modulus = Sqrt(vx*vx + vy*vy + vz*vz)
' components of the unit vector
dx = vx / modulus
dy = vy / modulus
dz = vz / modulus
' stepSize is a signed value, forward or backwards
deltaX = dx * stepSize
deltaY = dy * stepSize
deltaZ = dz * stepSize

轮换
所有的拳头:事物围绕轴旋转一个角度,而不是围绕一个点。
再次阅读最后一句。这意味着你不能简单地给出两个角度并获得旋转,你需要发生两次旋转的顺序,因为如果你的结果不一样改变顺序。
现在再读一遍。这意味着每个旋转需要一个
人们感到困惑的是轮换需要一个起源。想想你用来绘制圆弧的指南针。
所以:轴,角度和原点。

确定。让我们解释FPS游戏中的旋转。我们将用于旋转相机位置的原点。再说一次,不要把这个称为“旋转点”#34;。

让我们说你的轴X +向右,Y +深入屏幕,Z +向上。这是一个权利处理系统:如果计算与轴对齐的两个单位向量的叉积,则得到第三个单位向量。交叉乘积作为矩阵乘法,不可交换;所以要注意顺序,否则你会在相反的方向上得到一个向量。
如果将此轴系统用作世界坐标系,则该轴系统易于理解。 左侧处理系统是相同的,但更改了一些符号,例如Z= Y x X,而不是Z= X x Y

如果您的第一次旋转超过Z轴,那么将Wikipedia Rotation中显示的Rz矩阵应用于当前X向量和Y向量,我们得到新的X&#39;,Y&#39;向量,Z&#39;与Z相同。如果首先相机目标为(0, d, 0),则将其后乘Rz以获得新目标(tx, ty, 0)
&#34;预&#34;或&#34;发布&#34;矩阵乘法取决于矩阵是列还是行mayor顺序。通常在OpenGL中使用许多图形API列mayor顺序,这与Wikipedia链接相同。

现在假设用户想要一个下行轮换。所需的轴是我们在Z轴旋转之前获得的X'。这是一个&#34;本地&#34;轴。如果我们应用Rx矩阵,我们会得到局部旋转。对。但我们需要的是一个全球性的&#34;方向,以便对象定位良好。
当矩阵内容闪耀时:只需应用R2= Rx*Rz而不是R2= Rx。如果您将R2应用于(0, d, 0),则会获得new2目标(t2x, t2y, t2z) 它很简单,如#34;堆叠&#34;转换:Cn= Cn-1 * ... *C5*C4*C3*C2*C1其中Ck是&#39; k&#39;的列 - 市长 - 顺序矩阵。转换(翻译或轮换或其他)。只要注意顺序;行 - 市长顺序反转它。

一旦你有了第一个&#34;相机矩阵&#34;以下矩阵只是堆叠的问题。

注意:翻译不能用3x3矩阵表示。但4x4确实如此。使用4x4矩阵可以堆叠任何变换。

现在用户想要再次旋转Z轴(左右)。嗯,让我看看......当我们进行旋转时,整个轴系统会发生变化。这意味着现在,在前两次旋转之后,Z-局部轴,其中&#34;向上摄像机&#34;向量是,与Z-global不同。但是用户确实需要Z-global轮换,而不是本地轮换(用户想要X-local但是Z-global) 我们之前已经看到每个Ck矩阵代表一个局部变换。我们现在需要的是在本地系统中表示的Z-全局轴。那就是:Zv= R2 * (0,0,1)
好的,但我只知道Rx,Ry,Rz矩阵,现在Z-global与我的本地轴没有相同。真正。我们需要围绕任何轴旋转矩阵。 This link显示了它。

好的。但是......第一个相机矩阵&#34;是什么?建? This lookAt link显示了它。所需的参数(摄像机位置,目标和摄像机)取决于您最初想要的参数&#34;参见&#34;。
如果你对矩阵的推导感到好奇,我告诉你,变换矩阵行是用旧轴向量表示的新轴向量。并且您可以使用交叉产品获取向量并对其进行标准化。

不可即可。而不是使用堆叠矩阵(我知道它们在由于数值问题导致的许多变换后退化)我想得到&#34; camera.position&#34;,&#34; camera.target&#34;和#34; camera.up&#34; (重要的是:所有这些都在全局坐标中)并且我自己使用lookAt矩阵,用于每次摄像机移动。然后你必须每次计算这三个向量。

翻译显示在这个答案的开头。您必须翻译camera.position和camera.target。 camera.up是一个向量,而不是一个点;因此,翻译一个向量是没有意义的。

对于旋转调用,我们使用相机的位置作为任何旋转的原点。这意味着在旋转目标变换之前,它将全局坐标转换为原点,然后旋转,然后撤消翻译,如下所示:

target.x = target.x - camera.position.x
target.y = target.y - camera.position.y
target.z = target.z - camera.position.z
target = RotateGeneric(axis, angle, target)
target.x = target.x + camera.position.x
target.y = target.y + camera.position.y
target.z = target.z + camera.position.z

我认为你有一个RotateGeneric函数很好,它使用了我之前写过的链接中的矩阵。

要旋转上摄像头矢量,您可以使用相同的功能(没有翻译,它是一个矢量,对吧?)

您正在对全球系统进行所有计算。 Z轴旋转很简单。但是X-local-axis,在任何时候......我们如何得到它?嗯,有两种选择:

  • 跟踪其当前(x,y,z)方向。换句话说,旋转 它也像你为摄像机做的那样。
  • 再次使用矩阵魔法。一切 轮换可以撤消。所需的矩阵是与之相反的 电流矩阵,IC = C -1 。所以如果你有X-local xv =(1,0,0) 并希望其组件在全局坐标中,然后xg = IC * xv。当然,您需要更新并存储当前的C矩阵。

如果您还围绕Y轴旋转,则过程与X轴相同。

投影

在每次移动时使用矩阵堆栈或lookAt矩阵,得到的是轴系统(如X和Y轴)与OpenGL设备轴系统对齐。
现在剩下两个工作:投影和处理Z轴方向。

正如你所怀疑的那样,矩阵又来了。

我不会在这里写关于正字法和透视矩阵表示法,这不是问题的主题。
只需指出那些矩阵在适当的位置有一个-1可以反转Z的符号,所以OpenGL左手设备系统很开心。那么,大多数人总是使用价值并不是绝对必要的;但如果设置了+1,那么您应该更改深度比较功能,以告诉OpenGL使用右手系统。
堆叠投影矩阵&#34;&#34;相机矩阵M = P * C以及所有。