程序员音视频

OpenGL ES 基本知识

2019-11-26  本文已影响0人  Coder东
OpenGL ES(OpenGL for Embedded Systems)是以手持和嵌入式为目标的高级3D图形API。支持跨平台 iOS 安卓 BlackBerry(黑莓手机是指由加拿大Research In Motion Ltd公司推出的一种无线手持邮件解决终端设备)、bada(韩国三星电子自行开发的智能手机平台,底层为Linux核心)、Linux、Windows。

开放式图形库用于可视化的二维和三维数据。它是一个多功能开放标准图形库,支持2D和3D数字内容创建、机械和建筑设计、虚拟原型设计 、飞行模拟、视频游戏等应用程序。


OpenGL ES 3.0 图形管线.001.jpeg
  1. 矩阵变换位置
  2. 计算光照公式生成逐顶点颜色
  3. 生成/变换纹理坐标
    它可以用于执行自定义计算,实施新的变换,照明或者传统的固定功能所不允许的基于顶点的效果
attribute vec4  position ;
attribute vec2 textCoordinate;
uniform mat4 rotateMatrix;
varying lowp vec2 varyTextCoord;
void main(){
  varyTextCoord = textCoordinate;
  vec4 vPos = position;
  vPos = vPos * rotateMatrix;
  gl_Position = vPos;
}
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
    gl_FragColor = texture2D(colorMap,varyTextCoord);
}
逐片段操作.001.jpeg
GLKit框架
 ///创建OpenGL ES上下文并将其分配给从故事版加载的视图
    GLKView *view = (GLKView *)self.view;
    view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
    //配置视图创建的渲染缓冲区
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
    
    //启动多重采样
    view.drawableMultisample = GLKViewDrawableMultisample4X;
