OpenGL ES 入门之旅--OpenGL ES快速了解GLKit

栏目: 后端 · 发布时间: 5年前

内容简介:OpenGL ES (OpenGL for Embedded Systems) 是以⼿手持和嵌入式为⽬标的⾼级3D图形应用程序编程接⼝(API). OpenGL ES 是目前智能手机中占据统治地位的图形API.⽀持的平台: iOS, Andriod , BlackBerry ,bada ,Linux ,Windows.OpenGL ES 开放式图形库(OpenGL的)用于可视化的⼆维和三维数据。它是一个多功能开放标准图形库,⽀持2D和3D数字内容创建,机械和建筑设计,虚拟原型设计,飞⾏模拟,视频游戏等应用程

OpenGL ES (OpenGL for Embedded Systems) 是以⼿手持和嵌入式为⽬标的⾼级3D图形应用程序编程接⼝(API). OpenGL ES 是目前智能手机中占据统治地位的图形API.⽀持的平台: iOS, Andriod , BlackBerry ,bada ,Linux ,Windows.

OpenGL ES 开放式图形库(OpenGL的)用于可视化的⼆维和三维数据。它是一个多功能开放标准图形库,⽀持2D和3D数字内容创建,机械和建筑设计,虚拟原型设计,飞⾏模拟,视频游戏等应用程序。您可以使⽤OpenGL配置3D图形管道并向其提交数据。顶点被变换和点亮,组合成图元,并光栅化以创建2D图像。OpenGL旨在将函数调用转换为可以发送到底层图形硬件的图形命令。由于此底层硬件专用于处理图形命令,因此OpenGL绘图通常⾮常快。 OpenGL for Embedded Systems(OpenGL ES)是OpenGL的简化版本,它消除了了冗余功能,提供了一个既易于学习又更易于在移动图形硬件中实现的库。

OpenGL ES 入门之旅--OpenGL ES快速了解GLKit

OpenGL ES允许应用程序利用底层图形处理器的强大功能。iOS设备上的GPU可以执行复杂的2D和3D绘图,以及最终图像中每个像素的复杂着⾊计算。

GLKit简介

GLKit 框架的设计目标是为了简化基于OpenGL / OpenGL ES 的应用开发。它的出现加快OpenGL ES或OpenGL应⽤程序开发。 使用数学库,背景纹理加载,预先创建的着色器效果,以及标准视图和视图控制器来实现渲染循环。 GLKit框架提供了功能和类,可以减少创建新的基于着色器的应用程序所需的工作量,或者支持依赖早期版本的OpenGL ES或OpenGL提供的固定函数顶点或⽚段处理的现有应用程序。 GLKit的功能: 1.加载纹理 2.提供高性能的数学运算 3.提供常⻅的着⾊器 4.提供视图以及视图控制器.

GLKit是Cocoa Touch以及多个其他的框架(包含UIKit)的一部分。GLKView和GLKViewController类是GLKit框架的一部分。 GLKView是Cocoa Touch UIView类的内建子类, 提供绘制场所(View); GLKViewController是UIViewController的内建子类(扩展于标准的UIKit 设计模式. ⽤于绘制视图内容的管理与呈现.)

GLKit的Hello World

新建Xcode工程,在ViewController.h中导入头文件

#import <GLKit/GLKit.h>
#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>
复制代码

并将ViewController继承更改为GLKViewController,将ViewController的view的继承更改为GLKView。

{
    EAGLContext *context;   //上下文
    GLKBaseEffect *cEffect; //完成着色器的工作
}
复制代码

1.OpenGL ES 相关初始化

-(void)setUpConfig
{
//1.初始化上下文&设置当前上下文
context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES3];
//判断context是否创建成功
if (!context) {
        NSLog(@"Create ES context Failed");
    }
//设置当前上下文
[EAGLContext setCurrentContext:context];
    
//2.获取GLKView & 设置context
GLKView *view =(GLKView *) self.view;
view.context = context;

//3.配置视图创建的渲染缓存区.
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
    
//4.设置背景颜色
glClearColor(1, 0, 0, 1.0);
}
复制代码

注解1: EAGLContext 是苹果iOS平台下实现OpenGLES 渲染层. kEAGLRenderingAPIOpenGLES1 = 1, 固定管线 kEAGLRenderingAPIOpenGLES2 = 2, kEAGLRenderingAPIOpenGLES3 = 3,

