DXライブラリを使って3Dモデルを表示させる方法について説明しています。mmdファイルもしくはDxLibModelViewerでmv1ファイルに変換した3Dモデルが必要です。
3Dモデル表示の基本
DXライブラリで3Dモデルを表示させる場合はおおまかに以下の流れになる。
- pmd(+vmd)、pmx(+vmd)、mv1ファイルのどれかを用意する
- MV1LoadModel() で3Dモデルをメモリに読み込む
- SetCameraNearFar() と SetCameraPositionAndTarget_UpVecY() でカメラの設定
- MV1DrawModel() で3Dモデル表示
- 終了処理の時にMV1DeleteModel()で3Dモデルをメモリから削除
DXライブラリで読み込める3Dモデルのファイル形式は以下の通り。
- x
- mqo
- pmd(+vmd)
- pmx(+vmd)
- mv1
xは昔のファイル形式で現在はまず使うことがない。mqoはメタセコイアで作成された3Dモデルのファイル形式。pmd・pmxはMMDで人によっては馴染みが深いと思う。
mv1はDXライブラリ専用のファイル形式でDXライブラリダウンロード時についてくる「DxLibModelViewer」から変換するとできるファイル形式。DxLibModelViewerでは上の5つのほかにfbxファイルが読み込める。
VRoid Studioで使われるvroid/vrmは未対応。使う場合は一度fbxに変換する必要がある。
3DモデルはMMDを使うか、fbxファイルをDxLibModelViewerでmv1に変換するのが基本。
また3Dモデルを使う際はスケールに注意。フリー素材をあちこちから取ってきてる場合はスケールが違う可能性があるのでBlenderなどで統一する。複数人で開発する場合もあらかじめスケールを決めておくこと。
サンプルコード
それではサンプルコードをペタリ。シーン管理実装の際に作った Game.cpp/h に3Dモデルを表示させるコードを書きつつプレイヤーやカメラの情報を扱うファイルも追加する。
今回使うモデルの見た目。VRoid StudioのプリセットにあるものをBlenderでスケールを「メートル法:0.01」にしてfbx化し、さらにmv1に変換したもの。

