您的位置:首页 > 运维架构

孙其功陪你学之——OpenGL加载OBJ文件库glm.c和glm.h

2013-08-18 14:29 531 查看
GLM实现了用C语言对OBJ文件的常用操作,用于简单的3D游戏编程应该足够了。3DS MAX,MAYA都可以把模型以OBJ文件格式导出。OBJ文件中包含模型的顶点,面,三角形,法向,纹理坐标等数据,但是其中不包含纹理和材质。材质可以放在OBJ文件中指定一个材质库文件中,使用时材质库文件一般和OBJ文件放在一起。纹理图形就要自己想办法了。

//模型数据结构:

struct GLMmodel{

char* pathname; //模型文件和材质库的路径

char* mtllibname; //材质库名

GLuint numvertices; //顶点数

GLfloat* vertices; //储存顶点的向量

GLuint numnormals; //模型法向数

GLfloat* normals; //储存法向的向量

GLuint numtexcoords; //纹理坐标数

GLfloat* texcoords; //储存纹理坐标的向量

GLuint numfacetnorms; //规则平面数

GLfloat* facetnorms; //储存规则平面的向量

GLuint numtriangles; //三角形数

GLMtriangle* triangles; //储存三角形的向量

GLuint nummaterials; //材质数

GLMmaterial* materials; //储存材质的向量

GLuint numgroups;//图元组数

GLMgroup* groups;//储存图元组的向量

GLfloat position[3];//模型的位置

了解这个模型数据结构主要用于自己扩充操作,以下是glm提供的相关操作:

//单位化模型model并返回缩放比例因子

单位化就是把模型通过平移和缩放变换限制到3维坐标系中点为中心的一个单位正方体区域内

GLfloat glmUnitize(GLMmodel* model);

//计算模型的宽,高,深尺寸,结果保存在dimensions所指的3元素数组中

GLvoid glmDimensions(GLMmodel* model, GLfloat* dimensions);

//按比例参数缩放模型,参数大于1放大,大于0小于1缩小,小于0反射,等于0缩小到0

GLvoid glmScale(GLMmodel* model, GLfloat scale);

//反转模型的多边形顶点顺序,同时反转法向量,默认多边形顶点顺序是逆时针的。

GLvoid glmReverseWinding(GLMmodel* model);

//计算模型面的法向(假定多边形顶点顺序为逆时针)

GLvoid glmFacetNormals(GLMmodel* model);

//计算模型的平滑顶点法向,angle参数为平滑交叉的最大角度(角度制)

GLvoid glmVertexNormals(GLMmodel* model, GLfloat angle);

//按线性投影产生纹理坐标,它把顶点线性映射到矩形上

GLvoid glmLinearTexture(GLMmodel* model);

//按球形映射产生纹理坐标

GLvoid glmSpheremapTexture(GLMmodel* model);

//从内存中释放模型

GLvoid glmDelete(GLMmodel* model);

//从Wavefront公司标准的.OBJ文件中读取模型

GLMmodel* glmReadOBJ(char* filename);

//将模型按Wavefront
.OBJ文件格式写入文件,文件名由filename参数指定

//mode指定写入方式,此参数为取或(“|”)的位联合:

//GLM_NONE - 只按顶点处理

//GLM_FLAT - 按面计算法向

//GLM_SMOOTH - 按顶点计算法向

//GLM_TEXTURE - 包含纹理座标

//GLM_COLOR - 只包含颜色信息(纯色材质)

//GLM_MATERIAL - 包含材质信息

//其中GLM_FLAT和GLM_SMOOTH不能同时指定

//GLM_COLOR和GLM_MATERIAL也不能同时指定

GLvoid glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode);

//按mode指定模式使用当前的OPENGL绘制上下文(context)绘制模型

//mode参数同glmReadOBJ中的mode参数

GLvoid glmDraw(GLMmodel* model, GLuint mode);

//由模型生成OPENGL显示列表并返回显示列表索引号

//其中mode参数同glmWriteOBJ和glmDraw中的mode参数

GLuint glmList(GLMmodel* model, GLuint mode);

//合并模型中差别很小的顶点,epsilon参数指定要合并顶点间的最大差距

//推荐epsilon参数0.00001为焊接模型的起点

GLvoid glmWeld(GLMmodel* model, GLfloat epsilon);

//读取PPM格式的图形文件

//返回一个24位色的图象指针(可用于OPENGL纹理映射和图象绘制函数)

//同时图象尺寸存储在width,height指针参数指定的地址中

glmReadPPM(char* filename, int* width, int* height);
2。glm.c的使用

下面我们学习如何使用glm.c。

首先把glm.c加入工程,并在主文件中

#include "glm.h"。

加载文件用如下代码:

char* g_model_fn = "data\\al.obj";

GLMmodel* g_model = NULL;

g_model = glmReadOBJ(g_model_fn);

if (!g_model) exit(0);

glmUnitize(g_model);

glmScale(g_model,1.8);

glmFacetNormals(g_model);

glmVertexNormals(g_model, 90.0);

g_model_fn是文件名。

g_model是指向GLMmodel结构的指针。

glmReadOBJ加载一个OBJ文件,生成一个GL

Mmodel结构,并返回其指针。以后对这个

model的操作都需要这个指针作为标识。

glmUnitize把模型归一化到一个(-0.5,-0.5,-0.5)-

(0.5,0.5,0.5)的盒子内。这样模型的最大尺寸

是1,中心在原点。

glmScale把模型作伸缩变换(Al身高1米8)。

glmFacetNormals为模型的每个面(facet)生成法

向矢量。

glmVertexNormals为模型的每个顶点生成法向

矢量。顶点的法向矢量是对相邻面的法向矢

量取平均值而得到的,因此需要预先调用

glmFacetNormals。第二个参数表示一个界限,

如果某个相邻面与第一个相邻面的夹角超过

此界限,那么该面不参与平均。这样可以保

留大的转折而不致于让整个模型都没楞没角。

显示模型用如下代码:

Vector3 his_position(0,0.9,-2);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glDisable(GL_TEXTURE_2D);

glTranslatef(his_position.x,his_position.y,his_position.z);

glmDraw(g_model,GLM_SMOOTH | GLM_MATERIAL);

his_position 是记录Al位置的全局变量。Al的

位置用他的重心坐标表示,因此y坐标是0.9

(y坐标竖直向上)。

首先用glTranslatef把局部坐标系设置到Al的位

置。

glmDraw显示模型。第二个参数表示显示方式。

GLM_SMOOTH表示光滑着色,GLM_MATERIAL

表示使用模型自带的材料。此外还有其它一

些方式:GLM_NONE只显示顶点,GLM_FLAT

使用非光滑的着色),GLM_TEXTURE

使用纹理坐标。

程序结束时还应删除模型:

if(g_model) glmDelete(g_model);

glm还包括其它一些函数:

GLvoid glmDimensions(GLMmodel* model, GLfloat* dimensions);

得到模型的长宽高

GLvoid glmReverseWinding(GLMmodel* model);

颠倒多边形的顶点顺序

GLvoid glmLinearTexture(GLMmodel* model);

用投影到平面的方法生成纹理坐标

GLvoid glmSpheremapTexture(GLMmodel* model);

用投影到球面的方法生成纹理坐标

GLvoid glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode);

把模型存成OBJ文件

GLuint glmList(GLMmodel* model, GLuint mode);

生成模型的display list

GLvoid glmWeld(GLMmodel* model, GLfloat epsilon);

合并距离小于epsilon的顶点

GLubyte* glmReadPPM(const char* filename, int* width, int* height);

加载一个PPM文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: