zoukankan      html  css  js  c++  java
  • opengl导入obj模型

    在经过查阅各种资料以及各种bug之后,终于成功的实现了导入基本的obj模型。

    首相介绍一下什么是obj模型

    一.什么是OBJ模型

    obj文件实际上是一个文本文档,主要有以下数据,一般可以通过blender软件导出模型的obj文件。

    在3d图形处理中,一个模型(model)通常由一个或者多个Mesh(网格)组成,一个Mesh是可绘制的独立实体。例如复杂的人物模型,可以分别划分为头部,四肢等各个部分来建模,这些Mesh组合在一起最终形成人物模型。

    obj的文本内容一般包括以下数据

    usemtl和mtllib表示的材质相关数据,解析材质数据稍微繁琐,本节我们只是为了说明加载模型的原理,不做讨论。

    o 引入一个新的object

    v 表示顶点位置

    vt 表示顶点纹理坐标

    vn 表示顶点法向量

    f 表示一个面,面使用1/2/8这样格式,表示顶点位置/纹理坐标/法向量的索引,这里索引的是前面用v,vt,vn定义的数据 注意这里Obj的索引是从1开始的,而不是0

    二 利用opengl导入obj模型

    新建一个ObjLoader

    1 class ObjLoader{
    2 public:
    3     ObjLoader(string filename);//构造函数
    4     void Draw();//绘制函数
    5 private:
    6     vector<vector<GLfloat>>vSets;//存放顶点(x,y,z)坐标
    7     vector<vector<GLint>>fSets;//存放面的三个顶点索引
    8 };

    一个构造函数ObjLoader::ObjLoader用于导入obj文本内容

    Draw用于在opengl中绘制模型

    vector<vector<GLfloat>>vSets;//存放顶点(x,y,z)坐标
    vector<vector<GLint>>fSets;//存放面的三个顶点索引

    ObjLoader::ObjLoader(string filename)
    {
        std::ifstream file(filename);
        std::string line;
    while (getline(file, line))
    {
        if (line.substr(0, 2) == "vt")
        {
    
        }
        else if (line.substr(0, 2) == "vn")
        {
    
        }
        else if (line.substr(0, 1) == "v")
        {
            vector<GLfloat> Point;
            GLfloat x, y, z;
            std::istringstream s(line.substr(2));
            s >> x; s >> y; s >> z;
            Point.push_back(x);
            Point.push_back(y);
            Point.push_back(z);
            vSets.push_back(Point);
    
        }
        else if (line.substr(0, 1) == "f")
        {
            vector<GLint> vIndexSets;
            GLint u, v, w;
            std::istringstream vtns(line.substr(2));
            vtns >> u; vtns >> v; vtns>> w;
            vIndexSets.push_back(u-1);
            vIndexSets.push_back(v-1);
            vIndexSets.push_back(w-1);
            fSets.push_back(vIndexSets);
        }
        else if (line.substr(0, 1) == "#")
        {
    
        }
        else
        {
    
        }
    }
    file.close();
    }
    
    
    
    void ObjLoader::Draw(){
    
        glBegin(GL_TRIANGLES);//开始绘制
        for (int i = 0; i < fSets.size(); i++) {
            GLfloat VN[3];
            //三个顶点
            GLfloat SV1[3];
            GLfloat SV2[3];
            GLfloat SV3[3];
    
            if ((fSets[i]).size() != 3) {
                cout << "the fSetsets_Size is not correct" << endl;
            }
            else {
                    GLint firstVertexIndex = (fSets[i])[0];//取出顶点索引
                    GLint secondVertexIndex = (fSets[i])[1];
                    GLint thirdVertexIndex = (fSets[i])[2];
    
                    SV1[0] = (vSets[firstVertexIndex])[0];//第一个顶点
                    SV1[1] = (vSets[firstVertexIndex])[1];
                    SV1[2] = (vSets[firstVertexIndex])[2];
    
                    SV2[0] = (vSets[secondVertexIndex])[0]; //第二个顶点
                    SV2[1] = (vSets[secondVertexIndex])[1];
                    SV2[2] = (vSets[secondVertexIndex])[2];
    
                    SV3[0] = (vSets[thirdVertexIndex])[0]; //第三个顶点
                    SV3[1] = (vSets[thirdVertexIndex])[1];
                    SV3[2] = (vSets[thirdVertexIndex])[2];
    
    
                    GLfloat vec1[3], vec2[3], vec3[3];//计算法向量
                    //(x2-x1,y2-y1,z2-z1)
                    vec1[0] = SV1[0] - SV2[0];
                    vec1[1] = SV1[1] - SV2[1];
                    vec1[2] = SV1[2] - SV2[2];
    
                    //(x3-x2,y3-y2,z3-z2)
                    vec2[0] = SV1[0] - SV3[0];
                    vec2[1] = SV1[1] - SV3[1];
                    vec2[2] = SV1[2] - SV3[2];
    
                    //(x3-x1,y3-y1,z3-z1)
                    vec3[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
                    vec3[1] = vec2[0] * vec1[2] - vec2[2] * vec1[0];
                    vec3[2] = vec2[1] * vec1[0] - vec2[0] * vec1[1];
    
                    GLfloat D = sqrt(pow(vec3[0], 2) + pow(vec3[1], 2) + pow(vec3[2], 2));
    
                    VN[0] = vec3[0] / D;
                    VN[1] = vec3[1] / D;
                    VN[2] = vec3[2] / D;
               
                    glNormal3f(VN[0], VN[1], VN[2]);//绘制法向量
    
                    glVertex3f(SV1[0], SV1[1], SV1[2]);//绘制三角面片
                    glVertex3f(SV2[0], SV2[1], SV2[2]);
                    glVertex3f(SV3[0], SV3[1], SV3[2]);    
            }
        }
        glEnd();
    }

    然后我们写一个主函数

    //模型路径
    string filePath = "../data/monkey.obj";
    
    ObjLoader objModel = ObjLoader(filePath);
    //实现移动鼠标观察模型所需变量
    static float c = 3.1415926 / 180.0f;
    static float r = 1.0f;
    static int degree = 90;
    static int oldPosY = -1;
    static int oldPosX = -1;
    
    //安置光源
    void setLightRes() {
        GLfloat lightPosition[] = { 0.0f, 0.0f, 1.0f, 0.0f };
        glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
        glEnable(GL_LIGHTING); //启用光源
        glEnable(GL_LIGHT0);   //使用指定灯光
    }
    
    //初始化
    void init() {
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
        glutInitWindowSize(500, 500);
        glutCreateWindow("ObjLoader");
        glEnable(GL_DEPTH_TEST);
        glShadeModel(GL_SMOOTH);
        setLightRes();
        glEnable(GL_DEPTH_TEST);
    }
    
    void display()
    {
        glColor3f(1.0, 1.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);                            
        glLoadIdentity();                                     
        glTranslatef(0.0f, 0.0f, -5.0f);                                                              
        setLightRes();
        glPushMatrix();
    
        gluLookAt(r*cos(c*degree), 0, r*sin(c*degree), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
    
    
        objModel.Draw();//绘制obj模型
        glPopMatrix();
        glutSwapBuffers();
    }
    
    void reshape(int width, int height)
    {
        glViewport(0, 0, width, height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(60.0f, (GLdouble)width / (GLdouble)height, 1.0f, 200.0f);
        glMatrixMode(GL_MODELVIEW);
    }
    
    //移动鼠标360观察模型
    void moseMove(int button, int state, int x, int y)
    {
        if (state == GLUT_DOWN) {
            oldPosX = x; oldPosY = y;
        }
    }
    void changeViewPoint(int x, int y)
    {
        int temp = x - oldPosX;
        degree += temp;
        oldPosX = x;
        oldPosY = y;
    }
    
    void myIdle()
    {
        glutPostRedisplay();
    }
    
    int main(int argc, char* argv[])
    {
        glutInit(&argc, argv);
        init();
        glutDisplayFunc(display);
        glutReshapeFunc(reshape);
        glutMouseFunc(moseMove);
        glutMotionFunc(changeViewPoint);
        glutIdleFunc(myIdle);
        glutMainLoop();
        return 0;
    }

    这份代码只适合比较简单的obj文件,针对更为复杂的obj文件读取,比如说顶点法向量和纹理的载入等,可在这基础上进行改进。

    运行效果:

  • 相关阅读:
    atom无法安装插件的解决方法之一
    css3伪类温故知新
    flex 布局笔记
    NPM 无法下载任何包的原因,解决方法
    flex align-content中的描述的“多根轴线的对齐方式”中的“多根轴线”到底是什么
    nodejs express 静态文件的路径
    当函数传入参数是引用类型的几种情况和现象。
    关于NODE NPM 输入命令后没反应的问题
    no input file specified
    获取form提交的返回值
  • 原文地址:https://www.cnblogs.com/feifanrensheng/p/9416717.html
Copyright © 2011-2022 走看看