.FBXを読み込んでみる2(読み込み編)

それでは実際に FBXSDK を使用してデータを取り出してみようと思います。
まず、fbx20113_fbxsdk_win をインストールして Visual studio にパスを通します。
そして プロジェクトのフォルダに fbxsdk_20113.dll と fbxsdk_20113d.dll を置きます。
使い方は KFbxSdkManager を作成して、 KFbxImporter を作成して、
KFbxImporter にファイルを読み込んで初期化します。
そして、 KFbxScene を作成して、 KFbxScene に KFbxImporter で
インポートします。
そして、 KFbxNode を辿って KFbxMesh を探します。
KFbxMesh が見つかったら、そこから各種情報を取り出します。
今回は三角ポリゴンのみでテクスチャ無し、オブジェクト(レイヤー)が一つだけの
.FBXファイルを読み込みました。

 

PNG.h

#pragma once
#include "lodepng.h"

//テクスチャクラス
class TEXTURE{
protected:
 LodePNG_Decoder decoder;//デコーダ
 unsigned char* buffer;//バッファ
 size_t buffersize, imagesize;//サイズ
public:
 TEXTURE();
 TEXTURE(const char* FileName);//コンストラクタ
 void LOAD_PNG(const char* FileName);//PNG読み込み
 unsigned char* image;//イメージポインタ
 unsigned int Width,Height;//画像サイズ
};
TEXTURE::TEXTURE(){
}
TEXTURE::TEXTURE(const char* FileName){
 LOAD_PNG(FileName);
}
void TEXTURE::LOAD_PNG(const char* FileName){
 LodePNG_Decoder_init(&decoder);
 //ロード
 LodePNG_loadFile(&buffer, &buffersize, FileName);
 //デコード
 LodePNG_decode(&decoder, &image, &imagesize, buffer, buffersize);
 //幅,高さ
 Width = decoder.infoPng.width;Height = decoder.infoPng.height;
}
 

fbx.h

#pragma once
#pragma comment(lib,"fbxsdk_20113.lib")
#define K_PLUGIN
#define K_FBXSDK
#define K_NODLL
#define KFBX_DLLINFO
#include "PNG.h"
#include <fbxsdk.h>


