DXライブラリで3Dモデルの一部だけを表示または非表示にする方法について説明しています。半透明要素がある部分の描画対策などに。
3Dモデルの一部だけを表示/非表示にしたい
DXライブラリで3Dモデルを描画する場合 MV1DrawModel() を使用すればいいが、場合によっては3Dモデルの一部だけを表示あるいは非表示にしたいということがある。
よくある例は3Dモデルの一部に半透明部分(ガラス、水晶など)があり前後関係を考えて描画しないといけない場合。あとは装飾品のオン/オフとか。
こういった場合はパーツ毎に描画できる MV1DrawFrame() で3Dモデルの一部を表示/非表示にすることができる。
| 宣言 | int MV1DrawFrame(int MHandle, int FrameIndex) | |
| 概要 | モデルの指定のフレームを描画する | |
| 引数 | int MHandle | 描画するモデルのハンドル |
| int FrameIndex | 描画するフレームの番号 | |
| 戻り値 | 0 | 成功 |
| -1 | エラー発生 | |
DXライブラリでは3Dモデル内の階層構造のことをフレームと呼んでいる。フレームの構造は基本モデルファイルのものと同じ。
またフレームに割り当てられているマテリアル単位での表示/非表示もすることができる(DXライブラリではメッシュと呼ぶ)。こちらは MV1DrawMesh() を使って行う。
| 宣言 | int MV1DrawMesh(int MHandle, int MeshIndex) | |
| 概要 | モデルの指定のメッシュを描画する | |
| 引数 | int MHandle | 描画するモデルのハンドル |
| int FrameIndex | 描画するメッシュの番号 | |
| 戻り値 | 0 | 成功 |
| -1 | エラー発生 | |
サンプルコード
それでは実装。とりあえずプレイヤーモデルのフレームの総数もしくはメッシュ数を取得してfor文で全部描画するコード。
次はフレーム毎に描画するコード。
Player.cpp
//描写関数を以下のように変更
void Player_Draw() {
int FrameNum = 0;
// プレイヤーモデルの総フレーム数を取得
FrameNum = MV1GetFrameNum(player.ModelHandle);
// プレイヤーモデルをフレームごとに描画
for (int i = 0; i < FrameNum; i++) {
// ここにフレームごとに描画するかどうかの条件式を書いて判別
// 例として半透明要素があったら描画をスキップしている
if (MV1GetFrameSemiTransState(player.ModelHandle, i) == TRUE) continue;
MV1DrawFrame(player.ModelHandle, i);
}
}
まずプレイヤーモデルの総フレーム数を MV1GetFrameNum() で取得する。
| 宣言 | int MV1GetFrameNum(int MHandle) | |
| 概要 | モデルに含まれるフレームの数を取得する | |
| 引数 | int MHandle | 描画するモデルのハンドル |
| 戻り値 | -1以外 | モデルに含まれるフレーム数 |
| -1 | エラー発生 | |
あとはfor文で回して各フレームを描画する。
上の例ではfor文で総当たりしているが、フレーム名を検索してフレーム番号を取得して直接指定する方法もある。汎用性は低いが。
フレーム単位ではなくメッシュ単位で描画する場合はこちら。
//描写
void Player_Draw() {
int MeshNum = 0;
// プレイヤーモデルの総メッシュ数を取得
MeshNum = MV1GetMeshNum(player.ModelHandle);
// プレイヤーモデルをメッシュごとに描画
for (int i = 0; i < MeshNum; i++) {
// ここにメッシュごとに描画するかどうかの条件式を書いて判別
// 例として半透明要素があったら描画をスキップしている
//if (MV1GetMeshSemiTransState(player.ModelHandle, i) == TRUE) continue;
MV1DrawMesh(player.ModelHandle, i);
}
}
こちらも同様に MV1GetMeshNum() を使ってメッシュ数を取得し、for文で回して描画している。
| 宣言 | int MV1GetMeshNum(int MHandle) | |
| 概要 | モデルに含まれるメッシュの数を取得する | |
| 引数 | int MHandle | 描画するモデルのハンドル |
| 戻り値 | -1以外 | モデルに含まれるメッシュ数 |
| -1 | エラー発生 | |
どちらのコードでも半透明要素があるがどうかで描画をするかしないかの処理を入れいているが、実際に半透明要素のモデルを描画する場合は以下の手順を踏む。
- 半透明要素がないフレーム/メッシュを全部描画
- Zバッファを一度オフにする
- 半透明要素があるフレーム/メッシュをカメラから見て奥から描画
- Zバッファを再度オンにする
3の処理はZソートの機能が必要となるがDXライブラリにはZソート処理をする関数は残念ながらないため自作する必要がある。
「カメラからモデルへの方向ベクトル」の「カメラの向きベクトル」への正射影ベクトルの大きさ(これがカメラから見ての距離になる)を全フレーム/メッシュ計算し、その結果をソートして大きい順から描画していくのが一番単純?

コメント