-(void)drawRect:(CGRect)rect
    {
        //清除帧缓冲区
        glClearColor(0.0f,0.0f,0.1f,1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        //使⽤用先前配置的纹理,着⾊色器器和顶点数组绘制
        glBindTexture(GL_TEXTURE_2D,_planetTexture);
        glUseProgram(_diffuseShading);
        glUniformMatrix4fv(_uniformModelViewProjectionMatrix,1,0,
        _modelViewProjectionMatrix.m);
        glBindVertexArrayOES(_planetMesh);
        glDrawElements(GL_TRIANGLE_STRIP,256,GL_UNSIGNED_SHORT);
    }
@interface GLKTextureInfo : NSObject <NSCopying>
{
@private
    GLuint                      name;  //OpenGL上下文中纹理名称
    GLenum                      target;  //纹理绑定的目标
    GLuint                      width;  //加载纹理的高度
    GLuint                      height;  //加载的纹理宽度
    GLuint                      depth;
    GLKTextureInfoAlphaState    alphaState;  //加载纹理中alpha分量状态
    GLKTextureInfoOrigin        textureOrigin; //加载纹理中的原点位置
    BOOL                        containsMipmaps;  //加载的纹理是否包含mip贴图
    GLuint                      mimapLevelCount;
    GLuint                      arrayLength;
}


- (instancetype)initWithFrame:(CGRect)frame context:(EAGLContext *)context;

视图的代理

@protocol GLKViewDelegate <NSObject>

@required
/*
 Required method for implementing GLKViewDelegate. This draw method variant should be used when not subclassing GLKView.
 This method will not be called if the GLKView object has been subclassed and implements -(void)drawRect:(CGRect)rect.
 */
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect;

配置帧缓冲区的对象和属性

@property (nonatomic, readonly) NSInteger drawableWidth; //底层缓存区对象的高度(以像素为单位)
@property (nonatomic, readonly) NSInteger drawableHeight;//底层缓存区对象的宽度(以像素为单位)

@property (nonatomic) GLKViewDrawableColorFormat drawableColorFormat; //颜色缓存区设置格式
@property (nonatomic) GLKViewDrawableDepthFormat drawableDepthFormat;//深度缓存区设置格式
@property (nonatomic) GLKViewDrawableStencilFormat drawableStencilFormat;//模板缓存区设置格式
@property (nonatomic) GLKViewDrawableMultisample drawableMultisample;//多重采样缓存区设置格式
1.context  绘制视图内容时使用的OpenGL ES上下文
2.bindDrawable 将底层FrameBuffer 对象绑定到OpenGL ES
3.enableSetNeedsDisplay 布尔值,指定视图是否影响应使得视图内容无效的消息
4.display 立即重绘视图内容
5.snapshot  绘制视图内容并将其作为新视图对象返回
deleteDrawable 删除与视图关联的可绘制对象
glkView:drawInRect: 绘制视图内容(必须实现代理)
@protocol GLKViewControllerDelegate <NSObject>

@required
/*
 Required method for implementing GLKViewControllerDelegate. This update method variant should be used
 when not subclassing GLKViewController. This method will not be called if the GLKViewController object
 has been subclassed and implements -(void)update.
 */
- (void)glkViewControllerUpdate:(GLKViewController *)controller;
/*
 For setting the desired frames per second at which the update and drawing will take place.
 The default is 30.
 */
@property (nonatomic) NSInteger preferredFramesPerSecond;  视图控制器调用视图以及更新视图内容的速率
/*
 The actual frames per second that was decided upon given the value for preferredFramesPerSecond
 and the screen for which the GLKView resides. The value chosen will be as close to
 preferredFramesPerSecond as possible, without exceeding the screen's refresh rate. This value
 does not account for dropped frames, so it is not a measurement of your statistical frames per
 second. It is the static value for which updates will take place.
 */
@property (nonatomic, readonly) NSInteger framesPerSecond; //视图控制器调用视图以及更新其内容的实际速率
@property (nonatomic, getter=isPaused) BOOL paused; //渲染是否已暂停
@property (nonatomic) BOOL pauseOnWillResignActive;  // 当前程序重新激活活动状态时视图控制器是否自动暂停渲染循环
@property (nonatomic) BOOL resumeOnDidBecomeActive; //程序变化为活跃状态时,是否自动恢复呈现循环

#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>

@interface ViewController ()
{
    EAGLContext *context;
    GLKBaseEffect *cEffect;
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
 
    //1.OpengGL ES 相关初始化
    [self setUpConfig];
    //2.加载顶点/纹理坐标数据
    [self setUpVertexData];
    
    //3.加载纹理数据(使用GLBaseEffect)
    [self setUpTexture];
}

#pragma mark -- OpenGL ES setUp

-(void)setUpTexture
{
   //1.获取纹理图片路径
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"girl" ofType:@"png"];
    //2.设置纹理参数
    //纹理坐标原点是左下角 ,但是图片显示原点应该在左上角
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
    
    GLKTextureInfo *textureInfo =[GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
    //3.使用苹果GLkit 提供GLKBaseEffect 完成着色器工作
    cEffect = [[GLKBaseEffect alloc]init];
    cEffect.texture2d0.enabled = GL_TRUE;
    cEffect.texture2d0.name = textureInfo.name;
    
}

-(void)setUpVertexData
{
    /*设置顶点数组(顶点坐标、纹理坐标)
     纹理坐标系取值范围【0,1】;
     原点是左下角(0,0)
     (1,1)右上角
     */
    //一个正方形两个三角形 6个顶点
    GLfloat verTexData[] = {
        0.5,-0.5,0.0,   1.0f,0.0,//右下
        0.5,0.5,0.0f,   1.0f,1.0f,//右上
        -0.5,0.5,0.0,   0.0f,1.0f,//左上角
        
        0.5,-0.5,0.0f,  1.0f,0.0f,//右下
        -0.5,0.5,0.0f,  0.0f,1.0f,// 左上
        -0.5,-0.5,0.0f, 0.0f,0.0f,//左下
        
    };
    /*
     顶点数组:开发者可以选择设定函数指针,在调用绘制方法的时候,直接右内存传入顶点数据,也就是说这部分数据之前是存储在内存当中的,被称为顶点数组
     顶点缓存区:性能更高的做法是,提前 分配一块显存,将顶点数据预先传入到显存中,这部分显存就被称为顶点缓冲区
     */
    
    //2.开辟顶点缓存区
    //(1)创建顶点缓存区标识符
    GLuint bufferID;
    glGenBuffers(1, &bufferID);
    //(2).绑定顶点缓存区(明确作用)
    glBindBuffer(GL_ARRAY_BUFFER, bufferID);
    //(3)将顶点数组的数据copy到顶点焕存区中(GPU显存中)
    glBufferData(GL_ARRAY_BUFFER, sizeof(verTexData), verTexData, GL_STATIC_DRAW);
    
    /*打开读取通道
     1.在iOS中,默认情况下,出于性能考虑,所有顶点着色器的属性(Atrribute)变量都是关闭的。
     顶点数据在着色器端(服务端)是不可用的,即使已经使用glBufferData方法,将顶点数据从内存拷贝到顶点缓存区(GPU显存中)
     所以必须由glEanbleVertexAttribArray 方法打开通道,指定访问属性。才能让顶点着色器能够访问到从CPUd复制到GPU的数据
     注意:数据在GPU端是否可见,即着色器能否读取到数据,由是否启用了对应的属性决定。这就是glEnableVertexAttribArray的功能,允许顶点着色器读取GPU(服务端)数据
     2.方法简介
     glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
     功能: 上传顶点数据到显存的方法(设置合适的方式从buffer里面读取数据)
     参数列表:
     index,指定要修改的顶点属性的索引值,例如
     size, 每次读取数量。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a),纹理则是2个.)
     type,指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。
     normalized,指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)
     stride,指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0
     ptr指定一个指针,指向数组中第一个顶点属性的第一个组件。初始值为0
     */
    //顶点坐标
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
    //纹理坐标数据
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
}

-(void)setUpConfig
{
    ///创建OpenGL ES上下文并将其分配给从故事版加载的视图
    GLKView *view = (GLKView *)self.view;
    //初始化上下文
    view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    
    /*配置视图创建的渲染缓冲区
    GLKViewDrawableColorFormatRGBA8888  = 0 默认缓存区的每个像素的最小组成部分(RGBA)使用8bit(所以每个像素4个字节,4*8bit)
    GLKViewDrawableColorFormatRGB565,
   如果你的APP允许更小范围的颜色,即可设置这个。会让你的APP消耗更小的资源(内存和处理时间)
    */
        view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;// 默认
        view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    /*
     GLKViewDrawableDepthFormatNone = 0 完全没有深度缓冲区
     GLKViewDrawableDepthFormat16
     如果你要使用这个属性(一般用于3D游戏),你应该选择
     或GLKViewDrawableDepthFormat24。这里的差别是使用GLKViewDrawableDepthFormat16 将消耗更少的资源
     view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
     */
    
    //启动多重采样
    //    view.drawableMultisample = GLKViewDrawableMultisample4X;
    //设置当前上下文
    [EAGLContext setCurrentContext:view.context];
    //    GLKView *view = (GLKView *)self.view;
    //    view.context = context;
    //设置背景颜色
    glClearColor(1.0, 1.0, 0, 1.0);
    
}

#pragma mark -- GLKViewDelegate
//绘制视图的内容
/*
 GLKView对象使其OpenGL ES上下文成为当前上下文,并将其framebuffer绑定为OpenGL ES呈现命令的目标。然后,委托方法应该绘制视图的内容。
*/
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    //清楚帧缓冲区
//    glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT );
 
    //2.绘制准备
    [cEffect prepareToDraw];
    
    //3.开始绘制
    glDrawArrays(GL_TRIANGLES, 0, 6);
    
}
上一篇下一篇

猜你喜欢

热点阅读