【DXライブラリ】カメラを操作する、回転させる

DXライブラリでカメラを操作、回転させる方法について説明しています。プレイヤーを中心にカメラが回転するのを実装します。

カメラ操作(回転)の基本

3Dゲームでカメラを操作(回転)できる場合、ある点(基本はプレイヤー)を軸にカメラ座標を回転させるのが基本。プレイヤーを中心とした半径Rの球面上をカメラが移動するイメージ。

DXライブラリにおける3D座標空間での軸は以下の通り。Z軸正方向が奥行き。

DXライブラリ本家にカメラ操作(回転)のサンプルコードがあり、それを参考にすると流れはこんな感じ。

  1. Z軸方向にカメラからプレイヤーの距離分伸ばしたベクトルを作成
  2. そのベクトルを垂直方向に回転(X軸回転)させる
  3. さらに水平方向に回転(Y軸回転)させる
  4. 注視点座標を足してカメラの座標を決定する
  5. カメラの座標などを更新する

Unityなどのゲームエンジンでもカメラを回転させるアルゴリズムは大体同じ。

余談だがベクトルの回転は行列の一次変換を用いて行っている。3D処理では行列を使うことが多々あるのできちんと知りたい人は勉強しておくと吉。行列は昔高校の数学Cにあったので調べると色々ヒットするはず。

サンプルコード

さてカメラ操作(回転)の実装。今回はプレイヤーの座標が必要なので前回作成した Player.cpp/h にプレイヤーの座標を渡す関数を追加。

Player.h

//以下の関数を追加
void Player_GetPosition(VECTOR* target);

Player.cpp

//以下の関数を追加
//プレイヤーの座標を渡す
void Player_GetPosition(VECTOR* target) {
	*target = player.Position;
}

続いて Camera.cpp に以下のコードを以下のようにする。

Camera.cpp

#include "DxLib.h"
#include "Input.h"
#include "Camera.h"
#include "Player.h"
#include <math.h>

const static float CAMERA_ANGLE_SPEED = 0.05f; //カメラの旋回速度
const static float CAMERA_PLAYER_LENGTH = 3.8f; //カメラとプレイヤーの距離
const static float CAMERA_PLAYER_TARGET_HEIGHT = 1.0f; //プレイヤー座標からどれだけ高い位置を注視点とするか

//カメラ構造体
typedef struct {
	VECTOR Eye; //カメラの座標
	VECTOR Target; //カメラの注視点
	float AngleH; //水平角度
	float AngleV; //垂直角度
}camera_t;

camera_t camera;

//カメラ初期化
void Camera_Initialize() {
	//カメラの角度の初期化
	camera.AngleH = 0.0f;
	camera.AngleV = 0.0f;

	//奥行0.1~1000までをカメラの描画範囲とする
	SetCameraNearFar(0.1f, 1000.0f);

	//ライティング処理をOFF
	SetUseLighting(FALSE);
}

