如何将外部的obj模型导入OpenGL
作者:feiquan 出处:http://www.cnblogs.com/feiquan/ 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 大家写文都不容易,请尊重劳动成果~ 这里谢谢大家啦(*/ω\*)
1.关于obj的说明。
obj中存放的是顶点坐标信息(v),面的信息(f),法线(vn),纹理坐标(vt),以及材质(这个放在mtl)中
我使用CINEMA 4D导出用VS查看后的信息:
CINEMA 4D中的正方体:

导出obj后的信息

VS中查看;未标题4.obj
# WaveFront *.obj file (generated by CINEMA 4D) mtllib ./未标题4.mtl v -100 -100 100
v -100 100 100
v 100 -100 100
v 100 100 100
v 100 -100 -100
v 100 100 -100
v -100 -100 -100
v -100 100 -100
# 8 vertices vn 0 0 1
vn 1 0 0
vn 0 0 -1
vn -1 0 0
vn 0 1 0
vn 0 -1 0
# 6 normals vt 0 0 0
vt 0 1 0
vt 1 1 0
vt 1 0 0
# 4 texture coordinates o 立方体
usemtl default
f 3/4/1 4/3/1 2/2/1 1/1/1
f 5/4/2 6/3/2 4/2/2 3/1/2
f 7/4/3 8/3/3 6/2/3 5/1/3
f 1/4/4 2/3/4 8/2/4 7/1/4
f 4/4/5 6/3/5 8/2/5 2/1/5
f 5/4/6 3/3/6 1/2/6 7/1/6
未标题4.mtl
# WaveFront *.mtl file (generated by CINEMA 4D) newmtl default
Kd 1 1 1
这就是其中的信息。
我们知道OpenGL中建立不规则模型可以通过点和三角面来创建。那么我们要做的就是从obj中导出点的三维信息和面的三维信息。
2、obj中模型导出的设置。
首先在三维软件中创建一个模型。这里我以一个人体模型演示(只以线框显示)。



模型分析:
·我们可以看到这个模型的点面信息太多了,如果直接导出数据太多,处理时程序读取花费的时间太长,而且我们演示也不需要这种高模。
·还有就是,我们知道OpenGl中的运行后可视化界面的坐标是重-1到1,这里可以看到这个模型的尺寸太大,我们必须进行缩放。
模型不是一个整体,分层太多,导出后各个模块的数据是分开的,所以必须在软件中对模型连接,使其变为一个整体。
模型处理后:



我感觉这样就满足我的要求,后期运行程序读取数据不会超过4分钟
模型导出:注意一下以下地方就好,因为这里只要点(v),面(f)其他会干扰,也会使程序效率下降。导出后只有以下一个文件。


3.数据处理
将那个文件用VS打开后,可以看到里面的数据,这里我们要处理一下:
VS虽然可以直接打开obj但是从这个里面是无法读取数据的。

所以我们要新建一个txt文件,将里面的数据复制进来,然后把这个文件放在你新建的win32或MFC项目中,将先前的obj从工程中移除。

在VS中查找“#”开头的,有以下两句话,然后直接删除这个是我用CINEMA 4D导出后自带的,会干扰程序的运行。


4.编程
分析:
¨分析这些数据,不难猜想obj文件由若干行组成,每行开始有一个字母,用来标注改行数据所表示的意思,v 应该是顶点,g应该是一个名字,观察到,f后紧跟着三个整数,由opengl中的顶点数组得到,他应该是三角行的三个顶点,后面的三个整数就代表着前端顶点的索引值.
class obj3dmodel{
struct vertex{
double x,y,z;
};
struct face{
unsigned int v1,v2,v3;
};
vector<vertex>vertexs;
vector<face>faces;
public :
void parse(const char *filename);
void draw();
};
这里,我们定义两个结构体来表示顶点和三角形,并采用vector容器来保存数据组.
¨之所以把两个结构体定义在类的内部,一个是不想污染源代码,另一个是暂时还没有想到会在别的什么地方会用到他们.所以暂且把他们藏起来
void obj3dmodel::parse(const char *filename){
string s;
ifstream fin(filename);
if(!fin)return;
while(fin>>s){
switch(*s.c_str()){
case 'f':
{
face f;
fin>>f.v1>>f.v2>>f.v3;
cout<<"f "<<f.v1<<" "<<f.v2 <<" "<<f.v3<<endl;
faces.push_back(f);
}
break;
case 'v':
{
vertex v;
fin>>v.x>>v.y>>v.z;
cout<<"v "<<v.x<<" "<<v.y<<" "<<v.z<<" "<<endl;
this->vertexs.push_back(v);
}
break;
case 'w':break;
case 'x':break;
case 'y':break;
case 'z':break;
case '#':break;
default:
{}
break;
}
}
}
void obj3dmodel::draw(){
glBegin(GL_TRIANGLES);
for(int i=;i<faces.size();i++){
//下标减一
float move_y=0.5; //控制模型的位置
vertex v1=vertexs[faces[i].v1-];
vertex v2=vertexs[faces[i].v2-];
vertex v3=vertexs[faces[i].v3-];
glColor3f(0.3,0.5,);
glVertex3f(v1.x,v1.y-move_y,v1.z);
glColor3f(,,);
glVertex3f(v2.x,v2.y-move_y,v2.z);
glColor3f(0.5,0.5,);
glVertex3f(v3.x,v3.y-move_y,v3.z);
}
glEnd();
}


