【C++】めちゃくちゃ強引にポリゴンを変動させる #1【3D】

はじめに
---
この記事では、ゲーム内でプレイヤーがポリゴンを操作してステージを地形変動できるようにつくります。

カメラやプレイヤーの基本的な動作、モデルとの衝突判定等は実装済の状態で始めます。
地形を変動させるのはいろいろ方法がありますが、ひとまず強引にモデルのポリゴンの見た目と衝突判定を変える手法でやってみようと思います。

言語は **C++** 、 **エンジンを使わず** にVisualStudioで、ライブラリは **DXライブラリ** で制作を進めていきます。

::: note warn
【記事中のコードについての注意事項】
分かりやすさのため実際のものから書き換えている部分や省略している部分があります。
:::

長くなってしまうので、後半部分は記事を分けています。

https://qiita.com/0reo07/items/e8723f946d1484c98788


目次
---
1. モデルの情報を参照し、変数に格納
1. ポリゴンとして表示
1. [ポリゴンを変動することができるようにする](https://qiita.com/0reo07/items/e8723f946d1484c98788)

# モデルの情報を参照し、変数に格納

元々のステージの描画はこう
モデルを読み込み、大きさを少し変えて描画しています。
![before_Stage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/b296aa89-c10b-ed38-217b-d70211012f08.png)
ちなみにプレイヤーモデルは[Mixsamo](https://www.mixamo.com/#/)から拝借しています。

このステージモデルの情報を参照して変数格納します。
これはＤＸライブラリの関数で[MV1GetReferenceMesh](https://dxlib.xsrv.jp/function/dxfunc_3d_model_3.html#R10N4)を使います。
データ取得前に参照用メッシュの構築([MV1SetupReferenceMesh](https://dxlib.xsrv.jp/function/dxfunc_3d_model_3.html#R10N1))を忘れずに。
リファレンス通りに進めていきます。

```c++:Stage.h
class Stage 
{
//~省略~
private:
    //モデル情報
    int modelId_;

	//格納先変数
	MV1_REF_POLYGONLIST polygonList_;
};
```

```c++:Stage.cpp
void Stage::Init(void)
{
	//~省略~

	// モデル全体の参照用メッシュを構築
	MV1SetupReferenceMesh(modelId_, -1, TRUE);

	// 参照用メッシュ情報の取得
	polygonList_ = MV1GetReferenceMesh(modelId_, -1, TRUE);
}

void Stage::Draw(void)
{
	// ポリゴンの数だけ繰り返し
	int i;
	for (i = 0; i < polygonList_.PolygonNum; i++)
	{
		// ポリゴンを形成する三頂点を使用してワイヤーフレームを描画する
        // 色は黄色
		DrawLine3D(
			polygonList_.Vertexs[polygonList_.Polygons[i].VIndex[0]].Position,
			polygonList_.Vertexs[polygonList_.Polygons[i].VIndex[1]].Position,
			GetColor(255, 255, 0));

		DrawLine3D(
			polygonList_.Vertexs[polygonList_.Polygons[i].VIndex[1]].Position,
			polygonList_.Vertexs[polygonList_.Polygons[i].VIndex[2]].Position,
			GetColor(255, 255, 0));

		DrawLine3D(
			polygonList_.Vertexs[polygonList_.Polygons[i].VIndex[2]].Position,
			polygonList_.Vertexs[polygonList_.Polygons[i].VIndex[0]].Position,
			GetColor(255, 255, 0));
	}
}
```


こうすると
![after_Stage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/566a527f-2472-63a6-657a-016ae3157322.png)
こうなります。

今はまだメッシュ表示になっていますが、うまくモデル情報の参照ができていそうです。

# ポリゴンとして表示

情報が取れたので、[DrawPolygon3D](https://dxlib.xsrv.jp/function/dxfunc_3d_draw.html#R14N7)を使ってポリゴン表示をし、元々のステージのように描画していきたいと思います。

### 変数を変換
ここで問題が出てきます。DrawPolygon3Dの引数は、
```c++
DrawPolygon3D( VERTEX3D *Vertex, int PolygonNum, int GrHandle, int TransFlag ) 
```
ですが、先ほどモデル情報を格納した変数は`MV1_REF_POLYGONLIST polygon_;`

この **MV1_REF_POLYGONLIST** もＤＸライブラリの構造体で
<details><summary>MV1_REF_POLYGONLIST</summary>

```c++
struct MV1_REF_POLYGONLIST
{
    // ポリゴンの数
    int    PolygonNum ;

    // 頂点の数
    int    VertexNum ;

    // 頂点座標の最小値
    VECTOR    MinPosition ;

    // 頂点座標の最大値
    VECTOR    MaxPosition ;

    // ポリゴン構造体の配列へのポインタ
    MV1_REF_POLYGON    *Polygons ;

    // 頂点構造体の配列へのポインタ
    MV1_REF_VERTEX    *Vertexs ;
} ;
```
</details>

になっており、さらに頂点情報を持っている構造体の **MV1_REF_VERTEX** は
<details><summary>MV1_REF_VERTEX</summary>

```c++
struct MV1_REF_VERTEX
{
    // 位置
    VECTOR    Position ;

    // 法線
    VECTOR    Normal ;

    // テクスチャ座標
    UV    TexCoord[ 2 ] ;

    // ディフューズカラー
    COLOR_U8    DiffuseColor ;

    // スペキュラカラー
    COLOR_U8    SpecularColor ;
} ;
```
</details>

になっています。
もう一度DrawPolygon3Dの引数を確認してみます。
```c++
DrawPolygon3D( VERTEX3D *Vertex, int PolygonNum, int GrHandle, int TransFlag ) 
```
第２～４引数はMV1_REF_POLYGONLISTやMV1_REF_VERTEXで設定できそうですが、実際にやってみても、第１引数の `VERTEX3D *Vertex` はエラーが出ます。

DrawPolygon3Dをするためには、先ほどの変数から一部の情報を`VERTEX3D *Vertex`へ変換する必要があるようです。

```c++:Stage.h
class Stage 
{
//~省略~
private:
    //~省略~
    //頂点情報の格納
    std::vector<VERTEX3D> vertexes_;
};
```
```c++:Stage.cpp
void Stage::Init(void)
{
    //~省略~
    //頂点情報へ変換
    for (auto& v : vertexes_)
    {
    	for (int i = 0; i < polygonList_.VertexNum; i++)
    	{
                //頂点情報に変換
    			v.pos = polygonList_.Vertexs[i].Position;
    			v.dif = polygonList_.Vertexs[i].DiffuseColor;
    			v.spc = polygonList_.Vertexs[i].SpecularColor;
    			v.norm = polygonList_.Vertexs[i].Normal;
    			v.u = polygonList_.Vertexs[i].TexCoord[0].u;
    			v.v = polygonList_.Vertexs[i].TexCoord[0].v;

                //動的配列に格納
    			vertexes_.emplace_back(v);
    	}
    }
}

void Stage::Draw(void)
{
    //~省略~
	//ポリゴン描画
	DrawPolygon3D(vertexes_.data(), polygonList_.PolygonNum, DX_NONE_GRAPH, FALSE);
}
```

変換することで`DrawPolygon3D`で描画することができました。
![bfrPoly_Stage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/af05d53b-154b-ee02-5161-7b5ce7700df1.png)
うまく表示できていそうですが、左奥のほうをよく見てみると
![bfrPoly_Stage1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/001057b3-c3e8-8198-43a7-209197d808b4.png)
![bfrPoly_Stage2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/eb22bc99-617c-c852-b5c4-e943b57b20b6.png)
意図しないものも描画されてしまっています。


## 「ポリゴン」として表示

原因は`VERTEX3D *Vertex`にあります。VERTEX3Dは **頂点座標情報** をもつ構造体です。
![vertex.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/c050e7c4-30cb-a0e2-5da4-28ae60b720ac.png)
VERTEX3Dはモデルから読み込んできた頂点座標情報を保有しているだけで、どの頂点がポリゴンを形成しているのかの情報が欠けています。
![vertex1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/ce4c4113-42f1-06cf-bdb1-0f9576a27a79.png)

::: note info
ポリゴンは頂点を時計回りに指定し描画します。
:::

欠けているポリゴン情報をVERTEX3Dに指定する必要があります。`MV1_REF_POLYGONLIST`から取得して指定します。

```c++:Stage.cpp
void Stage::Init(void)
{
    //~省略~

	int num = polygonList_.PolygonNum;
	for (int i = 0; i < num; i++)
	{
		auto poly = polygonList_.Polygons[i];

		for (int p = 0; p < 3; p++)
		{
			//頂点の要素番号を取得
			int vIndex = poly.VIndex[p];

			//取得した頂点の要素番号を使って、頂点情報を取得
			auto verRef = polygonList_.Vertexs[vIndex];

			//頂点情報へ変換
			VERTEX3D v;
			v.pos = verRef.Position;
			v.dif = verRef.DiffuseColor;
			v.spc = verRef.SpecularColor;
			v.norm = verRef.Normal;
			v.u = verRef.TexCoord[0].u;
			v.v = verRef.TexCoord[0].v;

			//動的配列に格納
			vertexes_.emplace_back(v);
		}
	}
    //~省略~
}
```
書き換えたあとの出力結果は、
![complate_Stage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/46ed22cd-5047-c5b2-41c9-1a8cf84eb343.png)
![complate_Stage1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/0dbf1de3-272c-6803-8a54-dc3ab484af71.png)
![complate_Stage2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3402790/c4867023-3408-b76f-bf82-1e5a4e69ee60.png)
うまくポリゴン描画ができていそうです。

# ポリゴンを変動させる

こちらへ続きます。

https://qiita.com/0reo07/items/e8723f946d1484c98788