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文件读取,比如说顶点法向量和纹理的载入等,可在这基础上进行改进。

运行效果:

原文地址:https://www.cnblogs.com/feifanrensheng/p/9416717.html

时间: 2024-11-10 12:29:10

opengl导入obj模型的相关文章

Windows下Qt开发环境:OpenGL导入3DMax模型(.3DS)

参考:http://blog.csdn.net/cq361106306/article/details/41876541 效果: 源代码: 解释: CLoad3DS.h为加载3DMax模型的头文件,CLoad3DS.cpp为加载3DMax模型的实现文件, nehewidget.h为Qt下使用OpenGL头文件,nehewidget.cpp为Qt下使用OpenGL实现文件. 注意: 1.3D模型和纹理图片资源需要放在源代码同一目录下的Data目录中,即/Data/3DS和/Data/pic下. 2

解析OBJ模型并将其加载到Unity3D场景中

??各位朋友,大家好,欢迎大家关注我的博客,我是秦元培,我的博客地址是http://qinyuanpei.com.今天想和大家交流的是解析obj模型并将其加载到Unity3D场景中,虽然我们知道Unity3D是可以直接导入OBJ模型的,可是有时候我们并不能保证我们目标客户知道如何使用Unity3D的这套制作流程,可能对方最终提供给我们的就是一个模型文件而已,所以这个在这里做这个尝试想想还是蛮有趣的呢,既然如此,我们就选择在所有3D模型格式中最为简单的OBJ模型来一起探讨这个问题吧! 关于OBJ模

OpenGL学习脚印:模型加载初步-加载obj模型(load obj model)

写在前面 前面介绍了光照基础内容,以及材质和lighting maps,和光源类型,我们对使用光照增强场景真实感有了一定了解.但是到目前为止,我们通过在程序中指定的立方体数据,绘制立方体,看起来还是很乏味.本节开始介绍模型加载,通过加载丰富的模型,能够丰富我们的场景,变得好玩.本节的示例代码均可以在我的github下载. 加载模型可以使用比较好的库,例如obj模型加载的库,Assimp加载库.本节作为入门篇,我们一开始不使用这些库加载很酷的模型,而是熟悉下模型以及模型加载的概念,然后我们封装一个

unity3D 动态导入FBX、obj模型

公司项目的需求,需要动态的从本地导入FBX模型于是花了一天时间翻墙找到了一点可怜的资料. 1.这个可以动态加载OBJ模型,这个的话unity自带的有这个函数,当然OBJ模型是不带贴图的,对于一些场景是无法创建的. http://download.csdn.net/detail/xiaomuzi0802/8316215 2.这个比较实用的,可以动态载入多种模型,特别是FBX模型,在创建场景时候很好用,不过这个是试用版本,贴图会有问题,如果要更好的还是推荐买正版 http://download.cs

基于Qt的OpenGL可编程管线学习(2)- obj模型绘制

绘制一个Obj模型,效果如下图所示 这里给模型加载顶点和纹理的信息,加上环境光.漫反射和镜面反射,这里我用的是一个方向光. 并且让模型每一帧旋转一个角度达到动态旋转的效果. 1.Obj模型基本内容及加载 v 表示顶点数据 vt 表示纹理数据 vn 表示法线数据 f 表示一个面的顶点数据的Index 这里我是直接解析的模型,代码如下所示: objmode.h #ifndef OBJMODE_H #define OBJMODE_H #include <QObject> #include <Q

[计算机图形学] OpenGL读取obj文件并显示其3D效果

? 读取三维网格模型(Wavefront OBJ文件) 无法向立方体:cube.obj 有法向兔子模型:bunny.obj 有法向有纹理八字模型:Eight.obj OBJ文件的格式可参考:http://www.cnblogs.com/youthlion/archive/2013/01/21/2870451.html ? 利用OpenGL显示该模型的绘制效果(全部) 顶点显示 线条显示 面片显示 ? 核心代码说说 1.下面的点.纹理.法向量.面用于构成一个PIC的类,PIC用于存储从OBJ文件中

DirectX的OBJ模型加载与渲染

在之前的DirectX例子里我用的模型是.x文件,DirectX有一个方法D3DXLoadMeshFromX可以加载.x模型,但是这里有个问题,.x文件是没法用文本编辑器打开查看结构的,这里我来演示一下如何解析.obj模型. 首先让我们看一下.obj模型的组成部分以及结构,一个完整的obj模型一共分为三个部分:obj模型文件,mtl材质文件,纹理贴图;其中obj文件和mtl文件是可以用文本编辑器打开的,先打开obj文件,可以看到这样的内容: v -3.000767 2.993211 2.0142

Unity3D游戏开发从零单排(五) - 导入CS模型到Unity3D

游戏动画基础 Animation组件 Animation组件是对于老的动画系统来说的. 老的动画形同对应的动画就是clip,每个运动都是一段单独的动画,使用Play()或CrossFade(),直接播放动画 或淡入淡出播放动画. animation.Play("name"); animation.CrossFade("name"); 下面的是它的几个属性 Animation:默认的动画片段: Aniamtions:包含的动画片段: Play Automaticall

Unity 3d导入3dMax模型 产生若干问题

Unity 3d导入3dMax模型 会产生若干问题,按照官方 的说明,将max 模型导成fbx文件 导入untiy似乎也不能解决 1.x轴向偏转3dmax模型导入后自动有一个x轴270度的偏转,巧合的是,在unity中旋转模型的时候,你会发现y轴参照方向永远朝上,而x和z轴则以模型本身的 局部坐标 为准,这样当模型沿x轴旋转270度之后,z轴正好与y轴重合,这样你试图用程序 控制方向的时候就会发现旋转y和旋转z效果 相同,这显然不是你期望的结果.解决这个问题的方法是,将.max文件导出为.3ds