OPENGL读取OBJ模型
标签(空格分隔): OPENGL/C++
哈哈,先贴出下载链接好吧。下载页面
首先大家不要害怕,读取obj模型听上去很高端很麻烦,其实当你真正了解obj模型的格式,以及OPENGL绘制模型的方式,你也可以很清晰地去绘制obj模型。下面就开始正题吧。
一、什么是OBJ模型
为了观察方便,你可以随便在网上下载一个OBJ模型,然后用txt或者editplus打开。然后你就会看到很整齐的数据。大致如下图所示。
这些数据是什么意思呢。原来OBJ模型中记录的是一个一个的点,而一些点的组合可以组成一个面(可能是三角面片也可能是四角面片,因情况而议)OPENGL中将这些点全部画出来,然后根据组合规则连接成面,这样就可以表达出一个模型。这里给大家看一下具体例子。(盒子是我自己画的模型包围盒)
清楚OPENGL如何绘制OBJ模型后,只要搞清楚OBJ中数据到底是怎么存储的就好办了。
在上图给出的OBJ模型数据中
‘#’代表着该行后面是注释。
v代表着该行后面数据记录着一个点的坐标,包含X/Y/Z。
除了v开头外,常见的还有两个。
vt开头代表着该行后面数据记录着该点的贴图坐标(与贴图有关),包含XT/YT/ZT。
vn开头代表着该行后面数据记录着该点的法向坐标(与光照有关),包含XN/YN/ZN。
f代表着该行后面的数据记录组成该面的点的索引值包含V1/V2/V3(三角面片)。
这里你可能会问到,上图中f后面数据明明是 1/2 3/4 5/6是六个数据。与你说的不符合呀。这是因为f的组成有很多形式:
① f V1/VT1/VN1 V2/VT2/VN2 V3/VT3/VN3 (顶点/纹理坐标/法向)
② f V1/T1 V2/T2 V3/T3 (顶点/纹理坐标)
③ f V1 V2 V3 (顶点)
④ f V1//N1 V2//N2 V3//N3 (顶点//法向)
上述四种还只是三角面片的形式,面片还可能是四角、五角等。在链接给出的程序中只对上述三角面片的这四种形式做了讨论。
二、设计存储obj模型的相应类
设置好模型类。包含有顶点坐标、顶点纹理、顶点法向、面等信息和相应方法。然后按照C/C++读取文件方式去读取模型信息存入实例化类对象中。读取文件就不详述了,网上大把资料可以百度。
model.h
#include<gl/glut.h>
#include <math.h>
#include <iostream>
#include<string>
#include<fstream>
#include<sstream>
#include<vector>
using namespace std;
const float AngleToRadion = 3.14159f/180.0f;
class Objmodel {
private:
//obj模型信息
vector< vector<GLfloat>> vertex;
vector< vector<GLfloat>> vertex_texture;
vector< vector<GLfloat>> vertex_normal;
vector< vector<int>> face_vertex;
vector< vector<int>> face_texture;
vector< vector<int>> face_normal;
GLint v_num;
GLint vt_num;
GLint vn_num;
GLint f_num;
//保存obj边界点,计算模型包围盒
vector<GLfloat > center;
vector<GLfloat > one0fcatercorner; //包围盒对角线中一个点
vector<GLfloat > other0fcatercorner; //包围盒对角线中另一个点
public:
Objmodel();
~Objmodel();
//从文件中读取数据
void readFile(string path);
//显示模型数据
void showObj(GLint mode1,GLint mode2);
//计算obj包围盒中心 并将中心平移到原点
vector<GLfloat> getCenter();
//计算模型顶点法向
void calculateNormal();
//画出模型的包围盒
void drawBox();
};
三、实现功能
1、读取信息存入实例化对象中
C/C++读文件操作。
2、将模型移到视点前方适当位置
读入模型不一定会在你的视域内,你必须把它移动到视点前方来。这里我的思路是:
1)计算出物体的包围盒得到包围盒中心 XC/YC/ZC
a.包围盒的根据遍历所有顶点后的Xmax、Ymax、Zmax和Xmin、Ymin、Zmin这两个点来确定。如果你害怕模型中有单独的孤立点,可以对X,Y,Z排序后取最大的十个、最小的十个来平均(程序中有实现)。
b.计算出包围盒关键顶点,那么将它画出来也就很容易了。
2)将物体平移glTranslatef(-XC,-YC,-ZC)。
3)单单2)步骤还不够,可能还需要在Z方向上平移模型。这是需要跟你视点的角度范围θ和物体包围盒的较长的边长( ( Ymax - Ymin )或者 ( Xmax - Xmin )或者)来确定平移的距离d。如下图:
3、对于没有法向VN的模型,计算其法向
顶点的法向在有光照的情况下对于模型的显示及其重要,因为在OPENGL默认流水线中,除了环境光,漫反射和高光都与法向有关。如果法向不正确,物体的显示会出现极大的偏差。如下图,在没有法向情况下,旋转不同的角度容易观察出模型的效果不正常(此时灯光在永远在模型前方)。
所以对于没有给出VN的模型,需要我们手动计算模型的法向。
那么法向如何计算呢。简单一点的方法,可以把一个面的法向当做所有组成该面的顶点的法向(使用向量叉乘求得,不记得向量叉乘几何意义的同学可以看这里