OpenGL ES入门详解

来源:互联网 发布:算法设计与分析(第2版) 编辑:程序博客网 时间:2024/05/16 07:38
   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


来源:http://blog.csdn.net/wangyuchun_799/article/details/7736928

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 逆战下载的时候显示文件损坏怎么办 移动公司买手机送话费套路怎么办 开通京东白条身份信息被占用怎么办 丰巢快递柜把东西寄丢了怎么办? 圆通快递把我寄的东西弄丢了怎么办 快递把我寄出去的东西弄丢了怎么办 京东被盗刷都是到付怎么办 订机票时护照号错了怎么办 请问网上不小心点了扣话费了怎么办 不小心被中国移动扣了话费怎么办 京东买东西已经付款了说无货怎么办 不小心提交了两次中信信用卡怎么办 淘宝买东西扣了银行卡两次钱怎么办 拼多多同一个订单支付了两次怎么办 京东手机号服务密码忘记了怎么办 京东买的东西转手给别人保修怎么办 改了无线网密码还是上不去网怎么办 买的京东e卡丢了怎么办 已认证未抵扣的发票发生退货怎么办 办的消费卡不给退怎么办 银行卡密码忘了手机号也换了怎么办 公务卡在当当购物的刷卡单怎么办 杭州市网签提示住宅均价异常怎么办 吃鸡账号没有绑定手机就买了怎么办 微信绑定的银行卡密码错误怎么办 淘宝单张券已领取达上限怎么办 去办公室给领导送礼总有人怎么办 招行信用卡临时额度到期后怎么办 中银e令不想用了怎么办 中银e令密码忘了怎么办 银行卡预留手机号改了支付宝怎么办 手机一直收到支付验证码短信怎么办 微信绑定银行卡手机号码换了怎么办 银行卡网银登录输错密码锁了怎么办 中行信用卡主付卡的付卡怎么办停 在苏宁网购的移动空调要退货怎么办 单位发的购物卡掉了怎么办 支付宝ofo退押金后余额怎么办 e招贷分期多还了怎么办 别人用我的手机号贷款不还怎么办 电脑文件夹怎么设密码忘记了怎么办