fbxsdkで3Dモデルのロード　パート1

#自己紹介
某東京にある専門学校に在校している3年生です。
今、就活作品をOpenGLで制作しています。
最近はマイクラはまってます。

#はじめに
fbxsdkで3Dモデルをロードする記事を備忘録として書きます。
fbxsdkの導入などについては他の方の記事を見てください。
この記事ではfbxsdkの初期化と頂点座標の取得、頂点インデックスの取得を行います。
fbxsdkは.fbxの他に.obj, .dxf, .daeも読み込みと書き出しができるらしいです。
自分は.objと.fbxしか読み込んだことがないです。

#必要なクラスを作る

まず頂点のデータを格納するVertexとモデルの情報を保存するModelAssetを作ります。
それと、ロードする用のModelLoaderを作ります。

``` vertex.hpp
#pragma once

struct Vertex
{
	GLfloat position[3];
};
```

```model_asset.hpp
#pragma once
#include "vertex.hpp"

struct ModelAsset
{
    Vertex* vertices;
    int vertices_count;
    GLuint* indices;
    GLsizei indices_count;
};
```

```model_loader.hpp
#pragma once
#include <fbxsdk.h>
#include <iostream>
#include "model_asset.h"

class ModelLoader
{
public:
    static void Load(ModelAsset& model_asset, const char* path);

private:
    static void LoadVertex(ModelAsset& model_asset, FbxMesh& mesh);
    static void LoadIndices(ModelAsset& model_asset, FbxMesh& mesh);
};
```

これらが今回使うクラスと構造体です。

<!--初期化-->

#fbxsdkの初期化とMeshの取得

```model_loader.cpp
#include "model_loader.h"

void ModelLoader::Load(ModelAsset& model_asset, const char* path)
{
	// fbxsdk 初期化処理
	FbxManager* manager = FbxManager::Create();
	if (!manager) {
		std::cerr << "failed to create FbxManager." << std::endl;
		manager->Destroy();
		return;
	}

	FbxScene* scene = FbxScene::Create(manager, "");
	if (!scene) {
		std::cerr << "failed to create FbxScene." << std::endl;
		manager->Destroy();
		return;
	}

	FbxImporter* importer = FbxImporter::Create(manager, "");
	if (!importer) {
		std::cerr << "failed to create FbxImporter." << std::endl;
		manager->Destroy();
		scene->Destroy();
		return;
	}

	if (!importer->Initialize(path, -1, manager->GetIOSettings())) {
		std::cerr << "failed to initialize FbxImporter." << std::endl;
		importer->Destroy();
		manager->Destroy();
		scene->Destroy();
		return;
	}

	if (!importer->Import(scene))
	{
		std::cerr << "failed to import: " << path << std::endl;
		importer->Destroy();
		manager->Destroy();
		scene->Destroy();
		return;
	}

	importer->Destroy();

	// ポリゴンを三角形に変換
	FbxGeometryConverter geometry_converter(manager);
	geometry_converter.Triangulate(scene, true);

	FbxMesh* mesh = scene->GetSrcObject<FbxMesh>();
	if (!mesh) {
		std::cerr << "failed to load mesh." << " (" << path << ")" << std::endl;
		scene->Destroy();
		manager->Destroy();
		return;
	}
}
```

<!--頂点-->
#頂点の読み込み

mesh.GetControlPointsCount()で頂点の数を取得します。
mesh.getControlPointAt()で頂点座標を取得できるのでそれを配列に格納します。

``` model_loader.cpp
void ModelLoader::LoadVertex(ModelAsset& model_asset, FbxMesh& mesh)
{
	int control_points_count = mesh.GetControlPointsCount();
	model_asset.vertices_count = control_points_count;
	model_asset.vertices = new Vertex[control_points_count];

	for (int i = 0; i < control_points_count; i++) {
		FbxVector4 point = mesh.GetControlPointAt(i);
		Vertex vertex;
		vertex.position[0] = point[0];
		vertex.position[1] = point[1];
		vertex.position[2] = point[2];

		model_asset.vertices[i] = vertex;
	}
}
```

#頂点インデックスの読み込み

```model_loader.cpp
void ModelLoader::LoadIndices(ModelAsset& model_asset, FbxMesh& mesh)
{
	int polygon_vertex_count = mesh.GetPolygonVertexCount();
	model_asset.indices_count = polygon_vertex_count;
	model_asset.indices = new GLuint[polygon_vertex_count];

	for (int i = 0; i < polygon_vertex_count; i++) {
		model_asset.indices[i] = mesh.GetPolygonVertices()[i];
	}
}
```

#LoadVertexとLoadIndicesをLoad内で使用する

```model_data.cpp
void ModelLoader::Load(ModelAsset& model_asset, const char* path)
{
	// fbxsdk 初期化処理
	FbxManager* manager = FbxManager::Create();
	if (!manager) {
		std::cerr << "failed to create FbxManager." << std::endl;
		manager->Destroy();
		return;
	}

	FbxScene* scene = FbxScene::Create(manager, "");
	if (!scene) {
		std::cerr << "failed to create FbxScene." << std::endl;
		manager->Destroy();
		return;
	}

	FbxImporter* importer = FbxImporter::Create(manager, "");
	if (!importer) {
		std::cerr << "failed to create FbxImporter." << std::endl;
		manager->Destroy();
		scene->Destroy();
		return;
	}

	if (!importer->Initialize(path, -1, manager->GetIOSettings())) {
		std::cerr << "failed to initialize FbxImporter." << std::endl;
		importer->Destroy();
		manager->Destroy();
		scene->Destroy();
		return;
	}

	if (!importer->Import(scene))
	{
		std::cerr << "failed to import: " << path << std::endl;
		importer->Destroy();
		manager->Destroy();
		scene->Destroy();
		return;
	}

	importer->Destroy();

	// ポリゴンを三角形に変換
	FbxGeometryConverter geometry_converter(manager);
	geometry_converter.Triangulate(scene, true);

	FbxMesh* mesh = scene->GetSrcObject<FbxMesh>();
	if (!mesh) {
		std::cerr << "failed to load mesh." << " (" << path << ")" << std::endl;
		scene->Destroy();
		manager->Destroy();
		return;
	}

	LoadVertex(model_asset, *mesh);
	LoadIndices(model_asset, *mesh);

	scene->Destroy();
	manager->Destroy();
}
```

次は法線座標とuvなどをやろうと思います。
間違っている箇所があればコメントしてほしいです。

参考URL
fbxsdk: http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/
ゲームが作りたいんだ！: https://shikemokuthinking.blogspot.com/2013/06/fbxfbxsdkvc2010.html?view=magazine