如何將外部的obj模型導入OpenGL

做者:feiquan

出處:http://www.cnblogs.com/feiquan/

版權聲明:本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

你們寫文都不容易,請尊重勞動成果~ 這裏謝謝你們啦(*/ω\*)

 

1.關於obj的說明。前端

  obj中存放的是頂點座標信息(v),面的信息(f),法線(vn),紋理座標(vt),以及材質(這個放在mtl)中ios

  我使用CINEMA 4D導出用VS查看後的信息:程序員

  CINEMA 4D中的正方體:編程

  

  導出obj後的信息數組

  

  VS中查看;未標題4.obj數據結構

  

# WaveFront *.obj file (generated by CINEMA 4D)

mtllib ./未標題4.mtl

v -100 -100 100
v -100 100 100
v 100 -100 100
v 100 100 100
v 100 -100 -100
v 100 100 -100
v -100 -100 -100
v -100 100 -100
# 8 vertices

vn 0 0 1
vn 1 0 0
vn 0 0 -1
vn -1 0 0
vn 0 1 0
vn 0 -1 0
# 6 normals

vt 0 0 0
vt 0 1 0
vt 1 1 0
vt 1 0 0
# 4 texture coordinates

o 立方體
usemtl default
f 3/4/1 4/3/1 2/2/1 1/1/1
f 5/4/2 6/3/2 4/2/2 3/1/2
f 7/4/3 8/3/3 6/2/3 5/1/3
f 1/4/4 2/3/4 8/2/4 7/1/4
f 4/4/5 6/3/5 8/2/5 2/1/5
f 5/4/6 3/3/6 1/2/6 7/1/6

  未標題4.mtloop

  

# WaveFront *.mtl file (generated by CINEMA 4D)

newmtl default
Kd 1 1 1

  這就是其中的信息。this

  咱們知道OpenGL中創建不規則模型能夠經過點和三角面來建立。那麼咱們要作的就是從obj中導出點的三維信息和麪的三維信息。spa

二、obj中模型導出的設置。3d

  首先在三維軟件中建立一個模型。這裏我以一我的體模型演示(只以線框顯示)。

  

 

  模型分析:

  ·咱們能夠看到這個模型的點面信息太多了,若是直接導出數據太多,處理時程序讀取花費的時間太長,並且咱們演示也不須要這種高模。

  ·還有就是,咱們知道OpenGl中的運行後可視化界面的座標是重-1到1,這裏能夠看到這個模型的尺寸太大,咱們必須進行縮放。

  模型不是一個總體,分層太多,導出後各個模塊的數據是分開的,因此必須在軟件中對模型鏈接,使其變爲一個總體。

  模型處理後:

  

 

  我感受這樣就知足個人要求,後期運行程序讀取數據不會超過4分鐘

  模型導出:注意一下如下地方就好,由於這裏只要點(v),面(f)其餘會干擾,也會使程序效率降低。導出後只有如下一個文件。

  

 

 3.數據處理

  將那個文件用VS打開後,能夠看到裏面的數據,這裏咱們要處理一下:

  VS雖然能夠直接打開obj可是從這個裏面是沒法讀取數據的。

  

  因此咱們要新建一個txt文件,將裏面的數據複製進來,而後把這個文件放在你新建的win32或MFC項目中,將先前的obj從工程中移除。

  

 

  在VS中查找「#」開頭的,有如下兩句話,而後直接刪除這個是我用CINEMA 4D導出後自帶的,會干擾程序的運行。

  

  

 4.編程

  分析:

  ¨分析這些數據,不難猜測obj文件由若干行組成,每行開始有一個字母,用來標註改行數據所表示的意思,v 應該是頂點,g應該是一個名字,觀察到,f後緊跟着三個整數,由opengl中的頂點數組獲得,他應該是三角行的三個頂點,後面的三個整數就表明着前端頂點的索引值.

¨好知道了數據結構,就能夠提取分析obj文件啦
  
class obj3dmodel{
    struct vertex{
        double x,y,z;
    };
    struct face{
        unsigned int v1,v2,v3;
    };
    vector<vertex>vertexs;
    vector<face>faces;

public :
    void parse(const char *filename);
    void draw();
};

  這裏,咱們定義兩個結構體來表示頂點和三角形,並採用vector容器來保存數據組.

  ¨之因此把兩個結構體定義在類的內部,一個是不想污染源代碼,另外一個是暫時尚未想到會在別的什麼地方會用到他們.因此暫且把他們藏起來

¨咱們同時爲他定義了parse和draw方法,分別用來從文件中解析數據和利用opengl繪製

  

void obj3dmodel::parse(const char *filename){
    string s;
    ifstream fin(filename);
    if(!fin)return;
    while(fin>>s){
        switch(*s.c_str()){
        case 'f':
        {
            face f;
            fin>>f.v1>>f.v2>>f.v3;
            cout<<"f      "<<f.v1<<"       "<<f.v2 <<"       "<<f.v3<<endl;
            faces.push_back(f);
        }
        break;

        case 'v':
        {
            vertex v;
            fin>>v.x>>v.y>>v.z;
            cout<<"v      "<<v.x<<"       "<<v.y<<"       "<<v.z<<"       "<<endl;
            this->vertexs.push_back(v);
        }
        break;
        case 'w':break;
        case 'x':break;
        case 'y':break;
        case 'z':break;
        case '#':break;

        default: 
            {}
        break;
        
        }
    }         
}