using namespace std;
//3つのベクトル
struct Vector3f{
 float x;
 float y;
 float z;
}vec3d;
Vector3f & operator*(Vector3f &v,float size){
 v.x *= size;
 v.y *= size;
 v.z *= size;
 return v;
}
//4つのベクトル
struct Vector4f{
 float x;
 float y;
 float z;
 float w;
}vec4d;
//4つのカラー
struct Color4{
 float r;
 float g;
 float b;
 float a;
};
//4つの反射
struct Reflection4{
 Color4 diffuse;
 Color4 ambient;
 Color4 emission;
 Color4 specular;
};
//UV座標
struct UV{
 float u;//u値
 float v;//v値
}vec2d;
//ポリゴンデータ
struct Triangle{
 Vector3f TriVer;
 Vector3f TriNor;
 UV TriUV;
}Tri;
//ポリゴンデータ
struct Quadrangle{
 Vector3f QuadVer;
 Vector3f QuadNor;
 UV QuadUV;
}Quad;
//マテリアル構造体
struct MATERIAL{
 string MaterialName;//マテリアル名
 Reflection4 MaterialColor;//反射
 float Shininess;//shininess
 string TextureName;//テクスチャ名
 int TexNo;//テクスチャNO.
 vector <Triangle> Tridata;//三角面データ
 vector <Quadrangle> Quaddata;//四角面データ
}mtl;
//モデルクラス
class MODEL{
protected:
 vector <MATERIAL> Material;//マテリアル
 vector <TEXTURE*> TexData;//テクスチャデータ
 vector<GLuint> TexID;//テクスチャID
 GLuint TexID2;//代入用
 TEXTURE* tex;//代入用
public:
 KFbxSdkManager *SdkManager;//FBXSDKマネージャー
 KFbxImporter* Importer;
 KFbxScene* Scene;
 MODEL();
 MODEL(char* FileName,float size);//コンストラクタ
 bool FBX_Load(char* FileName,float size);//ロード
 void Draw();
};
MODEL::MODEL(){
}
MODEL::MODEL(char* FileName,float size){
 FBX_Load(FileName, size);
}
//描画
void MODEL::Draw(){
 glEnableClientState(GL_VERTEX_ARRAY);
 glEnableClientState(GL_NORMAL_ARRAY);
 for(int i=0;i<(signed)Material.size();i++){
  glPushMatrix();
  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,(const GLfloat *)&Material[i].MaterialColor.ambient);
  glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,(const GLfloat *)&Material[i].MaterialColor.diffuse);
  glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,(const GLfloat *)&Material[i].MaterialColor.specular);
  glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,Material[i].Shininess);
  if(Material[i].TexNo>0){
   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, TexID[Material[i].TexNo-1]);
  }else{
   glDisable(GL_TEXTURE_2D);
   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  }
  if(Material[i].Tridata.size()>1){
   glVertexPointer(3, GL_FLOAT,sizeof(Tri) , &Material[i].Tridata[0].TriVer.x);
   glNormalPointer(GL_FLOAT,sizeof(Tri),&Material[i].Tridata[0].TriNor.x);
   if(Material[i].TexNo>0)glTexCoordPointer(2, GL_FLOAT, sizeof(Tri), &Material[i].Tridata[0].TriUV.u);
   glDrawArrays(GL_TRIANGLES,0,Material[i].Tridata.size());
  }
  if(Material[i].Quaddata.size()>1){
   glVertexPointer(3, GL_FLOAT,sizeof(Quad) , &Material[i].Quaddata[0].QuadVer.x);
   glNormalPointer(GL_FLOAT,sizeof(Quad),&Material[i].Quaddata[0].QuadNor.x);
   if(Material[i].TexNo>0)glTexCoordPointer(2, GL_FLOAT, sizeof(Quad), &Material[i].Quaddata[0].QuadUV.u);
   glDrawArrays(GL_QUADS,0,Material[i].Quaddata.size());
  }
  glPopMatrix();
 }
 glDisableClientState(GL_VERTEX_ARRAY);
 glDisableClientState(GL_NORMAL_ARRAY);
 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 glDisable(GL_TEXTURE_2D);
}

//FBXファイル読み込み
bool MODEL::FBX_Load(char* FileName,float size){
 vector <Vector3f> Vertex;//頂点
 vector <Vector3f> Normal;//法線
 vector <UV> uv;//UV
 vector <int> VertexIndex;
 SdkManager = KFbxSdkManager::Create();
 Importer=KFbxImporter::Create(SdkManager,"importer");
 Importer->Initialize((const char*)FileName,-1);
 Scene = KFbxScene::Create(SdkManager, "scene");
 Importer->Import(Scene);
 KFbxNode* pRootNode=Scene->GetRootNode();//ノード
 KFbxMesh* pFbxMesh=0;
 KFbxNodeAttribute::EAttributeType type;
 KFbxNodeAttribute *pAttr=pRootNode->GetNodeAttribute();
 if(pAttr!=NULL)
 {
   type=pAttr->GetAttributeType();
  if(type==KFbxNodeAttribute::eMESH)//タイプがメッシュの場合
  {
   pFbxMesh=pRootNode->GetMesh();
  }
 }
 else//子がメッシュの可能性あり
 {
  int iNumChild=pRootNode->GetChildCount();
  KFbxNode* pChildNode=pRootNode->GetChild(0);
  pAttr=pChildNode->GetNodeAttribute();
  type=pAttr->GetAttributeType();
  if(type==KFbxNodeAttribute::eMESH)//タイプがメッシュの場合
  {
   pFbxMesh=pChildNode->GetMesh();
  }
  else
  {
   MessageBox(0,L"メッシュの読み込み失敗",NULL,MB_OK);
  }
 } 

 //頂点読み込み
 KFbxVector4* pCoord=pFbxMesh->GetControlPoints();
 for(int i=0;i<pFbxMesh->GetControlPointsCount();i++)
 {
  vec3d.x=(float)pCoord[i][0]*size;
  vec3d.y=(float)pCoord[i][1]*size;
  vec3d.z=(float)pCoord[i][2]*size;
  Vertex.push_back(vec3d);
 }

 //頂点インデックス読み込み 
 int* piIndex=pFbxMesh->GetPolygonVertices();
 for(int i=0;i<pFbxMesh->GetPolygonCount()*3;i++){
  VertexIndex.push_back(piIndex[i]);
 }

 //法線読み込み
 KFbxLayerElementNormal* ElementNormal = pFbxMesh->GetLayer(0)->GetNormals();
 if ( ElementNormal->GetMappingMode() == KFbxLayerElement::eBY_POLYGON_VERTEX ) {
  if ( ElementNormal->GetReferenceMode() == KFbxLayerElement::eDIRECT ) {
  // 直接取得
   for ( int i = 0; i < ElementNormal->GetDirectArray().GetCount(); ++i ) {
    vec3d.x = (float)ElementNormal->GetDirectArray().GetAt( i )[ 0 ];
    vec3d.y = (float)ElementNormal->GetDirectArray().GetAt( i )[ 1 ];
    vec3d.z = (float)ElementNormal->GetDirectArray().GetAt( i )[ 2 ];
    Normal.push_back(vec3d);
   }
  }
 }else if( ElementNormal->GetMappingMode() == KFbxLayerElement::eBY_CONTROL_POINT ) {
  if ( ElementNormal->GetReferenceMode() == KFbxLayerElement::eDIRECT ) {
   // 直接取得
   for ( int i = 0; i < ElementNormal->GetDirectArray().GetCount(); ++i ) {
    vec3d.x = (float)ElementNormal->GetDirectArray().GetAt( i )[ 0 ];
    vec3d.y = (float)ElementNormal->GetDirectArray().GetAt( i )[ 1 ];
    vec3d.z = (float)ElementNormal->GetDirectArray().GetAt( i )[ 2 ];
    Normal.push_back(vec3d);
   }
  }
 }
 
 //テクスチャー座標読み込み
 KFbxLayerElementUV* pUV=0;
 pUV=pFbxMesh->GetLayer(0)->GetUVs();
 for(int i=0;i<pFbxMesh->GetTextureUVCount();i++)
 {
  KFbxVector2 v2;
  uv.push_back(vec2d);
  v2=pUV->GetDirectArray().GetAt(i);
  uv[i].u=(float)v2.GetAt(0);
  uv[i].v=1.0f-(float)v2.GetAt(1);
 }

 //マテリアル読み込み
 KFbxNode* pNode=pFbxMesh->GetNode();

 for(int i=0;i<pNode->GetMaterialCount();i++)
 {
  //フォンモデルを想定
  KFbxSurfaceMaterial* pMaterial=pNode->GetMaterial(i);
  KFbxSurfacePhong* pPhong=(KFbxSurfacePhong*)pMaterial;
    
  //環境光
  KFbxPropertyDouble3 d3Ambient=pPhong->GetAmbientColor();
  mtl.MaterialColor.ambient.r=(float)d3Ambient.Get()[0];
  mtl.MaterialColor.ambient.g=(float)d3Ambient.Get()[1];
  mtl.MaterialColor.ambient.b=(float)d3Ambient.Get()[2];
  mtl.MaterialColor.ambient.a=1.0f;
  //拡散反射光
  KFbxPropertyDouble3 d3Diffuse=pPhong->GetDiffuseColor();
  mtl.MaterialColor.diffuse.r=(float)d3Diffuse.Get()[0];
  mtl.MaterialColor.diffuse.g=(float)d3Diffuse.Get()[1];
  mtl.MaterialColor.diffuse.b=(float)d3Diffuse.Get()[2];
  mtl.MaterialColor.diffuse.a=1.0f;
  //鏡面反射光
  KFbxPropertyDouble3 d3Specular=pPhong->GetDiffuseColor();
  mtl.MaterialColor.specular.r=(float)d3Specular.Get()[0];
  mtl.MaterialColor.specular.g=(float)d3Specular.Get()[1];
  mtl.MaterialColor.specular.b=(float)d3Specular.Get()[2];
  mtl.MaterialColor.specular.a=1.0f;
  mtl.Shininess=0.5f;


  //テクスチャー(ディフューズテクスチャーのみ)
  KFbxProperty lProperty;
  lProperty=pMaterial->FindProperty(KFbxSurfaceMaterial::sDiffuse);
  KFbxTexture* ktex=KFbxCast<KFbxTexture>(lProperty.GetSrcObject(KFbxTexture::ClassId, 0));
  if(ktex)
  {
   mtl.TextureName=ktex->GetName();
   //テクスチャを作成
   TexData.push_back(tex);
   TexData[TexData.size()-1] = new TEXTURE(mtl.TextureName.c_str());;
   mtl.TexNo=TexData.size();
   TexID.push_back(TexID2);
   glGenTextures(1, (GLuint *)&TexID[TexData.size()-1]);
   glBindTexture(GL_TEXTURE_2D, TexID[TexData.size()-1]);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 
   glEnable(GL_TEXTURE_2D);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,TexData[TexData.size()-1]->Width, TexData[TexData.size()-1]->Height,
    0,GL_RGBA, GL_UNSIGNED_BYTE, TexData[TexData.size()-1]->image);
   glDisable(GL_TEXTURE_2D);
  }
  Material.push_back(mtl);
 }

 //マテリアル毎のデータを作成
 for(int k=0;k<pFbxMesh->GetPolygonCount();k++)
  {
   KFbxLayerElementMaterial* mat = pFbxMesh->GetLayer(0)->GetMaterials();//レイヤーが1枚だけを想定
   int matId=mat->GetIndexArray().GetAt(k);
    Tri.TriVer=Vertex[VertexIndex[k*3]];
    Tri.TriNor=Normal[k*3];
    Material[matId].Tridata.push_back(Tri);
    Tri.TriVer=Vertex[VertexIndex[k*3+1]];
    Tri.TriNor=Normal[k*3+1];
    Material[matId].Tridata.push_back(Tri);
    Tri.TriVer=Vertex[VertexIndex[k*3+2]];
    Tri.TriNor=Normal[k*3+2];
    Material[matId].Tridata.push_back(Tri);
  }
 Vertex.clear();
 Normal.clear();
 uv.clear();
 VertexIndex.clear();

 return true;
}

