[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) カメラを一時的に 10 フィート後方に移動します (カメラはプレーヤーに緩やかに追従します)。
2) 3 点を計算します。1 つはプレイヤーの位置、つまりカメラのターゲットです。2 番目と 3 番目は移動したカメラの位置で、一方はプレーヤーを中心にわずかに時計回りに、もう一方はわずかに反時計回りに回転しています。
3) ステップ 2 の 3 点を使用して「上」ベクトルを計算します。
4) glu.LookAt を使用して、「カメラ」を適切に配置および方向付けします。
これは最初はうまく機能しているように見えますが、カメラを低くしたり、プレイヤーからの距離を長くしたりすると、物事がゆがみ始めます。カメラがズームインして表示され、風景の垂直スケールが拡大して表示されます。ランドスケープに平行にレンダリングされたスプライトの四角形も、カメラが真上にあるかのようにレンダリングされますが、カメラが下がるにつれて遠近感が増してレンダリングされる必要があります。何が欠けている可能性がありますか?