OpenGL ES入门详解
http://blog.csdn.net/wangyuchun_799/article/details/7736928
1.决定你要支持的OpenGL ES的版本。目前,OpenGL ES包含1.1和2.0两个版本,iPhone 3G+和iPad开始支持OpenGL ES2.0。而且这两个版本之间的差异非常大,不仅仅在编程思想上,API之间的差距也很大。因此,如果你想使用OpenGL ES开发3D程序或游戏,那么首先就要决定使用哪个版本,还是说两个版本都支持。OpenGL ES定义了代表不同版本的宏:
enum
{
kEAGLRenderingAPIOpenGLES1 = 1, //1.1版
kEAGLRenderingAPIOpenGLES2 = 2 //2.0版
}typedef NSUInteger EAGLRenderingAPI;
以iPhone代码为例,你可以通过以下方式判断用户设备所支持的OpenGL ES版本,如果支持2.0,就使用2.0进行渲染;如果仅支持1.1,则使用1.1版进行渲染:
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2; //默认优先使用2.0版
m_context = [[EAGLContext alloc] initWithAPI:api]; //使用2.0版初始化EAGLContext
if (!m_context ) { //使用2.0版初始化EAGLContext失败
api = kEAGLRenderingAPIOpenGLES1; //将API设为1.1版
m_context = [[EAGLContext alloc] initWithAPI:api];//使用1.1版初始化EAGLContext
}
if (!m_context || ![EAGLContext setCurrentContext:m_context]) { //1.1版初始化失败,则释放内存
[self release];
return nil;
}
if (api == kEAGLRenderingAPIOpenGLES1) {
//使用1.1版开始渲染
}
else {
//使用2.0版开始渲染
}
2.你想让你的OpenGL ES程序跨手机平台运行么?Android、iPhone、windows phone手机系统是当前最主流的手机系统,如何才能让我们编写出来的程序可以跨平台运行呢?好消息是,这三个平台都支持OpenGL ES,而且都支持C++语言。也许你明白了,方法就是通过C++来封装OpenGL ES,尽量少用特定平台的耦合代码。这样我们就可以将封装的OpenGL
ES引擎在不同的手机平台的使用,而且仅需要修改特定平台连接OpenGL ES的代码即可。
3.入门常见代码解析
3.1创建渲染缓冲区
GLuint m_renderbuffer;//创建一个渲染缓冲区对象
glGenRenderbuffers(1, &m_renderbuffer);//创建一个渲染缓冲区对象
glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);//将该渲染缓冲区对象绑定到管线上
3.2创建帧缓冲区
GLuint m_framebuffer;//创建一个帧缓冲区对象
glGenFramebuffers(1, &m_framebuffer);//创建一个帧染缓冲区对象
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);//将该帧染缓冲区对象绑定到管线上
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer);//将创建的渲染缓冲区绑定到帧缓冲区上,并使用颜色填充
3.3设置视口
glViewport(0, 0, width, height);//定义视口大小,说白了就是OpenGL ES窗口大小
3.4创建着色器
3.4.1创建一个空着色器
GLuint shaderHandle = glCreateShader(shaderType);//shaderType代表着色器的类型,可以是GL_VERTEX_SHADER(顶点着色器)或GL_FRAGMENT_SHADER(片元着色器)
3.4.2指定着色器源代码
glShaderSource(shaderHandle, 1, &source, 0);// source代表要执行的源代码字符串数组,1表示源代码字符串数组的字符串个数是一个,0表示源代码字符串长度数组的个数为0个
3.4.3编译着色器
glCompileShader(shaderHandle);//编译着色器
3.4.4检查编译是否成功
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);//查看编译着色器是否成功,可选的查询状态有L_DELETE_STATUS,GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, GL_SHADER_SOURCE_LENGTH
//如果编译出错,则记录出错信息
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
std::cout << messages;
exit(1);
}
3.5创建渲染源程序
3.5.1创建一个空源程序
GLuint programHandle = glCreateProgram();//创建一个渲染程序
3.5.2向源程序中添加着色器
glAttachShader(programHandle, shaderHandle);//将着色器添加到程序中
3.5.3链接源程序
glLinkProgram(programHandle);//你可能添加了多个着色器,链接程序
3.5.4检查链接程序是否成功
GLint linkSuccess;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);//查看连接是否成功
//链接失败记录失败信息
if (linkSuccess == GL_FALSE) {
GLchar message[256];
glGetProgramInfoLog(programHandle, sizeof(message), 0, &message[0]);
std::cout << message;
exit(1);
}
3.6顶点结构体
//此处定义了一个代表顶点的结构体,内部包含一个有两个点(x,y)组成的顶点的位置信息,和一个四个值(r, g, b, a)表示的颜色信息
struct Vertex{
float Position[2];
float Color[4];
};
//创建顶点数组,里面有6个顶点信息
const Vertex vertices[] = {
{{-0.5, -0.866}, {0.5, 1, 0.5, 1}},
{{0.5, -0.866}, {0.2, 0.6, 0.5, 1}},
{{0, 1}, {0.6, 0.1, 0.8, 1}},
{{0.5, -0.866}, {0.5, 0.5, 0.5, 1}},
{{1.5, -0.866}, {0.5, 0.5, 0.5, 1}},
{{1, 0.4}, {0.5, 0.5, 0.5, 1}}
};
3.7着色器
3.7.1顶点着色器
#define STRINGIFY(A) #A
const char *SimpleVertexShader = STRINGIFY(
attribute vec4 Position;//位置,vec4说明有4个点组成,attribute表示属性,由程序提供输入值
attribute vec4 SourceColor;//源颜色,RGBA
varying vec4 DestinationColor;//目标颜色,输出值,用来传递到片元着色器,vary表示可变传出变量
uniform mat4 Projection;//投影矩阵,mat4表示一个4*4的矩阵,uniform表示统一的,不变的,每个顶点都是固定的这个值
uniform mat4 Modelview;//模型矩阵
void main(void){
DestinationColor = SourceColor;//简单的将源颜色赋给目标颜色
gl_Position = Projection * Modelview * Position;//通过矩阵乘法获得目标位置,gl_Position是OpenGL ES内定的值,必须指定
}
);
3.7.2片元着色器
const char *SimpleFragmentShader = STRINGIFY(
varying lowp vec4 DestinationColor;//由顶点着色器传入,lowp表示低精度
void main(void){
gl_FragColor = DestinationColor;//片元颜色,gl_FragColor也是OpenGL ES内定的,必须指定
}
);
3.8开始渲染
3.8.1填充(清理)屏幕
glClearColor(0.1f, 0.9f, 0.5f, 1);//指定填充屏幕的RGBA值
glClear(GL_COLOR_BUFFER_BIT);//指定要清除哪些缓冲区,GL_COLOR_BUFFER_BIT表示颜色缓冲区,GL_DEPTH_BUFFER_BIT表示深度缓冲区,GL_STENCIL_BUFFER_BIT表示模板缓冲区
3.8.2从着色器代码中获取属性信息
GLuint m_simpleProgram = programHandle;
GLuint positionSlot = glGetAttribLocation(m_simpleProgram, "Position");//从着色器源程序中的顶点着色器中获取Position属性
GLuint colorSlot = glGetAttribLocation(m_simpleProgram, "SourceColor");//从着色器源程序中的顶点着色器中获取SourceColor属性
3.8.3开启顶点属性数组
glEnableVertexAttribArray(positionSlot);
glEnableVertexAttribArray(colorSlot);
3.8.4为着色器属性赋值
GLsizei stride = sizeof(Vertex);//单个顶点的数据长度
const GLvoid *pCoords = &vertices[0].Position[0];//顶点数组中的位置数组首地址
const GLvoid *pColors = &vertices[0].Color[0];/顶点数组中的颜色数组首地址
glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, pCoords);//为顶点着色器位置信息赋值,positionSlot表示顶点着色器位置属性(即,Position);2表示每一个顶点信息由几个值组成,这个值必须位1,2,3或4;GL_FLOAT表示顶点信息的数据类型;GL_FALSE表示不要将数据类型标准化(即fixed-point);stride表示数组中每个元素的长度;pCoords表示数组的首地址
glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);//同上
3.8.5渲染顶点
GLsizei vertexCount = sizeof(vertices)/sizeof(Vertex);//顶点个数
glDrawArrays(GL_TRIANGLES, 0, vertexCount);//将顶点数组使用三角形渲染,GL_TRIANGLES表示三角形, 0表示数组第一个值的位置,vertexCount表示数组长度
3.8.6渲染完毕,关闭顶点属性数组
glDisableVertexAttribArray(positionSlot);
glDisableVertexAttribArray(colorSlot);
4.OpenGL 1.1和2.0在编程上的区别
4.1函数命名上的区别
1.1版API函数和宏末尾通常都为加上OES(即OpenglES的缩写),2.0版本基本上都把这个后缀名给去掉了,如:
1.1API函数和宏:glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_renderbuffer);
2.0API函数和宏:glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
4.2渲染方式不同
1.1版是基于不可编程管线,2.0版是基于可编程管线的,明显的差别是1.1不支持着色器而2.0支持着色器,如下:
在1.1版将顶点渲染到屏幕上一般这样写:
glMatrixMode(GL_PROJECTION);
const float maxX = 2;
const float maxY = 3;
glOrthof(-maxX, maxX, -maxY, maxY, -1, 1);
glMatrixMode(GL_MODELVIEW);
2.0版支持着色器,就不再这么渲染顶点了。将顶点属性和变换方式全部放在顶点着色器和片元着色器中,然后程序中通过着色器来渲染
4.3编写同样的程序API不同
如,同样是激活和关闭顶点数组,在1.1中是glEnableClientState(GL_VERTEX_ARRAY);和glDisableClientState(GL_VERTEX_ARRAY);
但在2.0中,就变成了:glEnableVertexAttribArray(*);和glDisableVertexAttribArray(*);
差别的来源就在于1.1不使用着色器,而2.0使用着色器。
4.4编程难易程度不同。
1.1是基于不可编程管线的,因此,管线的各个组件都是写好的,我们仅需要调用即可。而2.0是基于可编程管线的,灵活性大大增加了,但是编写的难度和复杂度也增加了,因为什么功能都得自己写了。
5.着色器的使用流程
刚开始学习OpenGL ES2.0,对其着色器十分不感冒,什么是着色器,着色器该怎么使用,着色器包含哪些内容呢?
着色器就是一段包含着色信息的源代码字符串。通常着色器分为顶点着色器(Vertex Shader)和片元着色器(Fragment Shader),两个着色器分别写在不同的文件中,文件没有固定的后缀名,可以根据你自己的爱好写,但是最好能区别文件中写的是顶点着色器还是片元着色器,不然时间长了自己都不知道哪个文件中写的是什么信息了。如你可以给你的顶点着色器后缀名命名为:vert, ver, v, vsh等,给你的片元着色器后缀名命名为:frag, fra, f, fsh等。
着色器源代码和OpenGL源代码不是一起编译的,所以要特别强调我刚才说的“着色器是一段包含着色信息的源代码字符串”。所以,OpenGL源代码肯定是和工程一起编译的,但是着色器源代码是在运行期编译的。你可能会问,着色器的源代码是一个字符串怎么编译呢?所以OpenGL
ES提供了一套运行期动态编译的流程:
(1)创建着色器:glCreateShader
(2)指定着色器源代码字符串:glShaderSource
(3)编译着色器:glCompileShader
(4)创建着色器可执行程序:glCompileShader
(5)向可执行程序中添加着色器:glAttachShader
(6)链接可执行程序:glLinkProgram
OpenGL ES入门详解的更多相关文章
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- SQL注入攻防入门详解
=============安全性篇目录============== 本文转载 毕业开始从事winfrm到今年转到 web ,在码农届已经足足混了快接近3年了,但是对安全方面的知识依旧薄弱,事实上是没机 ...
- SQL注入攻防入门详解(2)
SQL注入攻防入门详解 =============安全性篇目录============== 毕业开始从事winfrm到今年转到 web ,在码农届已经足足混了快接近3年了,但是对安全方面的知识依旧薄弱 ...
- Quartz 入门详解
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用.Quartz可以用来创建简单或为运行十个,百个, ...
- Redis快速入门详解
Redis入门详解 Redis简介 Redis安装 Redis配置 Redis数据类型 Redis功能 持久化 主从复制 事务支持 发布订阅 管道 虚拟内存 Redis性能 Redis部署 Redis ...
- [转]SQL注入攻防入门详解
原文地址:http://www.cnblogs.com/heyuquan/archive/2012/10/31/2748577.html =============安全性篇目录============ ...
- [置顶]
xamarin android toolbar(踩坑完全入门详解)
网上关于toolbar的教程有很多,很多新手,在使用toolbar的时候踩坑实在太多了,不好好总结一下,实在浪费.如果你想学习toolbar,你肯定会去去搜索androd toolbar,既然你能看到 ...
- 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权
原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...
- webpack入门详解
webpack入门详解(基于webpack 3.5.4 2017-8-22) webpack常用命令: webpack --display-error-details //执行打包 webpa ...
随机推荐
- 模式匹配之sift--- sift图像特征提取与匹配算法代码
sift,The Scale Invariant Feature Transform ,尺度不变特征变换,是检测图像中具有唯一性.对图像平移.旋转.缩放.甚至仿射变换(如从不同角度拍摄图片)保持不变性 ...
- ajax 实现三级联动下拉菜单
ajax 实现三级联动,相当于写了一个小插件,用的时候直接拿过来用就可以了,这里我用了数据库中的chinastates表, 数据库内容很多,三级联动里的地区名称都在里面,采用的是代号副代号的方式 比如 ...
- EasyHLS直播在Linux非root用户运行时出现无法写文件的问题解决mkdir 0777
今天在Github上收到一个用户反馈的EasyHLS在linux上非root用户调用时,无法写目录的问题:https://github.com/EasyDarwin/EasyHLS/issues/3, ...
- ZOJ 3551 Bloodsucker <概率DP>
题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3551 题意:开始有N-1个人和一个吸血鬼, 每天有两个生物见面,当人 ...
- Hibernate中的Sesson操作
一.Session概述 Session是应用程序与数据库之间的一个会话,是Hibernate运作的中心,持久层操作的基础,相当于JDBC中的Connection.Session对象是通过Session ...
- ElasticSearch(十三) bulk api奇特的json格式的原因
bulk api的语法 正常的语法: {"action": {"meta"}}\n {"data"}\n {"action&quo ...
- A桶中有多少水?
如果你能算出桶中有多少水,我便许你下山去玩.有一天,老和尚让小和尚将A桶的水挑到B桶去,可是小和尚却想下山玩,不愿意挑水,老和尚便说:”如果你能够根据我的提示算出A桶中有多少升水,我便许你下山去玩.” ...
- [P2769] 猴子上树
题目描述 在猴村有一条笔直的山路,这条山路很窄,宽度忽略不计.有 n只猴子正站在山路上静静地观望今天来参加比赛的各位同学.用一个正整数Xi表示第i只猴子所站位置,任意两只猴子的所站位置互不相同.在这条 ...
- 项目中一个普通的Java类如何获取serviceimpl实现类(二)
HbOnLineConfigServiceImpl hbOnlineService=(HbOnLineConfigServiceImpl) WebContextFactoryUtil.getBean( ...
- linux apache 用户认证:
root@ubuntu:/# htpasswd -c /etc/apache2/password zhangsan (-c表示要创建一个password密码文件,文件存放目录是/etc/apache2 ...