注解2: (1). drawableColorFormat: 颜色缓存区格式. 简介: OpenGL ES 有一个缓存区,它用以存储将在屏幕中显示的颜色。你可以使用其属性来设置缓冲区中的每个像素的颜色格式。 GLKViewDrawableColorFormatRGBA8888 = 0, 默认缓存区的每个像素的最小组成部分(RGBA)使用8个bit,(所以每个像素4个字节,4*8个bit)。 GLKViewDrawableColorFormatRGB565, 如果你的APP允许更小范围的颜色,即可设置这个。会让你的APP消耗更小的资源(内存和处理时间)

(2). drawableDepthFormat: 深度缓存区格式 GLKViewDrawableDepthFormatNone = 0,意味着完全没有深度缓冲区 GLKViewDrawableDepthFormat16, GLKViewDrawableDepthFormat24, 如果你要使用这个属性(一般用于3D游戏),你应该选择GLKViewDrawableDepthFormat16或GLKViewDrawableDepthFormat24。这里的差别是使用GLKViewDrawableDepthFormat16将消耗更少的资源

2.加载顶点/纹理坐标数据

//1.设置顶点数组(顶点坐标,纹理坐标)
 /*
纹理坐标系取值范围[0,1];原点是左下角(0,0);
故而(0,0)是纹理图像的左下角, 点(1,1)是右上角.
*/
GLfloat vertexData[] = {
        0.5, -0.5, 0.0f,    1.0f, 0.0f, //右下
        0.5, 0.5, -0.0f,    1.0f, 1.0f, //右上
        -0.5, 0.5, 0.0f,    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).创建顶点缓存区标识符ID
GLuint bufferID;
glGenBuffers(1, &bufferID);
//(2).绑定顶点缓存区.(明确作用)
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
//(3).将顶点数组的数据copy到顶点缓存区中(GPU显存中)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
    
//3.打开读取通道.
//顶点坐标数据
glEnableVertexAttribArray(GLKVertexAttribPosition);
 /*
     typedef NS_ENUM(GLint, GLKVertexAttrib)
     {
     GLKVertexAttribPosition,顶点
     GLKVertexAttribNormal,法线
     GLKVertexAttribColor,颜色值
     GLKVertexAttribTexCoord0,纹理0
     GLKVertexAttribTexCoord1 纹理1
     } NS_ENUM_AVAILABLE(10_8, 5_0);
     */
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
//纹理坐标数据
//打开对应attribute开关
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
复制代码

注解1: 顶点数组: 开发者可以选择设定函数指针,在调用绘制方法的时候,直接由内存传入顶点数据,也就是说这部分数据之前是存储在内存当中的,被称为顶点数组。

顶点缓存区: 性能更高的做法是,提前分配一块显存,将顶点数据预先传入到显存当中。这部分的显存,就被称为顶点缓存区。 注解2: (1)在iOS中, 默认情况下,出于性能考虑,所有顶点着色器的属性(Attribute)变量都是关闭的. 意味着,顶点数据在着色器端(服务端)是不可用的. 即使你已经使用glBufferData方法,将顶点数据从内存拷贝到顶点缓存区中(GPU显存中). 所以, 必须由glEnableVertexAttribArray 方法打开通道.指定访问属性.才能让顶点着色器能够访问到从CPU复制到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。

3.加载纹理数据(使用GLBaseEffect)

//1.获取纹理图片路径
NSString * filepath = [[NSBundle mainBundle] pathForResource:@"shiyuan1" ofType:@"jpg"];
//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;
复制代码

4.绘制视图的内容

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

绘制结果:

OpenGL ES 入门之旅--OpenGL ES快速了解GLKit

下面用思维导图的形式做个OpenGL ES GLKit 加载图片的总结:

OpenGL ES 入门之旅--OpenGL ES快速了解GLKit

常用API解析

1.GLKView

GLKView 使⽤用OpenGL ES 绘制内容的视图默认实现: 1.初始化新视图

- (instancetype)initWithFrame:(CGRect)frame context:(EAGLContext *)context;
复制代码

2.视图代理

@property (nullable, nonatomic, assign) IBOutlet id <GLKViewDelegate> delegate;
复制代码

3.绘制视图内容时使用的OpenGL ES 上下文

@property (nonatomic, retain) EAGLContext *context;
复制代码

4.配置帧缓存区对象

