.Xの階層メッシュアニメーションを読み込んでみる2

それでは、実際に階層構造を作って表示してみる事にします。
今回はアニメーションはせずに、ただ単にモデルを表示するだけです。


2分木構造を再帰関数を使ってデータ処理をする場合、return で戻る先を
きちんと把握していないとおかしなデータ構造になってしまいます。
再帰関数というのは一つずつネストを深めて行きます。
なので、return すると1階層戻るのではなく 1 NODE 戻ります。
以下の図で説明すると Frame5 から1階層戻る時は 1回の return で
1階層戻りますが、Frame4 から 1階層戻る時は 1回目の return で
Frame3 に戻り、2回目の return でFrame2 に戻り、3回目の return で
Frame1 に戻って、やっと1階層戻る事になります。

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;
}

xfile.h

#pragma once
#include "PNG.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;
//メッシュ構造体
struct MESH{
public:
 vector <MATERIAL> Material;//マテリアル
 vector <TEXTURE*> TexData;//テクスチャデータ
 vector<GLuint> TexID;//テクスチャID
 GLuint TexID2;//代入用
 TEXTURE* tex;//代入用
}msh;
//ノード構造体
struct NODE{
 NODE* Node;//子ノード
 NODE* Next;//隣の階層
 string FrameName;//フレーム名
 MESH* Mesh;//メッシュ
}nde;
//階層メッシュクラス
class HIERARCHY{
public:
 bool Load_Hierarchy(char* FileName); //階層メッシュ読み込み
 bool Load_Frame(FILE& fp,NODE& node,int& hierarchy);  //フレーム読み込み
 bool Load_Mesh(FILE& fp,NODE& node);//メッシュ読み込み
 void Draw();//描画
 void Draw_Frame(NODE& node);
 void Init();
 HIERARCHY();
 HIERARCHY(char* FileName,int size);
 NODE Root;//ルートノード
 int Size;//サイズ
 int Back;//階層戻し
 char buffer[255];
};
HIERARCHY::HIERARCHY(){
 Init();
}
HIERARCHY::HIERARCHY(char* FileName,int size){
 Init();
 Size=size;
 Load_Hierarchy(FileName);
}
void HIERARCHY::Init(){
 Root.Node=NULL;
 Root.Next=NULL;
 Root.FrameName="Root";
 Root.Mesh=NULL;
}
void HIERARCHY::Draw_Frame(NODE& node){
 while(1){
  if(node.Mesh!=NULL){
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_NORMAL_ARRAY);
   for(int i=0;i<(signed)node.Mesh->Material.size();i++){
    glPushMatrix();
    glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,(const GLfloat *)&node.Mesh->Material[i].MaterialColor.ambient);
    glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,(const GLfloat *)&node.Mesh->Material[i].MaterialColor.diffuse);
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,(const GLfloat *)&node.Mesh->Material[i].MaterialColor.specular);
    glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,node.Mesh->Material[i].Shininess);

    if(node.Mesh->Material[i].TexNo>0){
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glEnable(GL_TEXTURE_2D);
     glBindTexture(GL_TEXTURE_2D, node.Mesh->TexID[node.Mesh->Material[i].TexNo-1]);
    }else{
     glDisable(GL_TEXTURE_2D);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }
 
    if(node.Mesh->Material[i].Tridata.size()>1){
     glVertexPointer(3, GL_FLOAT,sizeof(Tri) , &node.Mesh->Material[i].Tridata[0].TriVer.x);
     glNormalPointer(GL_FLOAT,sizeof(Tri),&node.Mesh->Material[i].Tridata[0].TriNor.x);
     //if(node.Mesh->Material[i].TexNo>0)glTexCoordPointer(2, GL_FLOAT, sizeof(Tri), &node.Mesh->Material[i].Tridata[0].TriUV.u);
     glDrawArrays(GL_TRIANGLES,0,node.Mesh->Material[i].Tridata.size());
    }
    if(node.Mesh->Material[i].Quaddata.size()>1){
     glVertexPointer(3, GL_FLOAT,sizeof(Quad) , &node.Mesh->Material[i].Quaddata[0].QuadVer.x);
     glNormalPointer(GL_FLOAT,sizeof(Quad),&node.Mesh->Material[i].Quaddata[0].QuadNor.x);
     //if(node.Mesh->Material[i].TexNo>0)glTexCoordPointer(2, GL_FLOAT, sizeof(Quad), &node.Mesh->Material[i].Quaddata[0].QuadUV.u);
     glDrawArrays(GL_QUADS,0,node.Mesh->Material[i].Quaddata.size());
    }
    glPopMatrix();
 
   }
   glDisableClientState(GL_VERTEX_ARRAY);
   glDisableClientState(GL_NORMAL_ARRAY);
   //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   //glDisable(GL_TEXTURE_2D);
  }

  if(node.Node!=NULL)Draw_Frame(*node.Node);
  if(node.Next!=NULL)Draw_Frame(*node.Next);
  if(node.Node==NULL)return;
  if(node.Next==NULL)return;
  return;
 }
}
void HIERARCHY::Draw(){
 Draw_Frame(Root);
}
//メッシュ読み込み
bool HIERARCHY::Load_Mesh(FILE& fp,NODE& node){
 vector <Vector3f> Vertex;//頂点
 vector <Vector3f> Normal;//法線
 vector <UV> uv;//UV
 vector <int> VertexIndex;
 vector <int> NormalIndex;
 vector <int> MaterialIndex;
 vector <int> FaceIndex;

 char key[255];
 char buf[255];
 
 int v1=0,v2=0,v3=0,v4=0;
 int Count=0;
 string str="";

 //読み込み
 while(!feof(&fp))
 {
  //キーワード 読み込み
  ZeroMemory(key,sizeof(key));
  fscanf_s(&fp,"%s ",key,sizeof(key));
  //頂点 読み込み
  if(strcmp(key,"Mesh")==0)
  {
   fgets(buf,sizeof(buf),&fp);//データは2行下にあると推定 改行する
   fgets(buf,sizeof(buf),&fp);
   Count=atoi(buf);
   for(int i=0;i<Count ;i++)
   {
    fscanf_s(&fp,"%f;%f;%f;,",&vec3d.x,&vec3d.y,&vec3d.z);
    Vertex.push_back(vec3d*(float)Size);
   }
   //頂点インデックス読み込み 
   fgets(buf,sizeof(buf),&fp);//データは2行下にあると推定 改行する
   fgets(buf,sizeof(buf),&fp);
   while(strchr(buf,';')==NULL){fgets(buf,sizeof(buf),&fp);}//空行対策
   Count=atoi(buf);  
   for(int i=0;i<Count ;i++)
   {
    int dammy=0;
    fgets(buf,sizeof(buf),&fp);
    str=buf;
    string::size_type first = str.find_first_not_of(" ");
    string::size_type index = str.find("3;");
    if(index-first==0){
     sscanf_s(buf,"%d;%d,%d,%d;,",&dammy,&v1,&v2,&v3);
     VertexIndex.push_back(v1);
     VertexIndex.push_back(v2);
     VertexIndex.push_back(v3);
    }
    if((index==-1)||(index-first>1)){
     sscanf_s(buf,"%d;%d,%d,%d,%d;,",&dammy,&v1,&v2,&v3,&v4);
     VertexIndex.push_back(v1);
     VertexIndex.push_back(v2);
     VertexIndex.push_back(v3);
     VertexIndex.push_back(v4);
    }
    FaceIndex.push_back(dammy);
   }
  }

  //法線 読み込み
  if(strcmp(key,"MeshNormals")==0)
  {
   fgets(buf,sizeof(buf),&fp);//データは2行下にあると推定 改行する
   fgets(buf,sizeof(buf),&fp);
   Count=atoi(buf);
   for(int i=0;i<Count ;i++)
   {
    fscanf_s(&fp,"%f;%f;%f;,",&vec3d.x,&vec3d.y,&vec3d.z);
    Normal.push_back(vec3d);
   }
   //法線インデックス読み込み 
   fgets(buf,sizeof(buf),&fp);//データは2行下にあると推定 改行する
   fgets(buf,sizeof(buf),&fp);
   while(strchr(buf,';')==NULL){fgets(buf,sizeof(buf),&fp);}//空行対策
   Count=atoi(buf);  
   for(int i=0;i<Count ;i++)
   {
    int dammy=0;
    fgets(buf,sizeof(buf),&fp);
    str=buf;
    string::size_type first = str.find_first_not_of(" ");
    string::size_type index = str.find("3;");
    if(index-first==0){
     sscanf_s(buf,"%d;%d,%d,%d;,",&dammy,&v1,&v2,&v3);
     NormalIndex.push_back(v1);
     NormalIndex.push_back(v2);
     NormalIndex.push_back(v3);
    }
    if((index==-1)||(index-first>1)){
     sscanf_s(buf,"%d;%d,%d,%d,%d;,",&dammy,&v1,&v2,&v3,&v4);
     NormalIndex.push_back(v1);
     NormalIndex.push_back(v2);
     NormalIndex.push_back(v3);
     NormalIndex.push_back(v4);
    }
   }
  }

  //マテリアルリスト
  if(strcmp(key,"MeshMaterialList")==0)
  {
   fgets(buf,sizeof(buf),&fp);//空改行
   fgets(buf,sizeof(buf),&fp);//マテリアル数
   fgets(buf,sizeof(buf),&fp);//リスト要素数
   Count=atoi(buf);
   for(int i=0;i<Count;i++)
   {
    fgets(buf,sizeof(buf),&fp);
    int test=atoi(buf);
    MaterialIndex.push_back(test);
   }
  }
  //マテリアル読み込み
  if(strcmp(key,"Material")==0)
  {
   fgets(buf,sizeof(buf),&fp);//直後の行にあると推定 改行する
   //ディフューズ
   fscanf_s(&fp,"%f;%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z,&vec4d.w);
   mtl.MaterialColor.diffuse=(const Color4 &)vec4d;
   //SHININESS 
   fscanf_s(&fp,"%f;",&mtl.Shininess);
   //スペキュラー
   fscanf_s(&fp,"%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z);
   mtl.MaterialColor.specular=(const Color4 &)vec4d;
   //エミッシブ
   fscanf_s(&fp,"%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z);
   mtl.MaterialColor.ambient=(const Color4 &)vec4d;

   node.Mesh =new MESH(msh);
   node.Mesh->Material.push_back(mtl);
 Count=0;
 //マテリアル毎のデータを作成
 for(int i=0;i<(signed)MaterialIndex.size();i++){
  if(FaceIndex[i]==3){
   for(int j=0;j<3;j++){
    Tri.TriVer=Vertex[VertexIndex[Count+j]];
    Tri.TriNor=Normal[NormalIndex[Count+j]];
    //Tri.TriUV=uv[VertexIndex[Count+j]];
    node.Mesh->Material[MaterialIndex[i]].Tridata.push_back(Tri);
   }
   Count+=3;
  }else{
   for(int j=0;j<4;j++){
    Quad.QuadVer=Vertex[VertexIndex[Count+j]];
    Quad.QuadNor=Normal[NormalIndex[Count+j]];
    //Quad.QuadUV=uv[VertexIndex[Count+j]];
 node.Mesh->Material[MaterialIndex[i]].Quaddata.push_back(Quad);
   }
   Count+=4;
  }
 }
 Vertex.clear();
 Normal.clear();
 uv.clear();
 VertexIndex.clear();
 NormalIndex.clear();
 MaterialIndex.clear();
 FaceIndex.clear();
 return true;
 }
 }
 return false;
}
//フレーム読み込み
bool HIERARCHY::Load_Frame(FILE& fp,NODE& node,int& hierarchy){
 char key[255];
 int begin=0,end=0;
 int current=hierarchy;//現在の階層
 int file_pos;

 while(!feof(&fp))
 {
  //キーワード 読み込み
  ZeroMemory(key,sizeof(key));
  fscanf_s(&fp,"%s ",key,sizeof(key));
  //ヘッダー読み飛ばし
  if(strcmp(key,"Header")==0){
   while(strcmp(key,"}")){
    fscanf_s(&fp,"%s ",key,sizeof(key));
   }
   continue;
  }
  //テンプレート読み飛ばし
  if(strcmp(key,"template")==0){
   while(strcmp(key,"}")){
    fscanf_s(&fp,"%s ",key,sizeof(key));
   }
   continue;
  }
  //階層+
  if(strcmp(key,"{")==0){
   begin++;
  }
  //階層-
  if(strcmp(key,"}")==0){
   end++;
  }
  //フレーム
  if(strcmp(key,"Frame")==0){
   fscanf_s(&fp,"%s ",key,sizeof(key));

   if(((begin==0)&&(end==0))||(end-begin==-1)){//子ノード追加
    node.Node=new NODE(nde);
    node.Node->FrameName=key;
    file_pos=ftell(&fp);
    Load_Mesh(fp,*node.Node);
    fseek( &fp, file_pos, SEEK_SET );
    hierarchy++;
    Load_Frame(fp,*node.Node,hierarchy);//再帰呼び出し
   }

   if(Back==current){//階層戻り先にきた場合、同一階層追加
    Back=-1;
    node.Next=new NODE(nde);
    node.Next->FrameName=buffer;
    file_pos=ftell(&fp);
    Load_Mesh(fp,*node.Next);
    fseek( &fp, file_pos, SEEK_SET );
    Load_Frame(fp,*node.Next,current);//再帰呼び出し
   }
   if(end-begin>0){//"}"が"{"より多い時は階層を戻る
    strcpy_s(buffer,255,key);
    Back=current-(end-begin);
    return true;
   }
 
   if((end-begin==0)&&((begin!=0)&&(end!=0))){//同一階層追加
    node.Next=new NODE(nde);
    node.Next->FrameName=key;
    file_pos=ftell(&fp);
    Load_Mesh(fp,*node.Next);
    fseek( &fp, file_pos, SEEK_SET );
    Load_Frame(fp,*node.Next,current);//再帰呼び出し
   }
   //階層を戻る
   if((Back!=-1)&&(Back<current))return true;
  }
 }
 return true;
}
//階層メッシュ読み込み
bool HIERARCHY::Load_Hierarchy(char* FileName){
 //Xファイルを開いて内容を読み込む
 Back=-1;
 int Hierarchy=0;
 FILE* fp=NULL;
 fopen_s(&fp,FileName,"rt");
 //読み込み
 fseek(fp,0,SEEK_SET);
 Load_Frame(*fp,Root,Hierarchy);
 fclose(fp);
 return true;
}

main.cpp

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

#define WIDTH 320
#define HEIGHT 240

float angle=0.0f;
HIERARCHY* hierarchy;

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.5f,0.5f,0.0f);//回転
 hierarchy->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);

 hierarchy = new HIERARCHY("sample.x",100);
}
int main(int argc, char *argv[])
{
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(WIDTH, HEIGHT);
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 glutCreateWindow("Xの階層メッシュ読み込み");
 glutDisplayFunc(display);
 glutIdleFunc(idle);
 Init();
 glutMainLoop();
 return 0;
}

 

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