//カメラ情報更新
void Camera_Update() {
    //カメラの角度を計算
  //→キーor右スティック右の入力があれば
    if (Input_GetGamepad(XINPUT_THUMBR_RIGHT) > 0 || Input_GetKeyboard(KEY_INPUT_RIGHT) > 0) {
        camera.AngleH += CAMERA_ANGLE_SPEED;
        //-180度以上になったら角度値が大きくなりすぎないように360度引く
        if (camera.AngleH > DX_PI_F) camera.AngleH -= DX_TWO_PI_F;
    }

    //←キーor右スティック左の入力があれば
    if (Input_GetGamepad(XINPUT_THUMBR_LEFT) > 0 || Input_GetKeyboard(KEY_INPUT_LEFT) > 0) {
        camera.AngleH -= CAMERA_ANGLE_SPEED;
        //-180度以下になったら角度値が大きくなりすぎないように360度足す
        if (camera.AngleH < -DX_PI_F) camera.AngleH += DX_TWO_PI_F;
    }

    //↑キーor右スティック上の入力があれば
    if (Input_GetGamepad(XINPUT_THUMBR_UP) > 0 || Input_GetKeyboard(KEY_INPUT_UP) > 0) {
        camera.AngleV += CAMERA_ANGLE_SPEED;
        //ある一定の角度以上にはならないようにする
        if (camera.AngleV > DX_PI_F / 2.0f - 0.6f) camera.AngleV = DX_PI_F / 2.0f - 0.6f;
    }

    //↓キーor右スティック下の入力があれば
    if (Input_GetGamepad(XINPUT_THUMBR_DOWN) > 0 || Input_GetKeyboard(KEY_INPUT_DOWN) > 0) {
        camera.AngleV -= CAMERA_ANGLE_SPEED;
        //ある一定の角度以下にはならないようにする
        if (camera.AngleV < -DX_PI_F / 2.0f + 0.6f) camera.AngleV = -DX_PI_F / 2.0f + 0.6f;
    }

    //プレイヤーの座標をゲット
    VECTOR tmp;
    Player_GetPosition(&tmp);

    //カメラの注視点はプレイヤー座標から規定値分高い座標
    camera.Target = VAdd(tmp, VGet(0.0f, CAMERA_PLAYER_TARGET_HEIGHT, 0.0f));

    //カメラの座標を決定する
    {
        MATRIX RotX, RotY; //カメラの回転に使う行列
        float Camera_Player_Length;

        //水平方向の回転はY軸回転
        RotY = MGetRotY(camera.AngleH);

        //垂直方法の回転はX軸回転
        RotX = MGetRotX(camera.AngleV);

        //カメラからプレイヤーまでの初期距離をセット
        Camera_Player_Length = CAMERA_PLAYER_LENGTH;

        // カメラの座標を算出
        // Z軸にカメラとプレイヤーとの距離分だけ伸びたベクトルを
        // 垂直方向回転( X軸回転 )させたあと水平方向回転( Y軸回転 )して更に
        // 注視点の座標を足したものがカメラの座標
        camera.Eye = VAdd(VTransform(VTransform(VGet(0.0f, 0.0f, -Camera_Player_Length), RotX), RotY), camera.Target);
    }

    //プレイヤーを見る角度にカメラを設置
    SetCameraPositionAndTarget_UpVecY(camera.Eye, camera.Target);
}

//描画
void Camera_Draw() {

}

//カメラ終了処理
void Camera_Finalize() {

}

今回はカメラの情報を扱う構造体 camera_t を追加。座標のほか、注視点および水平・垂直方向に回転させる際に必要となる角度を持たせる。またカメラの旋回速度などの値も定義しておく。

Camera_Update() にてキー入力に応じてカメラを回転させる。今回キーボードではカーソルキー、ゲームパッドでは右スティックで操作(回転)できるようにしている。垂直方向の角度について、一定の角度以上(以下)になると映像がひっくり返ってしまうので一定の角度以上(以下)にならないようにする。

カメラの角度からX・Y軸回転の行列を MGetRotX()・MGetRotY() で取得し、それを利用してカメラを回転させている。この際に使う VTransform() は行列を使ったベクトルの変換を行う関数。これらの関数の仕様は行列の知識が必要(昔は高校で習ったが今だと大学の線形代数で習う)のでここでは割愛。詳しくは本家ページにて。

一方 VAdd() はベクトルの加算に使う関数。これはよく使うのでここで説明。

宣言 VECTOR VAdd( VECTOR In1, VECTOR In2 )
概要 2つのベクトルを加算する
引数 VECTOR In1 加算されるベクトル
VECTOR In2 加算するベクトル
戻り値 In1とIn2を加算したVECTOR構造体

最後にSetCameraPositionAndTarget_UpVecY()でカメラの座標および注視点の座標を反映させるのを忘れずに

描画関数および終了処理関数は現状やることがないので空のまま。

コメント

タイトルとURLをコピーしました