在经过查阅各种资料以及各种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. 安装kafka集群

    1解压tar包 tar -zxvf kafka_2.-.tgz 2.进入config目录 3.配置server.properties文件 # Licensed to the Apache Softwa ...

  2. 2、一、Introduction(入门):1、Application Fundamentals(应用程序基础)

    一.Introduction(入门) 1.Application Fundamentals(应用程序基础) Android apps are written in the Java programmi ...

  3. MySQL复制搭建

    1. 原理 参考<涂抹MySQL  跟着三思一步一步学MySQL >这本书. 2.环境背景 操作系统 :CentOS 6.5 数据库版本:MySQL 5.6 主库A:192.168.1.2 ...

  4. flask操作mongo两种方式--常规

    #manage.py #coding=utf-8 #Flask-Script是一个可以在flask应用外部编写脚本的扩展 #常用功能: #运行一个开发的服务器 #python shell中操作数据库看 ...

  5. C语言中的正负数及其输出

    在数学中,数字有正负之分.在C语言中也是一样,short.int.long 都可以带上正负号,例如: //负数 ; short a2 = -0x2dc9; //十六进制 //正数 ; ; //八进制 ...

  6. vc下项目的头文件包含目录以及库导入预计库目录设置

    1.包含目录:include 头文件包含目录设置: project->setting->C/C++->常规: Additional include directories(附加包含目 ...

  7. (原创)Windows下使用android ADT工具dmtracedump.exe绘图

    在windows下使用dmtracedump绘图时,出现如下错误: 'dot' 不是内部或外部命令,也不是可运行的程序 或批处理文件. 应该是没有dot这个执行程序,安装:Graphviz程序,然后将 ...

  8. 《转载》Python3安装Scrapy

    运行平台:Windows Python版本:Python3.x IDE:Sublime text3 转载自:http://blog.csdn.net/c406495762/article/detail ...

  9. PowerDesigner快捷键【转】

    一般快捷键 快捷键 说明 F4 打开检查模型窗口,检查模型 F5 如果图窗口内的图改变过大小,恢复为原有大小即正常大小 F6 放大图窗口内的图 F7 缩小图窗口内的图 F8 在图窗口内中查看全部图内容 ...

  10. JAVA知多少

    读<java解惑>感觉有意思的就记录一下. 1.判断奇数还是偶数 public boolean isOdd(int i){ return i%2==1; }; 这样子看起来很对,但是考虑到 ...