在经过查阅各种资料以及各种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

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

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

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

运行效果:

opengl导入obj模型的更多相关文章

  1. 三维引擎导入obj模型不可见总结

    最近有客户试用我们的三维平台,在导入模型的时候,会出现模型全黑和不可见的情况.上一篇文章说了全黑的情况.此文说下不可见的情况. 经过测试,发现可能有如下两种情况. 导入的模型不在镜头视野内 导入的模型 ...

  2. 三维引擎导入obj模型全黑总结

    最近有客户试用我们的三维平台,在导入模型的时候,会出现模型全黑和不可见的情况.本文说下全黑的情况. 经过测试,发现可能有如下几种情况. obj 模型没有法线向量 如果obj模型导出的时候没有导出法线向 ...

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

    参考:http://blog.csdn.net/cq361106306/article/details/41876541 效果: 源代码: 解释: CLoad3DS.h为加载3DMax模型的头文件,C ...

  4. bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...

  5. OpenGL OBJ模型加载.

    在我们前面绘制一个屋,我们可以看到,需要每个立方体一个一个的自己来推并且还要处理位置信息.代码量大并且要时间.现在我们通过加载模型文件的方法来生成模型文件,比较流行的3D模型文件有OBJ,FBX,da ...

  6. OpenGl读取导入3D模型并且添加鼠标移动旋转显示

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html 最近实习要用到opengl库就是跟opencv 有点像的那个,然后下了 ...

  7. OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11627508.html 前言: 因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我 ...

  8. three.js加载obj模型

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...

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

     读取三维网格模型(Wavefront OBJ文件) 无法向立方体:cube.obj 有法向兔子模型:bunny.obj 有法向有纹理八字模型:Eight.obj OBJ文件的格式可参考:http: ...

随机推荐

  1. POJ 3273 Monthly Expense(二分搜索)

    Description Farmer John is an astounding accounting wizard and has realized he might run out of mone ...

  2. http 返回码 405 解决方案之一

    今天做网络请求数据的时候遇到返回码405,当时就傻了~~ 故事是这样的-- 我用post请求访问一个url,服务端数据是一个json的txt文件,理论上直接访问,返回json,然后解析就没事了,可是今 ...

  3. ios开发之--UITableView中的visibleCells的用法

    先上图: 具体代码如下: #import "ViewController.h" @interface ViewController ()<UITableViewDelegat ...

  4. Python easyGUI 登录框 非空验证

    import easygui as g msg='欢迎注册' title='注册' fieldNames=['*用户名','*密码','*重复密码','真实姓名','手机号','QQ','e-mail ...

  5. Explaining Delegates in C# - Part 6 (Asynchronous Callback - Way 3)

    By now, I have shown the following usages of delegates... Callback and Multicast delegatesEventsOne ...

  6. php-fpm 记录慢执行日志

    有时候我们访问一个 php 的网站很慢,要想知道慢的原因,需要配置 php-fpm.conf,记录执行慢的日志: [root@localhost ~]$ cat /usr/local/php/etc/ ...

  7. springboot 集成elasticsearch

    In this article, we will discuss about “How to create a Spring Boot + Spring Data + Elasticsearch Ex ...

  8. 新唐的开发环境的搭建,驱动以及BSP

    https://www.keil.com/demo/eval/arm.htm#DOWNLOAD1,MDK-ARM的IDE集成开发环境:mdk512.exehttp://www.keil.com/fid ...

  9. javaweb项目中表单生成的验证码以及校验

    首先先来看一下项目的结构吧,有两个servlet,一个是进行验证码的生成以及存储的,一个是进行校验的,还有一个jsp页面是用来实现form表单的书写和展示: 我们只需要看这三个就行了,其他的自动忽略: ...

  10. c++学习笔记—动态内存与智能指针浅析

    我们的程序使用内存包含以下几种: 静态内存用来保存局部static对象.类static数据成员以及定义在任何函数之外的变量,在使用之前分配,在程序结束时销毁. 栈内存用来保存定义在函数内部的非stat ...