2

[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 四边形也仍然被渲染,就好像相机在它们的正上方一样,当相机降低时它们应该以增加的视角渲染。我会错过什么?

4

0 回答 0