main.cpp

#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
#include <GL/freeglut/freeglut.h>
#include "fbx.h"

#define WIDTH 320
#define HEIGHT 240

float angle=0.0f;
MODEL* model;

void display(void)
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glViewport(0,0,WIDTH,HEIGHT);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(30.0, WIDTH/HEIGHT, 0.1, 2000.0);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 gluLookAt(0.0, 500.0, 500.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

 glRotatef(angle,0.0f,1.0f,0.0f);//回転

 model->Draw();
 glutSwapBuffers();
}
void idle(void)
{
 angle+=2.0f;
 Sleep(1);
 glutPostRedisplay();
}
void Init(){
 glClearColor(0.0, 0.0, 0.0, 1.0);
 glEnable(GL_BLEND);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 glEnable(GL_DEPTH_TEST);
 glEnable(GL_LIGHT0);
 glEnable(GL_LIGHTING);
 glEnable(GL_CULL_FACE);
 glCullFace(GL_BACK);
 model = new MODEL("sample.fbx",1);
}
int main(int argc, char *argv[])
{
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(WIDTH, HEIGHT);
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 glutCreateWindow("FBXローダ");
 glutDisplayFunc(display);
 glutIdleFunc(idle);
 Init();
 glutMainLoop();
 return 0;
}

 

最終更新:2014年04月16日 17:29
添付ファイル