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类
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模型的更多相关文章
- 三维引擎导入obj模型不可见总结
最近有客户试用我们的三维平台,在导入模型的时候,会出现模型全黑和不可见的情况.上一篇文章说了全黑的情况.此文说下不可见的情况. 经过测试,发现可能有如下两种情况. 导入的模型不在镜头视野内 导入的模型 ...
- 三维引擎导入obj模型全黑总结
最近有客户试用我们的三维平台,在导入模型的时候,会出现模型全黑和不可见的情况.本文说下全黑的情况. 经过测试,发现可能有如下几种情况. obj 模型没有法线向量 如果obj模型导出的时候没有导出法线向 ...
- Windows下Qt开发环境:OpenGL导入3DMax模型(.3DS)
参考:http://blog.csdn.net/cq361106306/article/details/41876541 效果: 源代码: 解释: CLoad3DS.h为加载3DMax模型的头文件,C ...
- bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...
- OpenGL OBJ模型加载.
在我们前面绘制一个屋,我们可以看到,需要每个立方体一个一个的自己来推并且还要处理位置信息.代码量大并且要时间.现在我们通过加载模型文件的方法来生成模型文件,比较流行的3D模型文件有OBJ,FBX,da ...
- OpenGl读取导入3D模型并且添加鼠标移动旋转显示
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html 最近实习要用到opengl库就是跟opencv 有点像的那个,然后下了 ...
- OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11627508.html 前言: 因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我 ...
- three.js加载obj模型
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...
- [计算机图形学] OpenGL读取obj文件并显示其3D效果
读取三维网格模型(Wavefront OBJ文件) 无法向立方体:cube.obj 有法向兔子模型:bunny.obj 有法向有纹理八字模型:Eight.obj OBJ文件的格式可参考:http: ...
随机推荐
- Spring中的类型转换与数据绑定(PropertyEditor、ConversionService、Data Binding、Formatter)
Spring早期使用PropertyEditor进行Object与String的转换.到Spring 3后,Spring提供了统一的ConversionService API和强类型的Converte ...
- SpringMVC由浅入深day02_4springmvc校验
4 springmvc校验 4.1 校验Validation理解 b/s系统中对http请求数据的校验多数在客户端进行,这也是出于简单及用户体验性上考虑,但是在一些安全性要求高的系统中服务端校验是不可 ...
- JS有趣的单线程
一.JS的执行特点 源于单线程的特性, JS在一段时间内只能执行一部分代码, 那么, 当有多块代码需要执行时, 就需要排队等候了. 二.单线程与异步事件 (1) 什么是异步事件? 异 ...
- 《NodeJs开发指南》第五章微博开发实例的中文乱码问题
在<NodeJs开发指南>第五章,按照书中的要求写好微博实例后,运行代码,发现中文显示出现乱码,原因是:views文件夹下的ejs文件的编码格式不是utf-8. 解决方法:以记事本方式打开 ...
- RF-For循环使用
场景1:
- SQL筛选出同一学科的时间最新的记录
1.建表语句 CREATE TABLE `score` ( `id` ) NOT NULL AUTO_INCREMENT, `student_id` ) ' COMMENT '学生表ID', `nam ...
- DOM的学习
今天学习了DOM,感觉学习起来真的没那么简单啦,这不是一个好现象啊,只有依靠自己大补课,嘿嘿,具体的总结了一下,今天学习的其实并不多,仅仅学习了不同的节点类型,但是知识还是蛮碎的,要一点一点的总结,昨 ...
- PowerDesigner 同步Name到Comment 及 同步 Comment 到Name
PowerDesigner中使用方法为: PowerDesigner->Tools->Execute Commands->Edit/Run Scripts 代码一:将Name ...
- 查询sql server 2008所有表和行数
查询sql server 2008所有表和行数 SELECT a.name, b.rows FROM sysobjects AS a INNER JOIN sysindexes AS b ON a.i ...
- android基础---->WidGet的使用
Widget是一个可以添加在别的应用程序中的”小部件”,我们可以使用自定义的Widget远程控制我们的程序做一些事情.一般用于在桌面上添加一个小部件,现在我们开始小部件的学习. 目录导航: WidGe ...