void obj3dmodel::draw(){
    glBegin(GL_TRIANGLES);
    for(int i=0;i<faces.size();i++){
        //下標減一
        float move_y=0.5; //控制模型的位置
        vertex v1=vertexs[faces[i].v1-1];
        vertex v2=vertexs[faces[i].v2-1];
        vertex v3=vertexs[faces[i].v3-1];
        glColor3f(0.3,0.5,0);
        glVertex3f(v1.x,v1.y-move_y,v1.z);

        glColor3f(1,1,0);
        glVertex3f(v2.x,v2.y-move_y,v2.z);

        glColor3f(0.5,0.5,0);
        glVertex3f(v3.x,v3.y-move_y,v3.z);
    }
    glEnd();
}
   注意頂點索引方式,obj裏面是以1爲基數的,因此在索引時要將索引值減1.則會報越界.
  運行程序:
  
5.運行結果:

·   

 

          低模                                                                高模

源碼提供:

  

// 1.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include <GL/glut.h>
#include<vector>//vector(向量): C++中的一種數據結構,確切的說是一個類.它至關於一個動態的數組,當程序員沒法知道本身須要的數組的規模多大時,用其來解決問題能夠達到最大節約空間的目的.
#include <fstream>
#include <string>
#include <iostream>

using namespace std;

GLfloat step=0.0,s=0.1,move[]={0,0,0};

class obj3dmodel{
    struct vertex{
        double x,y,z;
    };
    struct face{
        unsigned int v1,v2,v3;
    };
    vector<vertex>vertexs;
    vector<face>faces;

public :
    void parse(const char *filename);
    void draw();
};

void obj3dmodel::parse(const char *filename){
    string s;
    ifstream fin(filename);
    if(!fin)return;
    while(fin>>s){
        switch(*s.c_str()){
        case 'f':
        {
            face f;
            fin>>f.v1>>f.v2>>f.v3;
            cout<<"f      "<<f.v1<<"       "<<f.v2 <<"       "<<f.v3<<endl;
            faces.push_back(f);
        }
        break;

        case 'v':
        {
            vertex v;
            fin>>v.x>>v.y>>v.z;
            cout<<"v      "<<v.x<<"       "<<v.y<<"       "<<v.z<<"       "<<endl;
            this->vertexs.push_back(v);
        }
        break;
        case 'w':break;
        case 'x':break;
        case 'y':break;
        case 'z':break;
        case '#':break;

        default: 
            {}
        break;
        
        }
    }         
}

void obj3dmodel::draw(){
    glBegin(GL_TRIANGLES);
    for(int i=0;i<faces.size();i++){
        //下標減一
        float move_y=0.5;
        vertex v1=vertexs[faces[i].v1-1];
        vertex v2=vertexs[faces[i].v2-1];
        vertex v3=vertexs[faces[i].v3-1];
        glColor3f(0.3,0.3,0);
        glVertex3f(v1.x,v1.y-move_y,v1.z);

        glColor3f(1,1,0);
        glVertex3f(v2.x,v2.y-move_y,v2.z);

        glColor3f(0.5,0.5,0);
        glVertex3f(v3.x,v3.y-move_y,v3.z);
    }
    glEnd();
}

obj3dmodel obj;

void myinit(){
    GLfloat light_ambient[]={0.3,0.2,0.5};
    GLfloat light_diffuse[]={1,1,1};
    GLfloat light_position[]={2,2,2,1};
    GLfloat light1_ambient[]={0.3,0.3,0.2};
    GLfloat light1_diffuse[]={1,1,1};
    GLfloat light1_position[]={-2,-2,-2,1};
    //燈光
    glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
    glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
    glLightfv(GL_LIGHT0,GL_POSITION,light_position);
    glLightfv(GL_LIGHT1,GL_AMBIENT,light1_ambient);
    glLightfv(GL_LIGHT1,GL_DIFFUSE,light1_diffuse);
    glLightfv(GL_LIGHT1,GL_POSITION,light1_position);
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
    //深度
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    //材質
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
    glEnable(GL_COLOR_MATERIAL);

}

void DrawColorBox(){
    obj.draw();
    //glutSolidTeapot(1);    
}

void display(){
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    /*s+=0.005;
    if(s>1.0)s=0.1;*/  //不進行縮放

    //位移
    //move[0]+=0.005;        //x
    //move[1]+=0.005;        //y
    //move[2]+=0.005;        //z
    //if(move[0]>2)move[0]=0;
    //if(move[1]>2)move[1]=0;
    //if(move[2]>2)move[2]=0;

    glPushMatrix();
    //glScalef(s,s,s);
    //glTranslatef(move[0],move[1],move[2]);
    glRotatef(step,0,1,0);
    //glRotatef(step,0,0,1);
    //glRotatef(step,1,0,0);

    DrawColorBox();
    glPopMatrix();
    glFlush();
    glutSwapBuffers();
}

void stepDisplay(){
    //旋轉
    step=step+1;
    if(step>360)step=0;

    display();
}

void myReshape(GLsizei w,GLsizei h){
    glViewport(0,0,w,h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if(w<=h){
        glOrtho(-1.5,1.5,-1.5*(GLfloat)h/(GLfloat)w,1.5*(GLfloat)h/(GLfloat)w,-10,10);
    }else{
        glOrtho(-1.5*(GLfloat)w/(GLfloat)h,1.5*(GLfloat)w/(GLfloat)h,-1.5,1.5,-10,10);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboard (unsigned char key,int x,int y){
    switch(key){
    case 27:exit(0);break;
    }
}

int _tmain(int argc, CHAR* argv[])
{
    obj.parse("66.txt");
    //obj.parse("11.txt");
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
    glutInitWindowSize(500,400);
    glutCreateWindow("simple");
    myinit();
    glutReshapeFunc(myReshape);
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(stepDisplay);
    glutMainLoop();
    return 0;
}
相關文章
相關標籤/搜索