GLView是一系列类,旨在让iOS应用内使用OpenGL功能变得尽可能简单易行。
GLImage和GLImageView类使得在您的应用中加载和显示PVR格式图像和视频剪辑成为可能,无需了解任何OpenGL知识。下面将详细介绍PVR图像和视频的更多信息。
GLModel和GLModelView类允许您使用流行的WaveFront .obj格式加载3D模型并在视图中显示它,同样无需了解任何OpenGL知识。
GLView库是模块化的。如果您不想渲染3D模型,可以省略模型类,其余库仍然可以工作。如果您不感兴趣于加载和显示图像,只想为您设置基本的OpenGL上下文,可以省略图像和模型类。
注意:'支持'意味着库已经与该版本进行了测试。'兼容'意味着库应该在该iOS版本上工作(即它不依赖于任何不可用的SDK功能),但不再对其进行兼容性测试,可能需要调整或错误修复才能正确运行。
从版本1.5起,GLView需要ARC。如果您想在一个非ARC项目中使用GLView,只需将-fobjc-arc编译器标志添加到所有GLView类文件。为此,进入目标设置中的构建阶段选项卡,打开编译源文件组,在列表中双击所有与GLView相关的.m文件,并在弹出窗口中输入-fobjc-arc。
如果您想将整个项目转换为ARC,在GLUtils.m中注释掉#error行,然后在Xcode中运行Edit > Refactor > Convert to Objective-C ARC...工具,并确保所有希望使用ARC的文件都已被选中(包括所有GLView文件)。
要使用GLView,只需将类文件拖到您的项目中,并添加QuartzCore和OpenGLES框架。如果您使用的是可选的GZIP库,还需要添加libz.dylib。
GLView库目前包括以下类:
GLUtils - 这是一个由GLView库使用的有用类扩展和全局方法的集合。
GLView - 这是一个用于在屏幕上显示OpenGL图形的通用UIView子类。默认情况下,它不显示任何内容,但如果您熟悉OpenGL,您可以用来进行原始OpenGL绘图。
GLImage - 这是一个用于将图像文件加载为OpenGL纹理的类。它支持与UIImage相同的所有图像格式,以及许多PVR图像格式。
GLImageMap - 这是一个用于加载图像图快的类,也称为图像图库或精灵图。
GLImageView - 这是GLView的子类,专门设计用于显示GLImage。它的行为与UIImageView类似,接口也基本一致。
GLModel - 这是一个用于加载数字网格几何体,以便在GLView中渲染的类。目前它只支持Wavefront .obj文件和用于Apple GLEssentials示例代码的专用“WWDC2010”模型格式,但未来将支持其他格式。
GLModelView - 这是GLView的子类,专门设计以尽可能简单和容易地显示GLModel。
GLLight - 这个类表示光源,用于在GLModelView中照亮GLModel对象。
void CGRectGetGLCoords(CGRect rect, GLfloat *coords);
此方法用于将GLRect转换为OpenGL顶点。它接收一个指向包含8个GLfloat的数组的指针,并用该矩形4个角的位置坐标填充该数组。
这些方法扩展UIColor,使其更容易与OpenGL代码集成。
- (void)getGLComponents:(GLfloat *)rgba;
传递一个指向包含四个GLfloat的C数组的指针,此方法将填充颜色值的红色、绿色、蓝色和透明度组件。它与单色和RGB UIColor一起使用,但如果颜色包含模式图像或其他不支持的颜色格式则可能失败。
- (void)bindGLClearColor;
将UIColor绑定为当前OpenGL清除颜色。
- (void)bindGLBlendColor;
将UIColor绑定为当前OpenGL混合颜色。
- (void)bindGLColor;
将UIColor绑定为当前OpenGL颜色。
@property (nonatomic, assign) CGFloat fov;
这是垂直视野,以弧度为单位。默认值为零,表示正交投影(无透视),但将其设置为π/2(90度)以获得透视投影。
@property (nonatomic, assign) CGFloat near;
近裁剪面。OpenGL使用它来裁剪离摄像机太近的几何体。在正交投影模式下,此值可以是负数,但在透视模式下,值必须大于零。
@property (nonatomic, assign) CGFloat far;
远裁剪面。OpenGL使用它来裁剪离摄像机太远的几何体。减小远平面的值可以提高z缓冲器的精度并减少渲染伪影,因此尽可能将其设置得尽可能低(注意:它必须大于近值)。
@property (nonatomic, assign) NSTimeInterval frameInterval;
此属性控制视图动画的帧速率。默认值为1.0/60.0(每秒60帧)。如果动画变得不流畅,您可能希望将其降低到30 fps。
@property (nonatomic, assign) NSTimeInterval elapsedTime;
当动画视图时使用此属性。它表示从startAnimating方法首次被调用以来经过的总动画时间。当调用stop时不会重置,但您可以随时手动重置它,因为它是一个可读/写属性。
GLView具有以下方法
- (void)setUp
在 initWithCoder:
和 initWithFrame:
调用时被调用以初始化视图。覆盖此方法以在您自己的 GLView 子类中执行设置代码。请记住调用 [super setUp],否则视图将无法正确工作。
- (void)display;
如果您正在使用更新循环自行管理绘制,则可以调用此方法来立即调用 drawRect: 方法,而不是等待下一个 OS 帧更新。
- (void)drawRect:(CGRect)rect;
此方法(从 UIView 继承)负责绘制视图内容。默认实现不执行任何操作,但您可以在 GLView 子类中覆盖此方法以执行自己的 OpenGL 渲染逻辑。
- (void)bindFramebuffer;
此方法用于在尝试使用 OpenGL 命令进行任何绘制之前绑定 GLView。此方法在 drawRect:
方法之前自动调用,所以大多数情况下你不需要自己调用它。
- (BOOL)presentRenderbuffer;
调用此方法可更新视图并显示任何先前绘制命令的结果。此方法在 drawRect:
方法之后自动调用,所以大多数情况下你不需要自己调用它。
- (void)startAnimating;
开始视图的动画。这将每 60 秒调用一次 step:
方法,允许您对 OpenGL 几何体进行逐帧动画。
- (void)stopAnimating;
暂停动画。elapsedTime 属性不会自动重置,因此再次调用 startAnimating
会从停止的位置继续动画。
- (BOOL)isAnimating;
如果视图正在动画中返回 YES,如果不正在动画中返回 NO。
- (BOOL)shouldStopAnimating;
此方法用于在某些条件满足时自动停止动画。默认返回 NO,但可以由 GLView 的子类覆盖。例如,GLImageView 在动画图像序列结束时覆盖此方法以返回 YES。
- (void)step:(NSTimeInterval)dt;
在视图动画时每秒钟能够调用 60 次。dt 参数是自上次步骤以来的时间(以秒为单位)(这通常为 ~1/60 秒,根据您的渲染代码的复杂性和设备性能而定)。默认实现不执行任何操作,但您可以通过覆盖此方法来创建自己的动画逻辑。
- (UIImage *)snapshot;
此方法作为 UImage 返回 GLView 的当前内容(包括任何子视图)。请注意,调用此方法将始终使视图内容通过调用 drawRect: 方法重新渲染,即使视图最近已更新过。为支撑 GLView 的层也实现了 CALayer 的 renderInContext: 方法,允许您捕获包括 GLView 实例的任何视图层次结构。
@property (nonatomic, readonly) CGSize size;
图像的大小,以点为单位。与 UIImage 一样,在视网膜显示设备上,实际像素维度可能是大小的两倍,这取决于缩放属性。
@property (nonatomic, readonly) CGFloat scale;
图像缩放。对于在视网膜显示设备上的 2x 图像,此值将为 2.0。
@property (nonatomic, readonly) GLuint texture;
GLImage 使用的底层纹理 ID。您可以使用它来在您自己的绘图代码中绑定纹理,而不需要使用 bindTexture
方法。
@property (nonatomic, readonly) CGSize textureSize;
底层纹理的大小。纹理的维度总是 2 的幂。对于尺寸为 1.0(非视网膜)且具有 2 的幂维度的图像,这将与大小属性匹配。
@property (nonatomic, readonly) CGRect clipRect;
用于裁剪和调整纹理以适合图像 rect 的剪辑矩形。此矩形以纹理像素为单位测量,因此对于未裁剪的图像,clipRect 的大小将匹配 textureSize。
@property (nonatomic, readonly) CGRect contentRect;
用于指定要纹理化的图像部分的 content 矩形。此矩形以图像像素为单位测量。在大多数情况下,此矩形的大小将与图像大小匹配,且原点为 0,但是,如果图像内容已被从原始大小中裁剪掉,则 contentRect 可能小于由图像大小指定的边界。
@property (nonatomic, readonly) BOOL premultipliedAlpha;
具有半透明部分的图像可以采用预乘或非预乘的_alpha_。iOS在加载图像时通常使用预乘_alpha_,这是非-PVR图像的默认设置。使用苹果的命令行工具生成的PVR图像没有预乘_alpha_,因此默认情况下假设PVR图像没有预乘_alpha_,因此此属性将默认为NO。然而,一些工具可以选择生成带有预乘_alpha_的PVR图像,这通常建议这样做以避免图像不透明部分周围的奇异的黑色或白色光环。没有方法可以检测PVR图像是否使用了预乘_alpha_,因此如果您知道它是,或者当渲染图像时看起来不对劲,您可以使用imageWithPremultipliedAlpha:
方法切换此属性。有关更多详细信息,请参阅下面的“预乘_alpha_”部分。
@property (nonatomic, readonly) GLBlendMode blendMode;
blendMode属性确定在绘制图像时图像将与现有屏幕内容如何混合。您可以使用imageWithBlendMode:
方法更改此属性。此属性的数据类型为GLBlendMode,以下列出可能值
GLBlendModeScreen - 这类似于Photoshop中的屏幕混合模式 - 基础颜色变亮。
@property (nonatomic, readonly) const GLfloat *textureCoords;
用于渲染图像的纹理坐标。如果您需要使用OpenGL函数而不是使用drawAtPoint:
或drawInRect:
方法自行渲染图像,这些非常有用。textureCoords数组将始终包含8个有效的GLfloat值。
@property (nonatomic, readonly) const GLfloat *vertexCoords;
用于渲染图像的顶点坐标。如果您需要使用OpenGL函数而不是使用drawAtPoint:
或drawInRect:
方法自行渲染图像,这些非常有用。vertexCoords数组将始终包含8个有效的GLfloat值。
+ (GLImage *)imageNamed:(NSString *)nameOrPath;
此方法大致类似于等价的UIImage方法。nameOrPath参数指定的图像文件将被加载并返回。该图像也被缓存,因此对于任何后续对同一文件的imageNamed:
调用,将返回相同的图像副本。在内存不足的情况下,此缓存将被清除。使用@2x命名方案的Retina显示屏图像以及具有 ~ipad后缀的图像的行为与UIImage相同。
名称可以包含文件扩展名。如果没有,则假定.png。名称还可以包含完整或部分路径,而且与UIImage的版本不同,GLImage的imageNamed:
函数可以加载应用程序包以外的图像,例如从应用程序文档文件夹中。但是请注意,由于这些图像已被缓存,如果图像在应用程序运行期间可能被替换或删除,这种方式加载图像是不明智的,因为这可能会导致意外行为。
请注意:OpenGL纹理要求的尺寸必须是2的幂,例如8x128,32x64,128x128,512x256等。从版本1.2.2开始,GLImage可以加载尺寸不是2的幂的图像,并将自动将其放在最小的有效纹理尺寸内。然而,仍然建议在可能的情况下尽可能使用2的幂的图像,因为这可以避免视频内存的浪费。
+ (GLImage *)imageWithContentsOfFile:(NSString *)nameOrPath;
- (GLImage *)initWithContentsOfFile:(NSString *)nameOrPath;
这些方法从文件中加载GLImage。路径参数可以是完整的或部分路径。对于部分路径,假设路径相对于应用程序资源文件夹。如果省略了文件扩展名,则假定它是.png。使用@2x命名方案的Retina显示屏图像与UIImage的行为相同,具有~ipad后缀的图像也是如此。以这种方式加载的图像不会被以任何方式缓存或去重。
+ (GLImage *)imageWithUIImage:(UIImage *)image;
- (GLImage *)initWithUIImage:(UIImage *)image;
这些方法从现有的UIImage创建GLImage。保留UIImage的原始比例和方向。结果GLIImage格式将是一个32位未压缩的RGBA纹理。
+ (GLImage *)imageWithSize:(CGSize)size scale:(CGFloat)scale drawingBlock:(GLImageDrawingBlock)drawingBlock;
- (GLImage *)initWithSize:(CGSize)size scale:(CGFloat)scale drawingBlock:(GLImageDrawingBlock)drawingBlock;
这些方法允许您通过直接使用Core Graphics绘制内容来创建新的GLImage。前两个参数指定图像的大小和比例,第三个参数是一个阻塞函数,您可以使用它来进行绘图。该阻塞函数接受单个参数,即您要绘制到的CGContextRef。请参阅GLImage示例应用中的“绘图”标签以进行演示。
+ (GLImage *)imageWithData:(NSData *)data scale:(CGFloat)scale;
- (GLImage *)initWithData:(NSData *)data scale:(CGFloat)scale;
这些方法允许您从NSData对象创建GLImage。数据内容应与imageWithContentsOfFile:支持的格式之一中的图像文件相对应。图像大小和格式将自动从数据中提取。可以使用比例参数来指示图像针对的显示分辨率。
- (GLImage *)imageWithPremultipliedAlpha:(BOOL)premultipliedAlpha;
具有半透明部分的图像可以使用预乘或非预乘alpha。iOS在加载图像时通常使用预乘alpha,这是非PVR图像的默认值。使用Apple的命令行工具生成的PVR图像没有预乘alpha,因此对于PVR图像,假设图像没有预乘alpha。然而,某些工具具有生成具有预乘alpha的PVR图像的选项,通常推荐这样做,以避免图像不透明部分周围的奇怪的黑或白光环。但是,由于无法从文件格式检测到这一点,这些图像在使用GLImage加载时可能渲染不正确。为了纠正这一点,请使用此方法将值设置为YES以创建一个正确渲染的图像版本。有关更多详细信息,请参阅下面的“预乘alpha”部分。
- (GLImage *)imageWithBlendMode:(GLBlendMode)blendMode;
此方法可以用于创建使用不同混合模式的图像副本。有关不同混合模式的详细信息,请检查上面的blendMode属性描述。
- (GLImage *)imageWithOrientation:(UIImageOrientation)orientation;
如果您的图像被翻转或旋转以便适合较大的图像图,您可以更新此方法以更改显示时的方向。此方法不会改变图像像素,它只会影响通过drawAtPoint:和drawInRect:方法显示的方式。
- (GLImage *)imageWithClipRect:(CGRect)clipRect;
此方法可以用来设置图像的裁剪矩形。如果您正在加载一个PVR纹理图像,其中内容小于图像边界,但鉴于PVR格式的限制,图像文件必须是一个平方的边为2的幂的平方,这很有用。请注意,裁剪矩形以纹理像素为单位进行测量,而不是以图像坐标为单位,且不考虑缩放因子或之前的裁剪。您可以从图像的textureSize属性确定实际的纹理大小。注意:调整clipRect将相应地调整图像大小和contentRect,但是您可以通过在之后调用imageWithSize:和/或imageWithContentRect:来覆盖此操作。
- (GLImage *)imageWithContentRect:(CGRect)contentRect;
此方法可以用来设置图像的内容矩形。这在您想要操作图像的锚点或围绕图像的纹理部分添加填充时很有用。
- (GLImage *)imageWithScale:(CGFloat)scale;
此方法可以用来设置图像的比例。修改比例将自动相应地更新图像大小和contentRect,但不会实际更改图像像素。在极不可能的情况下,如果您想在未修改图像大小的情况下设置比例,可以在之后覆盖调用imageWithSize:以恢复原始大小。
- (GLImage *)imageWithSize:(CGSize)size;
本方法可用于设置图像大小。该方法实际上并不修改图像像素,它仅仅更改在使用 drawAtPoint:
方法绘制图像时的默认水平和垂直缩放系数。
- (void)bindTexture;
该方法用于在使用 OpenGL 绘图之前,绑定 GLImage 的底层 OpenGL 纹理。
- (void)drawAtPoint:(CGPoint)point;
该方法将在指定的点将图像绘制到当前绑定的 GLView 或 OpenGL 上下文中。
- (void)drawInRect:(CGRect)rect;
该方法将在当前绑定的 GLView 或 OpenGL 上下文中绘制图像,并将其拉伸以适应指定的 CGRect。
GLImageMap 类有以下方法
+ (GLImageMap *)imageMapWithContentsOfFile:(NSString *)nameOrPath;
- (GLImageMap *)initWithContentsOfFile:(NSString *)nameOrPath;
这些方法用于从文件创建一个 GLImageMap。参数可以是绝对路径或相对路径(相对路径假设在应用程序包内部)。如果省略了文件扩展名,则假设为 Xcode 5 .atlasc 文件(详见下文“使用 Xcode 5 / SpriteKit 纹理图集”),或 .plist。目前支持的唯一图像地图文件格式是 Xcode 5 / SpriteKit 纹理图集格式和 Cocos2D 精灵图格式,这些格式可以通过如 Zwoptex 或 TexturePacker 等工具导出。GLImageMap 完全支持旋转和修剪的图像以及图像别名。它会自动检测 @2x Retina 图像地图文件以及带有 ~ipad 后缀的文件。
+ (GLImageMap *)imageMapWithImage:(GLImage *)image data:(NSData *)data;
- (GLImageMap *)initWithImage:(GLImage *)image data:(NSData *)data;
这些方法用于从数据创建 GLImage。数据应表示图像地图文件的内容,格式应被 imageMapWithContentsOfFile:
方法所支持。如果图像参数为 nil,GLImageMap 将尝试从数据中指定的文件名定位纹理文件,但如果没有在应用程序包的根目录中找到图像文件,则可能无法找到它。在这种情况下,您可以提供要使用的 GLImage 作为图像地图图像,并且数据中指定的图像文件将被忽略。
- (NSInteger)imageCount;
此方法返回图像地图中的图像数量。
- (NSString *)imageNameAtIndex:(NSInteger)index;
此方法返回指定索引处的图像名。图像名按字母顺序排序,不一定反映它们在精灵图文件中的出现顺序。
- (GLImage *)imageAtIndex:(NSInteger)index;
- (GLImage *)objectAtIndexedSubscript:(NSInteger)index;
这些方法返回指定索引的图像地图图像。两种方法行为相同,但第二种方法的加入是为了支持对象索引,允许使用 spritemap[index]
语法访问精灵。图像地图图像按字母顺序排序,不一定反映它们在精灵图文件中的出现顺序。如果您希望按特定顺序访问图像,请将它们命名为数字,并用零填充到相同的长度。
- (GLImage *)imageNamed:(NSString *)name;
- (GLImage *)objectForKeyedSubscript:(NSString *)name;
这些方法返回指定名称的图像地图图像。两种方法行为相同,但第二种方法的加入是为了支持对象索引,允许使用 spritemap[@"spriteName"]
语法访问精灵。根据生成图像地图数据文件的工具,名称可能包含文件扩展名。如果您没有在名称参数中包含文件扩展名,则默认为 png。
GLImage 视图有以下属性
@property (nonatomic, strong) GLImage *image;
此方法用于在视图中设置和显示一个 GLImage。在绘制图像时,将尊重标准的 UIView contentMode
属性,以考虑它在视图内部的裁剪、拉伸和位置。
@property (nonatomic, strong) UIColor *blendColor;
(可选) 在渲染之前与图像混合的颜色。这可用于着色图像、修改其不透明度等。默认为白色。
@property (nonatomic, copy) NSArray *animationImages;
这用于指定要播放的图片序列。数组可以包含GLImages或文件名。如果提供了文件名,则图像将来自磁盘流,而不是预先加载。请参阅GLImage Demo示例应用的视频标签,以了解如何使用这种方法播放大型PVR视频序列,实现流畅的30fps性能和最小的内存消耗。
@property (nonatomic, assign) NSTimeInterval animationDuration;
动画图片序列将播放的持续时间。这以秒为单位,默认值为动画帧数除以30(即每秒30帧)。每次 animationImages 数组更新时,都会自动设置此值,因此在设置 animationImages 属性后,请务必记住设置此值。
@property (nonatomic, assign) NSInteger animationRepeatCount;
动画重复的次数。默认为零,这意味着动画将无限重复,直到调用 stopAnimating 方法。
@property (nonatomic, assign) CATransform3D imageTransform;
应用于图像的3D变换。这可以用来居中、缩放或旋转图像。使用此属性变换图像比使用 view.transform 或 view.layer.transform 属性变换整个视图更高效。
- (GLImageView *)initWithImage:(GLImage *)image;
此方法创建一个包含指定图像的GLImageView,并将视图帧设置为与图像大小匹配。
- (void)startAnimating;
继承自GLView,此方法开始 play animationImages 序列。回放始终从第一帧开始。当动画正在播放时调用 play 将重新从开头开始。
- (void)stopAnimating;
此方法停止动画序列。一旦停止,序列无法继续,只能从头开始。
- (BOOL)isAnimating;
此方法如果 animationImages 序列目前正在播放,则返回 YES。
+ (GLModel *)modelNamed:(NSString *)nameOrPath;
此方法通过指定的 nameOrPath 参数加载模型文件并返回一个 GLModel。该模型被缓存,因此对同一文件的后续 modelNamed 调用将返回模型的确切副本。在内存不足的情况下,此缓存将被清除。
名称可以包含文件扩展名。如果没有,则假定 .obj。名称还可以包含完整或部分文件路径。类似于 GLImage imageNamed: 函数,modelNamed: 可以加载应用程序包之外的模型,例如从应用程序文档文件夹加载。然而,因为这些模型被缓存,因此如果这些模型可能在应用程序运行期间被替换或删除,则不建议以这种方式加载模型,因为这可能导致意外的行为。
+ (GLModel *)modelWithContentsOfFile:(NSString *)path;
- (GLModel *)initWithContentsOfFile:(NSString *)path;
这些方法从文件加载 GLModel。路径参数可以是完整路径或部分路径。对于部分路径,假定路径是相对于应用程序资源文件夹的。格式由文件扩展名推断;目前只接受 .obj(Wavefront)和 .model(Apple的GLEssentials示例代码模型格式)文件。以这种方式加载的模型不会被以任何方式缓存或去重。请注意,也可以使用 @2x 和 ~ipad 文件名后缀指定不同设备的不同模型,这对于您希望为高端设备提供更详细模型的情况很有用。
- (GLModel *)initWithContentsOfFile:(NSString *)path;
- (GLModel *)initWithData:(NSData *)data;
这些方法使用数据初始化模型。数据格式应与支持的文件格式之一匹配。
- (void)draw;
在当前 GLView 中渲染模型。实际上,在调用 draw 之前,您可能希望为模型配置 OpenGL 状态,例如,通过设置用于渲染的纹理图像。请参阅 GLModelView 的 layoutSubviews
方法以获取示例。
@property (nonatomic, strong) GLModel *model;
视图将要渲染的模型。
@property (nonatomic, strong) GLImage *texture;
用于对模型进行纹理化的 GLImage。模型的纹理坐标必须定义,以便正确应用纹理。
@property (nonatomic, strong) UIColor *blendColor;
与模型纹理混合的颜色。这可以用来给模型上色或修改其不透明度。如果没有指定纹理图像,模型将以该颜色进行平面着色。
@property (nonatomic, copy) NSArray *lights;
用于照亮模型的 GLLight 对象数组。默认情况下,该数组包含单个位于物体上方和左侧的白色灯光。您可以设置多达八个灯光,虽然增加灯光的数量会对性能产生负面影响。设置空数组等效于只有一个环境白色灯光。
@property (nonatomic, assign) CATransform3D modelTransform;
应用于模型的 3D 变换。这可以用来将模型居中、缩放或旋转以适应视图框架。参见示例项目了解如何使用。
@property (nonatomic, strong) UIColor *ambientColor;
环境光照颜色。此颜色用于均匀照亮物体。默认为黑色(关闭)。
@property (nonatomic, strong) UIColor *diffuseColor;
@property (nonatomic, strong) UIColor *specularColor;
漫射和镜面反射光照颜色。这些颜色按方向照亮物体,来自变换位置指定的位置。这些默认为白色(全亮度)。
@property (nonatomic, assign) CATransform3D transform;
变换属性控制灯光的位置。目前,该变换只使用位置/平移部分。忽略旋转和缩放属性。使用 CATransform3DMakeTranslation(x, y, z) 设置适当的值。默认平移为 (0, 0, 1),通常在相机后面,或在相机和正在查看的场景之间。
- (void)bind:(GLuint)light;
此方法将 GLLight 绑定到场景中的特定灯光。灯光参数是一个 OpenGL 常量,表示灯光索引,其中 GL_LIGHT0 是第一个可用的灯光,GL_LIGHT7 通常是最后一个可用的灯光。
iOS 使用文件后缀巧妙地通过管理多个版本的资产来管理。第一代 iPad 引入了 ~ipad 后缀,用于指定 ipads 特定版本的文件(例如,foo~ipad.png)。iPhone 4 引入了 @2x 后缀,用于管理针对 Retina 显示屏的双倍分辨率的图像(例如 [email protected])。在第三代 iPad 上,您可以将这些后缀结合起来,以获得具有 Retina 质量的 iPad 图像(例如,foo@2x~ipad.png)。
GLImage 支持自动的 @2x 和 ~ipad 后缀,因此如果您尝试加载名为 foo.png 的图像,GLImage 将自动在 Retina iPhone 上查找 [email protected],在 iPad 上查找 foo~ipad.png,等等。这些后缀也适用于加载 ImageMap.plist 和 3D 模型文件,因此您可以为 Retina 显示提供更高分辨率的版本。
这是一个优雅的解决方案,但对于游戏可能不够,因为与应用程序不同,混合型游戏经常在 iPhone 和 iPad 上共享几乎所有相同的界面,资产和界面元素只是简单地放大,这意味着标准分辨率的 iPad 和全高清分辨率的 iPhone 需要使用相同的图像。
使用 @2x 后缀命名图像适用于 iPhone 但不适用于 iPad,而使用 ~ipad 后缀命名图像适用于 iPad 但不适用于 iPhone,这迫使您要么以不同的文件名复制相同的资产,要么编写自己的文件加载逻辑。
-hd 后缀是为了解决像 Cocos2D 库这样的库想要使用相同的 @2x 图形为 iPhone Retina 显示和 iPad 标准分辨率显示,因此为这两个使用相同的 -hd 文件名后缀。
GLView库不内置对-hd后缀的支持,但如果你在项目中包含StandardPaths库(《https://github.com/nicklockwood/StandardPaths》),GLView将使用这个库自动为GLImage、GLImageMap和GLModel添加对-hd后缀的支持,以及StandardPaths库支持的其他后缀,例如-iPhone 5特定资源的-568h后缀。
PVR图像格式是iOS设备中PowerVR图形芯片使用的特殊专有图像格式。PVR图像加载速度快,在内存中占用的空间比PNG少,因此对于需要加载和显示大量图像的应用程序非常有用。
由于加载速度很快,它们也足以从磁盘快速流式传输以创建电影剪辑,这对于不满足标准电影播放器API要求的情况(例如,需要具有透明部分的视频)来说是一种方便的视频显示方式。
你可能会在创建PVR时注意到文件大小实际上比等效的PNG文件要大。然而,这是误导性的——PNG文件使用内部zip压缩,使它们在磁盘上很小,但加载数据到内存后它们会扩展,占用与其宽度*高度*4字节相等的空间。
这同样适用于JPEG或其他任何图像格式。但是,对于PVR,磁盘上的大小与内存中的大小相匹配,因此16位的PVR只占用与相同尺寸的PNG一半的内存,压缩的PVR占用的空间更少。由于磁盘上的结构与内存中的一致,因此PVR的加载也更快,因为不需要解压缩或转码。
然而,PVR限制为平方图像,且尺寸为2的幂。有关转换的注意事项请参阅下面。
GLImage可以加载PVR图像,这是iOS图形芯片使用的特殊格式,具有极高的内存效率且加载速度快。通常,如果你使用PNG或JPEG格式的图像,出于避免阻塞UI的目的,你可能需要使用后台线程来加载这些图像,那么你可以使用PVR格式实时地在主线程上加载,而且没有性能影响。
要生成PVR图像,最好的选择是使用Imagination PVRTexTool,您可以从以下链接作为PVR SDK的一部分下载: corporations.imgtec.com/developers/powervr/installers/
SDK免费下载(尽管需要注册),包括一个易于使用的GUI工具和一个非常强大的命令行工具。PVRTexTool可以用来批量将所有已知的PNG图像格式转换为PVR格式。
注意:除了需要2的幂的尺寸外,PVR图像还必须是完美的平方,即宽度和高度必须相等。有效的大小为2x2、4x4、8x8、16x16、32x32、64x64、128x128、256x256等。在转换之前,请记住裁剪或调整图像到有效尺寸。
安装完成后,您可以在以下位置找到命令行PVRTexTool:
/Applications/Imagination/PowerVR/GraphicsSDK/PVRTexTool/CLI/OSX_x86/PVRTexToolCLI
GLImage目前只支持遗留的PVR版本2纹理格式。PVRTexTool使用-legacyтивpvr选项支持此功能。如果您的图像包含透明度,您还希望使用-p选项启用预乘alpha。
你可能想要使用的典型纹理工具设置如下所示
/Applications/Imagination/PowerVR/GraphicsSDK/PVRTexTool/CLI/OSX_x86/PVRTexToolCLI -i {input_file_name}.png -o {output_file_name}.pvr -legacypvr -p -l -f PVRTC1_4 -q pvrtcbest
这会生成一个4位压缩PVR图像,具有最佳可用的压缩质量。这将需要几秒钟才能运行,所以请不要担心。
如果您需要在应用程序中缩放图像或以极大缩放大小查看它们,则启用Mipmap可以提高以较小尺寸绘制时的图像质量是一个好主意。Mipmap会增加磁盘和内存中PVR文件的大小,大约增加33%,因此如果您只想以100%大小或更高显示您的图像,请不要使用它。要启用Mipmap,请添加-m标志并使用-mfilter标志来指定Mipmap算法
/Applications/Imagination/PowerVR/GraphicsSDK/PVRTexTool/CLI/OSX_x86/PVRTexToolCLI -i {input_file_name}.png -o {output_file_name}.pvr -legacypvr -p -l -m -mfilter cubic -f PVRTC1_4 -q pvrtcbest
这将生成一个带有alpha和Mipmap的4 bpp压缩PVR图像。
如前所述,这些文件看起来像压缩的JPEG图像,可能不适合用户界面组件或细节精细的图像。它们更适合大照片或如果以PNG等无损格式存储,加载速度太慢或占用太多内存的图像。然而,您也可以通过为-f标志指定不同的值,创建多种更高、非压缩格式的PVR图像。可用格式包括
- RGBG8888 - 32 bits-per-pixel, high quality 24-bit colour with 8-bit alpha
- ETC2_RGBA - 16 bits-per-pixel, 12-bit colour and 4-bit alpha
- ETC2_RGB_A1 - 16 bits-per-pixel, higher precision 5-bit color but only 1-bit alpha
- ETC2_RGB - 16 bits-per-pixel, higher precision color, but no alpha transparency
- PVRTC1_4 - 4 bits-per-pixel lossy compression, with alpha
- PVRTC1_4_RGB - 4 bits-per-pixel lossy compression, without alpha
- PVRTC1_2 - 2 bits-per-pixel lossy compression, with alpha
- PVRTC1_2_RGB - 2 bits-per-pixel lossy compression, without alpha
要批量转换文件夹中的一组图像,只需转到包含您的图像的目录,然后运行以下命令
find ./ -name \*.png | sed 's/\.png//g' | \ xargs -I % -n 1 /Applications/Imagination/PowerVR/GraphicsSDK/PVRTexTool/CLI/OSX_x86/PVRTexToolCLI -i %.png -o %.pvr -legacypvr -p -l -m -mfilter cubic -f PVRTC1_4 -q pvrtcbest
这将依次将PVRTexTool命令应用于文件夹中的每个文件。
要将GLImageView用作PVR视频播放器,您需要将视频转换为一系列PVR图像。假设您从一个与QuickTime兼容的视频文件开始,请按照以下步骤操作。如果您已经有了一系列编号的PNG或JPEG图像作为视频,则可以跳到第4步。
1) 在QuickTime 7中打开您的视频(不是QuickTime X)。您需要QuickTime Pro许可证才能进行任何有用的工作。
2) 假设视频的边长不是2的幂平方,您必须首先将其转换为正确的宽高比。选择“导出...”并选择“将电影转换为MPEG-4”。在此界面中,您可以选择自定义的宽度和高度。选择最接近实际视频大小的平方宽高比,您最好是选择裁剪或缩放图像,而不是字母箱,选择尽可能高的质量以避免压缩伪影。
3) 导出您的视频为MP4后,在QuickTime 7中打开新的视频,再次选择导出选项。这次选择“将电影转换成图像序列”并将视频导出为PNG文件序列。
4) 现在您有了单个帧,您需要将它们转换为PVR。使用上面列出的批量转换技术(根据您的电影是否有透明度,您可能需要调整格式、质量等)
find ./ -name \*.png | sed 's/\.png//g' | \ xargs -I % -n 1 /Applications/Imagination/PowerVR/GraphicsSDK/PVRTexTool/CLI/OSX_x86/PVRTexToolCLI -i %.png -o %.pvr -legacypvr -p -l -f PVRTC1_4 -q pvrtcbest
这将生成带有alpha的4 bpp压缩PVR图像帧(这会花费很长时间,您可能想要喝一杯)。由于单独的图像帧仍然相当大,您现在可以通过运行以下命令来gzip它们
find ./ -name \*.pvr | sed 's/\.pvr//g' | xargs -I % -n 1 gzip %.pvr
(以下为gzip图像的详细信息)
5) 现在您可以传递一个包含图像名称的数组到GLImageView类的animationImages
属性,以按顺序播放您的图像(请记住传递图像文件名,而不是图像本身,这将减少内存使用并避免图像首次加载时出现长时间延迟)。
PVR图像序列与原始MP4电影或等效PNG图像序列相比非常大。PVR针对内存使用和加载速度进行了优化,而不是磁盘空间,所以请准备好您的应用程序如果包含大量PVR图像会显著增加。为了减少磁盘上PVR图像的大小,您可以使用gzip将其减小,这可以根据图像内容大幅度减小它们的尺寸。要gzip一个PVR图像,您可以使用以下命令行工具
gzip {image_file}
要对PVR图像文件夹单独进行gzip压缩,请切换到图像文件夹,然后可以使用以下命令
find ./ -name \*.pvr | sed 's/\.pvr//g' | xargs -I % -n 1 gzip %.pvr
您可以在项目中包含GZIP库来加载压缩的图像(https://github.com/nicklockwood/Gzip)。GLImage类将自动检测GZIP库的存在,并在加载时解压图像。
GLModel类也支持gzip,因此如果您的模型文件非常大,您可能想尝试压缩它们以减少应用大小。
具有alpha通道的图像可以使用直方alpha或预乘alpha生成。在iOS上,通常使用预乘alpha,因为它对渲染更有效。添加到您的Xcode项目的PNG图像将自动转换为使用预乘alpha,因此GLImage在加载图像时假定使用预乘alpha。
当使用PVR图像时,直方alpha可能导致图像不透明部分在渲染时出现单像素黑色或白色光环(您可以在GLImage演示中的PVR图像中看到轻微的白色光环),因此建议您与PVR图像使用预乘alpha,这可以通过在PVRTexTool中添加-p标志来实现(这在上面的示例中已经包含)。
目前,没有自动检测在加载PVR图像时的alpha类型的方法,因此如果您使用直方alpha生成PVR,GLImage仍然假定它们是预乘的,这会使它们在显示时看起来更差。为了更正这一点,在加载图像后对图像调用[image imageWithPremultipliedAlpha:NO]
以创建将其视为具有直方alpha的副本。
GLImageMap支持的精灵表格式包含指示纹理文件是否有预乘alpha的元数据,因此在用GLImageMap加载精灵表时不需要进一步工作。
GLView库可以加载存储在Xcode 5 / SpriteKit纹理图集格式的精灵。要使用纹理图集,首先创建包含所有精灵图像的文件夹(包括标准变体和@2x变体),并添加扩展名.atlas,将其添加到您的项目中。
然后,在您的项目构建设置中,搜索“SpriteKit”并将“启用纹理图集生成”选项设置为(如果您尚未导入图集,可能显示为SPRITEKIT_TEXTURE_ATLAS_OUTPUT),默认“输出纹理图集格式”为“RGBA8888_PNG”(目前GLView不支持Xcode的任何压缩纹理格式)。
您不需要导入SpriteKit框架。在导入精灵表时,使用GLImageMap +imageMapWithContentsOfFile方法,可以指定文件扩展名“atlasc”(注意“c”),或者去掉路径扩展名,如果可用,GLImageMap将自动找到图集文件。
您需要使用Xcode 5或更高版本来生成图集文件,但您可以通过GLImageMap加载和使用它们,适用于在iOS 4.3及更高版本上运行的应用程序 - 它们不仅限于iOS 7。
版本1.6.2
版本1.6.1
版本1.6
版本1.5.1
版本1.5
版本 1.4
版本 1.3.9
版本 1.3.8
版本 1.3.7
版本 1.3.6
版本 1.3.5
版本 1.3.4
版本 1.3.3
版本 1.3.2
版本 1.3.1
版本 1.3
版本 1.2.2
版本1.2.1
版本1.2
版本1.1.1
版本1.1
版本1.0