OpenGL使用glm類庫載入OBJ
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文件 。推薦閱讀:
※如何判定一點是否在給定頂點的不規則封閉區域內?
※如何用OpenGL封裝一個2D引擎?
※對多重採樣(MSAA)原理的一些疑問?
※為什麼 NVIDIA 的示例總是一條龍?
※Shader 在現在圖形管線中可以負責多少部分?
TAG:OpenGL |