drawableColorFormat 颜⾊渲染缓存区格式
/*
GLKViewDrawableColorFormatRGBA8888 = 0,
GLKViewDrawableColorFormatRGB565,
GLKViewDrawableColorFormatSRGBA8888,
*/
drawableDepthFormat 深度渲染缓存区格式
/*
GLKViewDrawableDepthFormatNone = 0,
GLKViewDrawableDepthFormat16,
GLKViewDrawableDepthFormat24,
*/
drawableStencilFormat 模板渲染缓存区的格式
/*
GLKViewDrawableStencilFormatNone = 0,
GLKViewDrawableStencilFormat8,
*/
drawableMultisample 多重采样缓存区的格式
/*
GLKViewDrawableMultisampleNone = 0,
GLKViewDrawableMultisample4X,
*/
复制代码

5.帧缓存区属性

drawableHeight 底层缓存区对象的⾼度(以像素为单位)
drawableWidth 底层缓存区对象的宽度(以像素为单位)
复制代码

6.将底层FrameBuffer 对象绑定到OpenGL ES

- (void)bindDrawable;
复制代码

7.删除与视图关联的可绘制对象/删除视图FrameBuffer对象

- (void)deleteDrawable;
复制代码

8.绘制视图内容并将其作为新图像对象返回

@property (readonly, strong) UIImage *snapshot;
复制代码

9.布尔值(BOOL),指定视图是否响应使得视图内容无效的消息

@property (nonatomic) BOOL enableSetNeedsDisplay;
复制代码

10.立即重绘视图内容

- (void)display;
复制代码

11.绘制视图内容(必须实现代理)

//GLKViewDelegate ⽤用于GLKView 对象回调⽅方法
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect;
复制代码

2. GLKViewController

GLKViewController 管理OpenGL ES 渲染循环的视图控制器 1.视图控制器的代理

@property (nullable, nonatomic, assign) IBOutlet id <GLKViewControllerDelegate> delegate;
复制代码

2.配置视图的帧速率

//视图控制器调用视图以及更新视图内容的速率
@property (nonatomic) NSInteger preferredFramesPerSecond;
//视图控制器调用视图以及更新其内容的实际速率
@property (nonatomic, readonly) NSInteger framesPerSecond;
复制代码

3.控制帧更新

//Bool值,渲染循环是否已暂停
@property (nonatomic, getter=isPaused) BOOL paused;
//Bool值,当前程序重新激活活动状态时视图控制器是否自动暂停循环渲染
@property (nonatomic) BOOL pauseOnWillResignActive;
//Bool值,当前程序变为活动状态时视图控制器是否自动恢复呈现渲染
@property (nonatomic) BOOL resumeOnDidBecomeActive;
复制代码

4.获取有关视图view的更新信息

//视图控制器自创建以来发送的帧更新数
@property (nonatomic, readonly) NSInteger framesDisplayed;
//⾃视图控制器第⼀次恢复发送更新事件以来经过的时间量
@property (nonatomic, readonly) NSTimeInterval timeSinceFirstResume;
//自上次视图控制器恢复发送更新事件以来更新的时间量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastResume;
//⾃上次视图控制器调用委托⽅法以及经过的时间量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastUpdate;
//⾃上次视图控制器调用视图display 方法以来经过的时间量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastDraw;
复制代码

5.渲染循环回调方法--更新视图内容,处理更新事件, 在这里,其实系统还有一个方法用于更新视图:- (void)update;

//在显示每个帧之前调用
- (void)glkViewControllerUpdate:(GLKViewController *)controller;
复制代码

注: 如果不对GLKViewController进行子类化,则会调用glkViewControllerUpdate进行视图更新,如果GLKViewController被子类化,并且手动实现了- (void)update;则此时就不会调用glkViewControllerUpdate,相当于update覆盖了glkViewControllerUpdate,其实本质上update和glkViewControllerUpdate是相同的。

6.暂停/恢复通知

//在渲染循环暂停或者恢复之前调用
- (void)glkViewController:(GLKViewController *)controller willPause:(BOOL)pause;
复制代码

3.GLKit 纹理加载GLTextureLoader

GLKTextureInfo类创建OpenGL纹理信息。该类包含以下属性:

name : OpenGL上下文中纹理名称 target : 纹理绑定的目标 height: 加载的纹理高度 width : 加载的纹理宽度 textureOrigin : 加载纹理中的原点位置 alphaState : 加载纹理中alpha分量状态

GLTextureLoader 简化从各种资源文件中加载纹理:

  1. 初始化
//初始化一个新的纹理加载到对象中
- (instancetype)initWithSharegroup:(EAGLSharegroup *)sharegroup;
//初始化一个新的纹理加载对象
- (instancetype)initWithShareContext:(NSOpenGLContext *)context;
复制代码

2.从文件资源中加载纹理