3Dモデルは.sinや.vcxprojファイルがある場所にフォルダを作ってそこに置いておく。コード内からは相対パスでファイルを指定する。ファイルは動かさないように。
まずは3Dモデルの情報を扱うために Player.cpp/h を追加する。
Player.h
#ifndef DEF_PLAYER_H #define DEF_PLAYER_H void Player_Initialize(); void Player_Update(); void Player_Draw(); void Player_Finalize(); #endif
Player.cpp
#include "DxLib.h"
#include "Input.h"
#include "Player.h"
//プレイヤーの構造体
typedef struct {
int ModelHandle; //モデルハンドル
VECTOR Position; //座標
}player_t;
player_t player;
//初期化
void Player_Initialize() {
//座標は原点
player.Position = VGet(0.0f, 0.0f, 0.0f);
//モデルの読み込み
player.ModelHandle = MV1LoadModel("(任意のファイルの相対パス)");
}
//更新
void Player_Update() {
}
//描写
void Player_Draw() {
MV1DrawModel(player.ModelHandle);
}
//終了処理
void Player_Finalize() {
MV1DeleteModel(player.ModelHandle);
}
Playerの構造体を作り、座標とモデルハンドルの情報を持たせる。本来なら向きとかアニメーション情報も必要だがそれは後で実装。
VECTORはDXライブラリが用意している3つの変数(x, y, z)を持つ構造体。MV1LoadModel()に読み込ませたい3Dモデルを相対パスで指定。
| 宣言 | int MV1LoadModel(char *FileName) | |
| 概要 | モデルの読み込み | |
| 引数 | char *FileName | ロードする3Dモデルのパス文字列のアドレス |
| 戻り値 | -1以外 | モデルのハンドル |
| -1 | エラー発生 | |
3Dモデルを読み込んだら座標の初期化を行う。直接値を入れてもいいが VGet() を使って座標を指定する。ベクトルを取得する関数だが座標決定としてよく使われる。
| 宣言 | VECTOR VGet( float x, float y, float z ) ; | |
| 概要 | ベクトルを取得する | |
| 引数 | float x | 取得するベクトルのX成分 |
| float y | 取得するベクトルのY成分 | |
| float z | 取得するベクトルのZ成分 | |
| 戻り値 | -1以外 | 正常 |
| -1 | エラー発生 | |
情報の更新を行う Player_Update() だが今回はやることがないので空のまま。Player_Draw() でプレイヤーのモデルの描画を MV1DrawModel() で行う。
| 宣言 | int Mv1DrawModel(int MHandle) | |
| 概要 | モデルを描画する | |
| 引数 | int MHandle | 描画するモデルのハンドル |
| 戻り値 | 0 | 成功 |
| -1 | エラー発生 | |
Player_Finalize() は終了処理。読み込んだデータを破棄する。
| 宣言 | int MV1DeleteModel(int MHandle) | |
| 概要 | モデルを削除する | |
| 引数 | int MHandle | 削除するモデルのハンドル |
| 戻り値 | 0 | 成功 |
| -1 | エラー発生 | |
次にカメラの情報を扱うためにCamera.cpp/hを追加する。
Camera.h
#ifndef DEF_CAMERA_H #define DEF_CAMERA_H void Camera_Initialize(); void Camera_Update(); void Camera_Draw(); void Camera_Finalize(); #endif
Camera.cpp
#include "DxLib.h"
#include "Input.h"
#include "Camera.h"
//カメラ初期化
void Camera_Initialize() {
//奥行0.1~1000までをカメラの描画範囲とする
SetCameraNearFar(0.1f, 1000.0f);
//プレイヤーを見る角度にカメラを設置
SetCameraPositionAndTarget_UpVecY(VGet(0.0f, 1.2f, -3.8f), VGet(0.0f, 1.0f, 0.0f));
//ライティング処理をOFF
SetUseLighting(FALSE);
}
//カメラ情報更新
void Camera_Update() {
}
//描画
void Camera_Draw() {
}
//カメラ終了処理
void Camera_Finalize() {
}
SetCameraNearFar() でカメラの描画範囲を、SetCameraPositionAndTarget_UpVecY() でカメラの位置を注視点を指定する。
| 宣言 | int SetCameraNearFar(float near, float Far) | |
| 概要 | カメラの手前クリップ・奥クリップの距離を設定する | |
| 引数 | float Near | 手前クリップの距離 |
| float Far | 奥クリップの距離 | |
| 戻り値 | 0 | 成功 |
| -1 | エラー発生 | |
| 宣言 | int SetCameraPositionAndTarget_UpVecY( VECTOR Position, VECTOR Target ) | |
| 概要 | カメラの視点と注視点を設定する | |
| 引数 | VECTOR Position | カメラの位置 |
| VECTOR Target | カメラの注視点 | |
| 戻り値 | 0 | 成功 |
| -1 | エラー発生 | |
なお今回はライティング処理をOFFにしている。ONだと現状下のように怖い見た目になってしまうのでOFFにしている。

最後にGame.cppに以下のコードを追加・変更する。
Game.cpp
//略
//初期化関数に以下のコードを追加する
void Game_Initialize() {
//プレイヤー情報更新
Player_Update();
//カメラ情報更新
Camera_Update();
}
//更新関数に以下のコードを追加する
void Game_Update() {
//プレイヤー情報初期化
Player_Initialize();
//カメラ情報初期化
Camera_Initialize();
//略
}
//描画関数に以下のコードを追加する
void Game_Draw() {
//略
//プレイヤーの描画
Player_Draw();
Camera_Draw();
}
//終了処理に以下のコードを追加
void Game_Finalize() {
Player_Finalize();
Camera_Finalize();
}
プレイヤーおよびカメラの初期化・更新・描画・終了処理を行う関数を追加。
実行した結果

このままモデルを真正面から見てるだけでは味気ないので次はカメラを操作(回転)できるようにする。

コメント