[2012 年 9 月 23 日编辑] 从自上而下的角度想象 FPS 控制(扫射、转弯)。现在想象一下,当玩家转动时,整个屏幕都会旋转,所以他们总是面向显示器的顶部。现在想象一下,相对于他们的方向,投射这个的“相机”总是在玩家上方和后方 10 英尺处。这意味着相机以 45 度角俯视风景,随着玩家的转动而旋转。我试图掌握为此所需的代码而失去理智,这就是我迄今为止所得到的结果好坏参半:
Public Sub Mode_Perspective()
' Set OpenGL matrices to perspective mode.
' Set projection mode.
Gl.MatrixMode(Gl.PROJECTION)
Gl.LoadIdentity()
Glu.Perspective(45, sWidth / sHeight, Camera.Near, Camera.Far)
Gl.MatrixMode(Gl.MODELVIEW)
Gl.LoadIdentity()
Gl.Scalef(1, -1, 1 * ElevationScale)
End
Public Sub Update_Camera()
' Calculate translated camera position.
CameraXY = Calculate.TranslateInDirection(Camera.WorldX, Camera.WorldY, 10, Camera.Orientation + 90)
' Calculate up vector.
CameraTarget[0] = Client.PlayerData[Client.Number].WorldX_Current
CameraTarget[1] = Client.PlayerData[Client.Number].WorldY_Current
CameraTarget[2] = Client.PlayerData[Client.Number].WorldZ_Current
CameraLeft[0] = Calculate.RotateX(CameraXY[0], CameraXY[1], Camera.WorldX, Camera.WorldY, 1)
CameraLeft[1] = Calculate.RotateY(CameraXY[0], CameraXY[1], Camera.WorldX, Camera.WorldY, 1)
CameraLeft[2] = Camera.WorldZ
CameraRight[0] = Calculate.RotateX(CameraXY[0], CameraXY[1], Camera.WorldX, Camera.WorldY, -1)
CameraRight[1] = Calculate.RotateY(CameraXY[0], CameraXY[1], Camera.WorldX, Camera.WorldY, -1)
CameraRight[2] = Camera.WorldZ
UpVector = Calculate.Normal(CameraTarget, CameraLeft, CameraRight)
' Update OpenGL matrix.
Glu.LookAt(CameraXY[0], CameraXY[1], Camera.WorldZ, Client.PlayerData[Client.Number].WorldX_Current, Client.PlayerData[Client.Number].WorldY_Current, Client.PlayerData[Client.Number].WorldZ_Current, UpVector[0], UpVector[1], UpVector[2])
End
Public Function TranslateInDirection(StartX As Single, StartY As Single, Distance As Single, Direction As Single) As Single[]
' Translate specified coordinates by specified units at specified direction.
' General declarations.
Dim NewXY As New Single[2]
NewXY[0] = StartX + Distance * Cos(Rad(Direction))
NewXY[1] = StartY + Distance * Sin(Rad(Direction))
' Return new coordinates.
Return NewXY
End
Public Function RotateX(PWOX As Single, PWOY As Single, OriginX As Single, OriginY As Single, Orientation As Single) As Single
' Rotate specified point about specified point and return new X coordinate.
Return (OriginX + (Cos(Rad(Orientation)) * (PWOX - OriginX) - Sin(Rad(Orientation)) * (PWOY - OriginY)))
End
Public Function RotateY(PWOX As Single, PWOY As Single, OriginX As Single, OriginY As Single, Orientation As Single) As Single
' Rotate specified point about specified point and return new Y coordinate.
Return (OriginY + (Sin(Rad(Orientation)) * (PWOX - OriginX) + Cos(Rad(Orientation)) * (PWOY - OriginY)))
End
Public Function Normal(p1 As Single[], p2 As Single[], p3 As Single[]) As Single[]
' Calculate and return surface normal of specified triangle.
' General declarations.
Dim N As New Single[3]
Dim Magnitude As Single
' Calculate normal.
N[0] = (p2[1] - p1[1]) * (p3[2] - p1[2]) - (p2[2] - p1[2]) * (p3[1] - p1[1])
N[1] = (p2[2] - p1[2]) * (p3[0] - p1[0]) - (p2[0] - p1[0]) * (p3[2] - p1[2])
N[2] = ((p2[0] - p1[0]) * (p3[1] - p1[1]) - (p2[1] - p1[1]) * (p3[0] - p1[0])) * -1
' Normalize normal.
Magnitude = Sqr(N[0] ^ 2 + N[1] ^ 2 + N[2] ^ 2)
N[0] = N[0] / Magnitude
N[1] = N[1] / Magnitude
N[2] = N[2] / Magnitude
Return N
End
以下是我对 Update_Camera 过程所做工作的总结:
1) 暂时将相机移动到其身后十英尺(它松散地跟随玩家)。
2) 计算三个点。一个是玩家的位置,或相机目标。第二个和第三个是移动相机的位置,一个围绕玩家稍微顺时针旋转,另一个稍微逆时针旋转。
3) 使用步骤 2 中的三个点计算“向上”向量。
4) 使用 glu.LookAt 正确定位和定向“相机”。
起初这似乎效果很好,但是当我降低相机或增加它与玩家的距离时,事情开始扭曲。相机似乎放大了,风景的垂直比例似乎增加了。平行于景观渲染的 Sprite 四边形也仍然被渲染,就好像相机在它们的正上方一样,当相机降低时它们应该以增加的视角渲染。我会错过什么?