上一篇我们学习了如何搭建IOS下openGL的开发环境,接下来我们来学习如何绘制一个多边形。

在2.0之前,es的渲染采用的是固定管线,何为固定管线,就是一套固定的模板流程,局部坐标变换 -> 世界坐标变换 ->观察坐标变换->背面消除->光照->裁剪->投影->视口计算->光栅化,程序员只需要调用固定的api修改一些配置参数就可以完成整个渲染流程了。而到了2.0,固定管线改成了可编程管线,我们对整个渲染流程可以再编程,没有固定的api给你调用,一切都依靠shader来完成。那么什么是shader呢:

Shader分为顶点着色器(Vertex Shader)和片段着色器(Fragment Shader)。其中Vertex Shader主要负责顶点的几何关系等的运算,Pixel Shader主要负责片源颜色等的计算。
 
我们使用的是openGLES2.0。因此必然会用到shader,shader使用OpenGL着色语言(GLSL―OpenGL Shading Language)编写,在这里就不仔细介绍。
 
 
首先,设置好缓存
 GLuint _renderBuffer;
 GLuint _frameBuffer; glGenRenderbuffers(1, &_renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
[_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable: (id<EAGLDrawable>)self.layer]; glGenFramebuffers(1, &_frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
_renderBuffer);

在设置缓存之前,最好先清理一次,避免重复设置

if (_frameBuffer) {
glDeleteFramebuffers(1, &_frameBuffer);
_frameBuffer = 0;
} if (_renderBuffer) {
glDeleteRenderbuffers(1, &_renderBuffer);
_renderBuffer = 0;
}

设置好缓存之后开始编译着色器,基本上编译着色器的步骤都是固定,图像处理,滤镜实现基本都是通过着色器来完成。以下是编译着色器的代码。

GLuint _program;
GLunit _positionSlot;
_program = [MTShaderOperations compileShaders:@"Vertex"
shaderFragment:@"Fragment"];
glUseProgram(_program);
_positionSlot = glGetAttribLocation(_program, "Position");

glUseProgram(_program);

//绑定着色器中的参数

_positionSlot = glGetAttribLocation(_program, "Position");

+ (GLuint)compileShaders:(NSString *)shaderVertex shaderFragment:(NSString *)shaderFragment {
// 1 vertex和fragment两个shader都要编译
GLuint vertexShader = [MTShaderOperations compileShader:shaderVertex withType:GL_VERTEX_SHADER];
GLuint fragmentShader = [MTShaderOperations compileShader:shaderFragment withType:GL_FRAGMENT_SHADER]; // 2 连接vertex和fragment shader成一个完整的program
GLuint _glProgram = glCreateProgram();
glAttachShader(_glProgram, vertexShader);
glAttachShader(_glProgram, fragmentShader); // link program
glLinkProgram(_glProgram); // 3 check link status
GLint linkSuccess;
glGetProgramiv(_glProgram, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(_glProgram, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"%@", messageString);
exit(1);
}
return _glProgram;
}
+ (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType {
// 1 查找shader文件
NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:@"glsl"];
NSError* error;
NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
if (!shaderString) {
NSLog(@"Error loading shader: %@", error.localizedDescription);
exit(1);
} // 2 创建一个代表shader的OpenGL对象, 指定vertex或fragment shader
GLuint shaderHandle = glCreateShader(shaderType); // 3 获取shader的source
const char* shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = (int)[shaderString length];
glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength); // 4 编译shader
glCompileShader(shaderHandle); // 5 查询shader对象的信息
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"%@", messageString);
exit(1);
} return shaderHandle;
}

当然,要编译着色器,首先我们要写好着色器代码。绘制多边形的着色器代码十分简单,如果有不懂得童鞋可以参考OpenGL着色语言(GLSL―OpenGL Shading Language)

新建一个empty文件,然后将后缀改成glsh就可以开始写着色器代码了。

Vertex Shader代码如下:

attribute vec4 Position;

void main(void)
{
gl_Position = Position; }

Fragment Shader代码如下

void main(void)
{ gl_FragColor = vec4(0,1,1, 1.0);
}

编译好着色器之后,我们就可以开始绘制图形了,在这里要注意的是在openGLES中只能画三角形,所有的图形都是由三角形组成的。

还有,在定义顶点时要注意openGL中的坐标系不同于UIKit。

首先定义顶点数组

 const GLfloat vertices[] = {
-1, -1, 0, //左下
1, -1, 0, //右下
-1, 1, 0, //左上
1, 1, 0 }; //右上

绘制图形

//传入顶点参数

glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);

glEnableVertexAttribArray(_positionSlot);

//绘制多边形

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

在上面我们画出了多边形,这个多边形是顶点数组按照顺序画出所有的三角形,在不少情况下,并不能符合我们的要求。我们可以试着将上面最后一句改成

glDrawArrays(GL_TRIANGLE_STRIP, 1, 4);

得到的图像如下

由于openGL只能画三角形,因此在顶点数组中,顶点按照怎样的顺序链接十分重要。因此在openGLES中提供了另一个方法。

//定义索引数组
const GLubyte indices[] = {
0,1,2,
1,2,3
};

//根据索引数组的顺序画出多边形

glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_BYTE, indices);


这样我们就画出了一个四边形,其他多边形也是一样的步骤。

下一篇章我们会讲如何传入一个纹理,敬请期待。