· 

低模 高模
源码提供:
// 1.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <GL/glut.h>
#include<vector>//vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的.
#include <fstream>
#include <string>
#include <iostream> using namespace std; GLfloat step=0.0,s=0.1,move[]={,,}; class obj3dmodel{
struct vertex{
double x,y,z;
};
struct face{
unsigned int v1,v2,v3;
};
vector<vertex>vertexs;
vector<face>faces; public :
void parse(const char *filename);
void draw();
}; void obj3dmodel::parse(const char *filename){
string s;
ifstream fin(filename);
if(!fin)return;
while(fin>>s){
switch(*s.c_str()){
case 'f':
{
face f;
fin>>f.v1>>f.v2>>f.v3;
cout<<"f "<<f.v1<<" "<<f.v2 <<" "<<f.v3<<endl;
faces.push_back(f);
}
break; case 'v':
{
vertex v;
fin>>v.x>>v.y>>v.z;
cout<<"v "<<v.x<<" "<<v.y<<" "<<v.z<<" "<<endl;
this->vertexs.push_back(v);
}
break;
case 'w':break;
case 'x':break;
case 'y':break;
case 'z':break;
case '#':break; default:
{}
break; }
}
} void obj3dmodel::draw(){
glBegin(GL_TRIANGLES);
for(int i=;i<faces.size();i++){
//下标减一
float move_y=0.5;
vertex v1=vertexs[faces[i].v1-];
vertex v2=vertexs[faces[i].v2-];
vertex v3=vertexs[faces[i].v3-];
glColor3f(0.3,0.3,);
glVertex3f(v1.x,v1.y-move_y,v1.z); glColor3f(,,);
glVertex3f(v2.x,v2.y-move_y,v2.z); glColor3f(0.5,0.5,);
glVertex3f(v3.x,v3.y-move_y,v3.z);
}
glEnd();
} obj3dmodel obj; void myinit(){
GLfloat light_ambient[]={0.3,0.2,0.5};
GLfloat light_diffuse[]={,,};
GLfloat light_position[]={,,,};
GLfloat light1_ambient[]={0.3,0.3,0.2};
GLfloat light1_diffuse[]={,,};
GLfloat light1_position[]={-,-,-,};
//灯光
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
glLightfv(GL_LIGHT1,GL_AMBIENT,light1_ambient);
glLightfv(GL_LIGHT1,GL_DIFFUSE,light1_diffuse);
glLightfv(GL_LIGHT1,GL_POSITION,light1_position);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
//深度
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
//材质
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
glEnable(GL_COLOR_MATERIAL); } void DrawColorBox(){
obj.draw();
//glutSolidTeapot(1);
} void display(){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /*s+=0.005;
if(s>1.0)s=0.1;*/ //不进行缩放 //位移
//move[0]+=0.005; //x
//move[1]+=0.005; //y
//move[2]+=0.005; //z
//if(move[0]>2)move[0]=0;
//if(move[1]>2)move[1]=0;
//if(move[2]>2)move[2]=0; glPushMatrix();
//glScalef(s,s,s);
//glTranslatef(move[0],move[1],move[2]);
glRotatef(step,,,);
//glRotatef(step,0,0,1);
//glRotatef(step,1,0,0); DrawColorBox();
glPopMatrix();
glFlush();
glutSwapBuffers();
} void stepDisplay(){
//旋转
step=step+;
if(step>)step=; display();
} void myReshape(GLsizei w,GLsizei h){
glViewport(,,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h){
glOrtho(-1.5,1.5,-1.5*(GLfloat)h/(GLfloat)w,1.5*(GLfloat)h/(GLfloat)w,-,);
}else{
glOrtho(-1.5*(GLfloat)w/(GLfloat)h,1.5*(GLfloat)w/(GLfloat)h,-1.5,1.5,-,);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
} void keyboard (unsigned char key,int x,int y){
switch(key){
case :exit();break;
}
} int _tmain(int argc, CHAR* argv[])
{
obj.parse("66.txt");
//obj.parse("11.txt");
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(,);
glutCreateWindow("simple");
myinit();
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutIdleFunc(stepDisplay);
glutMainLoop();
return ;
}
如何将外部的obj模型导入OpenGL的更多相关文章
- opengl导入obj模型
在经过查阅各种资料以及各种bug之后,终于成功的实现了导入基本的obj模型. 首相介绍一下什么是obj模型 一.什么是OBJ模型 obj文件实际上是一个文本文档,主要有以下数据,一般可以通过blend ...
- OpenGL OBJ模型加载.
在我们前面绘制一个屋,我们可以看到,需要每个立方体一个一个的自己来推并且还要处理位置信息.代码量大并且要时间.现在我们通过加载模型文件的方法来生成模型文件,比较流行的3D模型文件有OBJ,FBX,da ...
- 三维引擎导入obj模型全黑总结
最近有客户试用我们的三维平台,在导入模型的时候,会出现模型全黑和不可见的情况.本文说下全黑的情况. 经过测试,发现可能有如下几种情况. obj 模型没有法线向量 如果obj模型导出的时候没有导出法线向 ...
- 三维引擎导入obj模型不可见总结
最近有客户试用我们的三维平台,在导入模型的时候,会出现模型全黑和不可见的情况.上一篇文章说了全黑的情况.此文说下不可见的情况. 经过测试,发现可能有如下两种情况. 导入的模型不在镜头视野内 导入的模型 ...
- three.js加载obj模型
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...
- Unity3D之Mecanim动画系统学习笔记(二):模型导入
我们要在Unity3D中使用上模型和动画,需要经过下面几个阶段的制作,下面以一个人形的模型开发为准来介绍. 模型制作 模型建模(Modelling) 我们的美术在建模时一般会制作一个称为T-Pose( ...
- Obj模型功能完善(物体材质,光照,法线贴图).Cg着色语言+OpenTK+F#实现.
这篇文章给大家讲Obj模型里一些基本功能的完善,包含Cg着色语言,矩阵转换,光照,多重纹理,法线贴图的运用. 在上篇中,我们用GLSL实现了基本的phong光照,这里用Cg着色语言来实现另一钟Blin ...
- 如何将MagicaVoxel模型导入UE4中(2)
前言 当可以把MagicaVoxel的静态模型导入到UE4后,我又开始不满足了.默认第三人称蓝图的"汽车碰撞人偶(雾)"与场景中的体素画风格格不入,于是,我便想着用自己建造的体素画 ...
- 关于重复记录和外部 ID (CRM导入提示已找到重复的查找引用)
http://docs.huihoo.com/oracle/crm-on-demand/21/local/html/Release21_SimpleChinese/index.htm?toc.htm? ...
随机推荐
- 实用的jQuery技巧
1.回到顶部按钮 利用jQuery里的animate和scrollTop方法,你便不需要使用插件创建简单的滚动到顶部动画. // Back to top $('.top').click(functi ...
- 使用SpringBoot开发REST服务
本文介绍如何基于Spring Boot搭建一个简易的REST服务框架,以及如何通过自定义注解实现Rest服务鉴权 搭建框架 pom.xml 首先,引入相关依赖,数据库使用mongodb,同时使用red ...
- php银联网页支付实现方法
本文实例讲述了php银联网页支付实现方法.分享给大家供大家参考.具体分析如下: 这里介绍的银联WAP支付功能,仅限消费功能. 1. PHP代码如下: 复制代码代码如下: <?phpna ...
- 一个简易的服务框架lsf
项目地址:https://github.com/jianliu/lsf 主体思路是利用javaassist实现一个代理类,代理java的接口,实现每一个方法,实现的代码是对每个方法的名称.参数构建一个 ...
- oracle恢复已删除的表
drop 误删除表之后使用flashback table tablename to before drop 可恢复或者使用flashback table "BIN$gcfME7ObTx+n0 ...
- Xamarin 使用极光推送 详细教程
源码下载地址:http://download.csdn.net/download/kendocross/8677263 有兴趣的看以去看看 一.首先新建一个Xamarin.Android 项目,过程 ...
- PHP运算符优先级 运算符分类
运算符 运算符是可以通过给出的一或多个值(用编程行话来说,表达式)来产生另一个值(因而整个结构成为一个表达式)的东西. 运算符可按照其能接受几个值来分组.一元运算符只能接受一个值,例如 !(逻辑取反运 ...
- 腾讯qq等级计算公式面试题
就三道题大概是: 1. 推算出等级相应的天数 这个还比較简单,公式是:(b=2a+3) a是等级, b是相应的天数 2. 推算出等级总共的天数 先看下规律 等级a 相应天数b 总天数s 1 5 5 ...
- 2016.3.17__CSS3动画__第十一天
CSS3动画 假设您认为这篇文章还不错,能够去H5专题介绍中查看很多其它相关文章. 通过 CSS3,我们能够创建动画,这能够在很多网页中取代动绘图片.Flash 动画以及 JavaScript. 今日 ...
- HDU1598 find the most comfortable road 【并查集】+【枚举】
find the most comfortable road Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ...