OpenGLES_实战04_教你绘制球体

学习是一件开心的额事情

本节学习目标

使用OpenGL绘制一个地球

上干货

  • 第一步 创建一个工程
让学习成为一种习惯
让学习成为一种习惯
  • 第二步 创建GLKViewController类型的控制器
让学习成为一种习惯
  • 第三步 添加OpenGL ES 2.0的头文件
让学习成为一种习惯
  • 第四步 配置我们的GLKViewController 控制器
GLKView *glkView = (GLKView*)self.view;
glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;// 设置深度缓冲区格式
// 创建管理上下文
glkView.context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
// 设置当前上下文
[EAGLContext setCurrentContext:glkView.context];
  • 第五步 创建一个负责渲染的类
@property(nonatomic,strong)GLKBaseEffect *baseEffect;
self.baseEffect = [[GLKBaseEffect alloc]init];
  • 第六步 生成球体的顶点坐标和纹理坐标和索引

下面是生成球体坐标C语言方法

#define ES_PI  (3.14159265f)

int generateSphere(int numSlices, float radius, float **vertices,
            float **texCoords, uint16_t **indices, int *numVertices_out) {
int i;
int j;
int numParallels = numSlices / 2;
int numVertices = (numParallels + 1) * (numSlices + 1);
int numIndices = numParallels * numSlices * 6;
float angleStep = (2.0f * ES_PI) / ((float) numSlices);
if (vertices != NULL)
    *vertices = malloc(sizeof(float) * 3 * numVertices);
if (texCoords != NULL)
    *texCoords = malloc(sizeof(float) * 2 * numVertices);
if (indices != NULL)
    *indices = malloc(sizeof(uint16_t) * numIndices);
for (int i = 0; i < numParallels + 1; i++) {
    for (int j = 0; j < numSlices + 1; j++) {
        int vertex = (i * (numSlices + 1) + j) * 3;
        if (vertices) {
            (*vertices)[vertex + 0] = radius * sinf(angleStep * (float)i) *
            sinf(angleStep * (float)j);
            (*vertices)[vertex + 1] = radius * cosf(angleStep * (float)i);
            (*vertices)[vertex + 2] = radius * sinf(angleStep * (float)i) *
            cosf(angleStep * (float)j);
        }
        if (texCoords) {
            int texIndex = (i * (numSlices + 1) + j) * 2;
            (*texCoords)[texIndex + 0] = (float)j / (float)numSlices;
            (*texCoords)[texIndex + 1] = 1.0f - ((float)i / (float)numParallels);
        }
    }
}
if (indices != NULL) {
    uint16_t *indexBuf = (*indices);
    for (i = 0; i < numParallels ; i++) {
        for (j = 0; j < numSlices; j++) {
            *indexBuf++ = i * (numSlices + 1) + j;
            *indexBuf++ = (i + 1) * (numSlices + 1) + j;
            *indexBuf++ = (i + 1) * (numSlices + 1) + (j + 1);
            
            *indexBuf++ = i * (numSlices + 1) + j;
            *indexBuf++ = (i + 1) * (numSlices + 1) + (j + 1);
            *indexBuf++ = i * (numSlices + 1) + (j + 1);
        }
    }
}
if (numVertices_out) {
    *numVertices_out = numVertices;
}
return numIndices;
}

接下来定义上面函数需要的参数

GLfloat   *_vertexData; // 顶点数据
GLfloat   *_texCoords;  // 纹理坐标
GLushort  *_indices;    // 顶点索引
 GLint    _numVetex;   // 顶点数量
GLuint  _texCoordsBuffer;// 纹理坐标内存标识
GLuint  _numIndices; // 顶点索引的数量

调用上面方法生成顶点坐标,纹理坐标,索引数组

 _numIndices = generateSphere(200, 1.0, &(_vertexData), &(_texCoords), &_indices, &_numVetex);
  • 第七步 将顶点坐标,纹理坐标,索引坐标加载到GPU 中去
-(void)loadVertexData{

// 加载顶点坐标数据
glGenBuffers(1, &_vertexBuffer); // 申请内存
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); // 将命名的缓冲对象绑定到指定的类型上去
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*_numVetex*3,_vertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);  // 绑定到位置上
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), NULL);

// 加载顶点索引数据
GLuint _indexBuffer;
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _numIndices*sizeof(GLushort), _indices, GL_STATIC_DRAW);



// 加载纹理坐标
glGenBuffers(1, &_texCoordsBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _texCoordsBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*_numVetex*2, _texCoords, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), NULL);

}
  • 第八步 将我们的地图照片使用刚才创建的渲染类GLKBaseEffect 加载到内存中去
让学习成为一种习惯
GLKTextureInfo *textureInfo =
[GLKTextureLoader textureWithCGImage:[UIImage imageNamed:@"earth-diffuse.jpg"].CGImage options:nil error:nil];
self.baseEffect.texture2d0.target = textureInfo.target;
self.baseEffect.texture2d0.name = textureInfo.name;
  • 第九步 在绘制之前,我们要设置一下 世界坐标和绘制球体的自身坐标
 // 设置世界坐标和视角
float aspect = fabs(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);
self.baseEffect.transform.projectionMatrix = projectionMatrix;

// 设置模型坐标
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, -1.0f, -6.5f);
self.baseEffect.transform.modelviewMatrix =  modelViewMatrix;
  • 第十一步 我们设置个沿着Y轴旋转的效果
// update方法系统会自动调动  
-(void)update{
 self.baseEffect.transform.modelviewMatrix = GLKMatrix4Rotate(self.baseEffect.transform.modelviewMatrix, 0.1, 0, 1, 0);
}
  • 第十二步 开始绘制
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{

// 清除颜色缓冲区
glClearColor(1.0, 0, 1.0, 1);
glClear(GL_COLOR_BUFFER_BIT);

// 绘制之前必须调用这个方法
[self.baseEffect prepareToDraw];
static int i =1;
if (i < _numIndices-2000){
    i = i+1000;
}else{
    i = _numIndices;
}

// 以画单独三角形的方式 开始绘制
glDrawElements(GL_TRIANGLES, i,GL_UNSIGNED_SHORT, NULL);
}

代码!

运行一下:

让学习成为一种习惯

总结

写这篇文章主要给初学者一个绘制球体的思路,苹果给我们封装的类,帮助我们简化了不少代码,如果纯OpenGL 做这样一个练习代码量还是挺多的。

代码下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 1 前言 一直想沿着图像处理这条线建立一套完整的理论知识体系,同时积累实际应用经验。因此有了从使用AVFounda...
    RichardJieChen阅读 5,642评论 5 12
  • 你好,三角形 图形渲染管线(Pipeline) 3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Pi...
    IceMJ阅读 7,411评论 2 13
  • 开发基于 OpenGL 的应用程序,必须先了解 OpenGL 的库函数。它采用 C 语言风格,提供大量的函数来进行...
    sillen阅读 3,030评论 0 4
  • 第五章-数据 本章我们会学到什么 如何创建缓冲和纹理,用它们来存储数据,以及程式如何访问数据。 如何使得OpenG...
    葭五阅读 4,489评论 2 13
  • 若我们都爱与过去聊天,那全世界都在失眠。
    北七海阅读 167评论 0 0