iOS-----openGL--openGL ES iOS 入门篇2--->绘制一个多边形的更多相关文章

  1. IOS 中openGL使用教程2(openGL ES 入门篇 | 绘制一个多边形)

    在上一篇我们学习了如何搭建IOS下openGL的开发环境,接下来我们来学习如何绘制一个多边形. 在2.0之前,es的渲染采用的是固定管线,何为固定管线,就是一套固定的模板流程,局部坐标变换 -> ...

  2. Three.js 第一篇:绘制一个静态的3D球体

    第一篇就画一个球体吧 首先我们知道Three.js其实是一个3D的JS引擎,其中的强大之处就在于这个JS框架并不是依托于JQUERY来写的.那么,我们在写这一篇绘制3D球体的文章的时候,应该注意哪些地 ...

  3. 3-ESP8266 SDK开发基础入门篇--点亮一个灯

    https://www.cnblogs.com/yangfengwu/p/11072834.html 所有的源码 https://gitee.com/yang456/Learn8266SDKDevel ...

  4. IOS 中openGL使用教程3(openGL ES 入门篇 | 纹理贴图(texture)使用)

    在这篇文章中,我们将学习如何在openGL中使用纹理贴图. penGL中纹理可以分为1D,2D和3D纹理,我们在绑定纹理对象的时候需要指定纹理的种类.由于本文将以一张图片为例,因此我们为我们的纹理对象 ...

  5. iOS-----openGL--openGL ES iOS 入门篇3---> 纹理贴图(texture)

    在这篇文章中,我们将学习如何在openGL中使用纹理贴图. penGL中纹理可以分为1D,2D和3D纹理,我们在绑定纹理对象的时候需要指定纹理的种类.由于本文将以一张图片为例,因此我们为我们的纹理对象 ...

  6. Java入门篇(六)——类和对象

    写到这里终于写到了入门篇的最后一个知识点了.类和对象是Java中经常被提到的两个词汇,实际上可以将类看作对象的载体,它定义了对象所具有的功能.Java是面向对象的语言,因此掌握类与对象是学习Java语 ...

  7. IOS 中openGL使用教程1(openGL ES 入门篇 | 搭建openGL环境)

    OpenGL版本 iOS系统默认支持OpenGl ES1.0.ES2.0以及ES3.0 3个版本,三者之间并不是简单的版本升级,设计理念甚至完全不同,在开发OpenGL项目前,需要根据业务需求选择合适 ...

  8. iOS-----openGL--openGL ES iOS 入门篇--->搭建openGL环境

    OpenGL版本 iOS系统默认支持OpenGl ES1.0.ES2.0以及ES3.0 3个版本,三者之间并不是简单的版本升级,设计理念甚至完全不同,在开发OpenGL项目前,需要根据业务需求选择合适 ...

  9. iOS开发-OpenGL ES入门教程1

    http://www.jianshu.com/p/750fde1d8b6a 这里是一篇新手教程,环境是Xcode7+OpenGL ES 2.0,目标写一个OpenGL ES的hello world.O ...

随机推荐

  1. jsp另外五大内置对象之out输出

    <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding= ...

  2. POJ 1067 取石子游戏 (威佐夫博奕,公式)

    题意: 有两堆石子,两个人轮流取石子.规定每次有两种取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子.最后把石子全部取完者为胜者.给定两堆石子数量,问先手的输赢? ...

  3. 打开某exe提示"应用程序无法启动,因为应用程序的并行配置不正确……"的解决方案

    本人在新安装好了的windows server 2008 r2 (64位)上运行“RefilesName V2.0(文件批量改名).exe”,结果提示: 应用程序无法启动,因为应用程序的并行配置不正确 ...

  4. python爬虫之路——变量和变量类型

    变量类型: ①单值:int ②多值:数组 ③复杂:类 变量类型:就是变量的数据结构,表示这个变量所代表的内容的格式是怎样的. (多值)四种基本数据结构: 列表,字典,元组,集合 列表: ①元素可变,  ...

  5. Android(java)学习笔记113:Activity的生命周期

    1.首先来一张生命周期的总图: onCreate():创建Acitivity界面       onStart():让上面创建的界面可见              onResume():让上面创建的界面 ...

  6. CPP-网络/通信:gsoap 的教程和使用

    1.1.1     gSOAP 1.1.1 .1      简介 gSOAP 编译工具提供了一个 SOAP/XML 关于 C/C++ 语言的实现,从而让 C/C++ 语言研发 web 服务或客户端程式 ...

  7. JavaScript操作DOM

    1.DOM对象简介: 什么是DOM:(Document Object Model) 译为文档对象模型,是 HTML 和 XML 文档的编程接口.   2.DOM HTML 节点树:指的是DOM中为操作 ...

  8. Feign-手动创建FeignClient

    前言 在<Feign-请求不同注册中心的服务>中,提到,如果需要请求不同注册中心的服务,可以设置@FeignClient的url属性. 这种做法有个缺点,需要服务消费者,配置各个环境的ur ...

  9. oracle 快速复制一张表,并在此创建索引,日志及并行度

    复制表结构及其数据 create table table_name_new as select * from table_name_old 只复制表结构 create table table_name ...

  10. UICollectionView实现无限轮播

    #import "KGNewsController.h"#import "KGNewsCell.h"#import "KGNews.h"#i ...