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

    转载:http://blog.csdn.net/shuzfan/article/details/50738394 GoogLeNet主要贡献提出了Inception结构: Architectural ...

  2. easyui datagrid 单元格编辑(cell editing)

    demo中有row editing 项目中发现个cell editing,但是有bug,修改好了 主要实现功能:单击数据表格单元格,编辑单元格数据 js代码如下: $.extend($.fn.data ...

  3. error LNK2038: 检测到“_MSC_VER”的不匹配项: 值“1600”不匹配值“1800”

    _MSC_VER 定义编译器的版本.下面是一些编译器版本的_MSC_VER值:MS VC++ 10.0 _MSC_VER = 1600MS VC++ 9.0 _MSC_VER = 1500MS VC+ ...

  4. jQuery Colorbox弹窗插件使用教程小结、属性设置详解以及colorbox关闭

    jQuery Colorbox是一款弹出层,内容播放插件,效果极佳,当然我主要是用来弹出图片啦. jQuery Colorbox不仅有弹性动画效果,淡入淡出效果,幻灯片播放,宽度自定义,还能够ajax ...

  5. 使用HttpClient访问url的工具类

    maven依赖jar包配置: <dependency> <groupId>org.apache.httpcomponents</groupId> <artif ...

  6. N76E003之SPI

    串行外围总线 (SPI)N76E003系列提供支持高速串行通信的SPI模块.SPI 为微控制与外设 EEPROM, LCD 驱动, D/A 转换之间提供全双工.高速.同步传输的总线.可提供主机从机模式 ...

  7. React Native汇错归纳(持续更新中……)

    1.2017-10-25: 报错信息:“Cannot find entry file index.android.js in any of roots…..” 解决方法: 1.首先从虚拟机中找问题:看 ...

  8. AngularJS控制器和AngularJS过滤器的学习(3)

    前面简单的学习了AngularJS的表达式和指令,就可以说大概对AngularJS有了一定的了解吧,嘿嘿,下面就来总结学习一下AngularJS的控制器和过滤器哦. 说起来AngularJS控制器,其 ...

  9. PHP 二叉树 二叉排序树实现

    <?php /** * PHP 二叉树 * @author : xiaojiang 2014-01-01 * */ class Tree { protected $k = null; prote ...

  10. SqlServer中循环查询结果集

    ); begin ; open c_test_main;--打开游标 --开始循环 begin fetch next from c_test_main into @id,@value; --赋值到变量 ...