//从文件加载2D纹理图像并从数据中创建新的纹理
+ (nullable GLKTextureInfo *)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options  error:(NSError * __nullable * __nullable)outError; 
//从文件中异步加载2D纹理图像,并根据数据创建新纹理
- (void)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block; 
复制代码

3.从URL地址中加载纹理

//用URL加载2D纹理图像并从数据中创建新的纹理
+ (nullable GLKTextureInfo *)textureWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//用URL异步加载2D纹理图像,并根据数据创建新纹理
- (void)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
复制代码

4.从内存中数据创建纹理

//从内存空间加载2D纹理图像并从数据中创建新的纹理
+ (nullable GLKTextureInfo *)textureWithContentsOfData:(NSData *)data options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//从内存空间异步加载2D纹理图像,并根据数据创建新纹理
- (void)textureWithContentsOfData:(NSData *)data options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
复制代码

5.从CGImages创建纹理

//从Quartz加载2D纹理图像并从数据中创建新的纹理
+ (nullable GLKTextureInfo *)textureWithCGImage:(CGImageRef)cgImage options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//从Quartz异步加载2D纹理图像,并根据数据创建新纹理
- (void)textureWithCGImage:(CGImageRef)cgImage options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;

复制代码

6.从URL加载多维数据创建纹理

//从单个URL加载⽴方体贴图纹理图像,并根据数据创建新纹理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//从单个URL异步加载⽴方体贴图纹理图像,并根据数据创建新纹理
- (void)cubeMapWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
复制代码

7.从文件资源加载多维数据创建纹理

//从单个文件加载⽴方体贴图纹理对象,并从数据中创建新纹理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//从单个文件异步立方体贴图纹理图像,并根据数据创建新纹理
- (void)cubeMapWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
//从一系列文件加载立方体贴图纹理图像.并根据数据创建新的纹理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfFiles:(NSArray<id> *)paths options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//从一系列文件异步立方体贴图纹理图像,并根据数据创建新纹理
- (void)cubeMapWithContentsOfFiles:(NSArray<id> *)paths options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
复制代码

4.GLKit光照GLKBaseEffect

1.命名Effect

//给Effect(效果)命名
 NSString  *label; 
复制代码

2.配置模型视图转换

//绑定效果时应用于顶点数据的模型视图,投影和纹理变换
GLKEffectPropertyTransform  *transform;
复制代码

3.配置光照效果

//⽤于计算每个片段的光照策略,
GLKLightingType  lightingType;

注:
GLKLightingTypePerVertex 表示在三⻆形中每个顶点执⾏光照计算,然后在三角形进行插值。
GLKLightingTypePerPixel 表示光照计算的输⼊在三角形内插入,并且在每个片段执行光照计算。
复制代码

4.配置光照

//布尔值,表示为基元的两侧计算光照
GLboolean  lightModelTwoSided;
//计算渲染图元光照使⽤用的材质属性
GLKEffectPropertyMaterial *material;  
//环境颜色,应⽤效果渲染的所有图元
GLKVector4  lightModelAmbientColor;
//场景中第一个光照属性,第二个光照属性,第三个光照属性
GLKEffectPropertyLight   *light0, *light1, *light2; 
复制代码

5.配置纹理

//第⼀个纹理属性,第二个纹理属性
GLKEffectPropertyTexture  *texture2d0, *texture2d1;
//纹理应⽤于渲染图元的顺序
NSArray<GLKEffectPropertyTexture*> *textureOrder; 
复制代码

6.配置雾化

//应用于场景的雾属性
GLKEffectPropertyFog  *fog;  
复制代码

7.配置颜色信息

//布尔值,表示计算光照与材质交互时是否使用颜色顶点属性
GLboolean  colorMaterialEnabled;
//布尔值,指示是否使用常量颜⾊
GLboolean  useConstantColor;
//不提供每个顶点颜色数据时使用常量颜⾊
GLKVector4  constantColor; 
复制代码

8.准备绘制效果

//准备渲染效果
- (void) prepareToDraw;
复制代码

至此 OpenGL ES GLKit的常用API基本就是这些,后续还会继续补充进来。如有书写错误,注释错误,方法使用错误还请指出。THX。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Black Box Society

The Black Box Society

Frank Pasquale / Harvard University Press / 2015-1-5 / USD 35.00

Every day, corporations are connecting the dots about our personal behavior—silently scrutinizing clues left behind by our work habits and Internet use. The data compiled and portraits created are inc......一起来看看 《The Black Box Society》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试