教程
OpenGLES入門教程1-Tutorial01-GLKit
OpenGLES入門教程2-Tutorial02-shader入門
OpenGLES入門教程3-Tutorial03-三維變換
OpenGLES入門教程4-Tutorial04-GLKit進階
OpenGLES進階教程1-Tutorial05-地球月亮
OpenGLES進階教程2-Tutorial06-光線
OpenGLES進階教程3-Tutorial07-粒子效果
OpenGLES進階教程4-Tutorial08-幀緩存
OpenGLES進階教程5-Tutorial09-碰碰車
OpenGLES進階教程6-Tutorial10-平截體優(yōu)化
OpenGLES進階教程7-Tutorial11-天空盒效果
距離上一篇教程已經有兩個月了梯投,這兩個月詳細閱讀GPUImage的源碼疲恢,并寫了詳細解析,發(fā)現(xiàn)對OpenGLES的深入了解很有幫助姓迅。
上周一個簡書的朋友問我,如果有一個.obj文件,如何用OpenGL ES把它顯示到iOS屏幕上蒲祈。
-
obj文件如下
之前學習blender的時候,在國外的一個系列教程有提到解析obj文件萝嘁,這篇教程便來介紹如何解析obj和mtl文件梆掸,并用OpenGL ES顯示出來。
概念介紹
1牙言、obj文件
obj文件是一種3D模型文件酸钦。
-
文件格式
其中
v 幾何體頂點 (Geometric vertices)
vt 貼圖坐標點 (Texture vertices)
vn 頂點法線 (Vertex normals)
f 面 (Face)
2、mtl文件
mtl文件則是obj文件的附屬文件咱枉,描述幾何體的表面屬性卑硫。
-
文件格式
其中
環(huán)境反射 Ka r g b
漫反射 Kd r g b
鏡反射 Ks r g b
反射指數(shù) Ns exponent 指定材質的反射指數(shù)徒恋,定義了反射高光度
折射值 Ni ptical density 指定材質表面的光密度,即折射值
漸隱指數(shù) d factor 參數(shù)factor表示物體融入背景的數(shù)量
核心思路
新建一個工程欢伏,讀入obj和mtl文件入挣,解析文件內容,寫入到.h/.c文件中硝拧,把.h/.c文件加入新的工程引用径筏。
效果展示
具體細節(jié)
1、文件解析
自定義Model結構體來存儲讀取的信息河爹,通過一行行讀入文件匠璧,并用字符串匹配來解析數(shù)據(jù)。
typedef struct Model
{
int vertices;
int positions;
int texels;
int normals;
int faces;
int materials;
}Model;
Model getOBJinfo(string fp)
{
Model model = {0};
ifstream inOBJ;
inOBJ.open(fp);
if (!inOBJ.good()) {
cout << "error on open " << fp << endl;
exit(1);
}
while (!inOBJ.eof()) {
string line;
getline(inOBJ, line);
string type = line.substr(0, 2);
if (type.compare("v ") == 0) {
model.positions++;
}
else if (type.compare("vt") == 0) {
model.texels++;
}
else if (type.compare("vn") == 0) {
model.normals++;
}
else if (type.compare("f ") == 0) {
model.faces++;
}
}
model.vertices = model.faces * 3;
inOBJ.close();
return model;
}
2咸这、文件寫入
把Model中存儲的解析信息夷恍,分別寫入到.h/.c文件中。
void writeCtexels(string fp, string name, Model model, int faces[][10], float texels[][2])
{
// Append C file
ofstream outC;
outC.open(fp, ios::app);
// Texels
outC << "const float " << name << "Texels[" << model.vertices*2 << "] = " << endl;
outC << "{" << endl;
// Texels
for(int j=0; j<model.materials; j++)
{
for(int i=0; i<model.faces; i++)
{
if(faces[i][9] == j)
{
int vtA = faces[i][1] - 1;
int vtB = faces[i][4] - 1;
int vtC = faces[i][7] - 1;
outC << texels[vtA][0] << ", " << texels[vtA][1] << ", " << endl;
outC << texels[vtB][0] << ", " << texels[vtB][1] << ", " << endl;
outC << texels[vtC][0] << ", " << texels[vtC][1] << ", " << endl;
}
}
}
outC << "};" << endl;
outC << endl;
// Close C file
outC.close();
}
3媳维、最終文件
Materials 材質
Diffuse 漫反射
Specular 鏡面反射
Normal 法線
Texel 紋理
Position 位置
extern const int starshipVertices;
extern const float starshipPositions[198];
extern const float starshipTexels[132];
extern const float starshipNormals[198];
extern const int starshipMaterials;
extern const int starshipFirsts[3];
extern const int starshipCounts[3];
extern const float starshipDiffuses[3][3];
extern const float starshipSpeculars[3][3];
4酿雪、場景渲染
渲染的過程中,設置好BaseEffect后侄刽,進行渲染指黎;有多組參數(shù)時,要分別設置再渲染州丹。
/**
* 渲染場景代碼
*/
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[self setMatrices];
for(int i=0; i<starshipMaterials; i++)
{
// 設置材質
self.baseEffect.material.diffuseColor = GLKVector4Make(starshipDiffuses[i][0], starshipDiffuses[i][1], starshipDiffuses[i][2], 1.0f);
self.baseEffect.material.specularColor = GLKVector4Make(starshipSpeculars[i][0], starshipSpeculars[i][1], starshipSpeculars[i][2], 1.0f);
[self.baseEffect prepareToDraw];
glDrawArrays(GL_TRIANGLES, starshipFirsts[i], starshipCounts[i]);
}
}
總結
這篇教程有兩個工程醋安,一個負責解析,一個用來渲染墓毒。解析的邏輯簡單但較繁瑣吓揪,可以直接看這里;渲染的邏輯和之前教程類似所计,唯一復雜的部分是光照部分的設置柠辞,可以看這里。
另外主胧,blender這個工具非常好用叭首。之前為了學習blender,尋找了很多教程踪栋。demo的解析部分代碼焙格,也是參考教程里面的內容,出處已經找不到夷都。