BCMeshTransformView 0.9

BCMeshTransformView 0.9

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最新发布2014 年 12 月

Bartosz Ciechanowski 维护。



BCMeshTransformView 使得将网格变形应用到视图层次结构变得简单。它灵感来自私有 CALayer 属性 meshTransform 和其值类 CAMeshTransform。我 强烈 推荐您查看 关于这两个属性的博客文章,因为它深入解释了这些概念,并可能解释了我所做出的 API 选择。

功能

  • 转换常规 UIKit 视图层次结构
  • 与基于块的 UIView 网格动画可动画
  • 支持方向性光照

演示应用程序包含一些网格变形的工作示例以及它可以实现什么。

安装

BCMeshTransformView 通过 CocoaPods 提供

pod 'BCMeshTransformView'

或者,您可以复制 BCMeshTransformView 文件夹的内容并将其包含到项目中,并包含 BCMeshTransformView.h

要求

  • iOS 7.0
  • ARC
  • GLKit 框架

您可以选择包含 OpenGL ES 框架,这将启用 帧捕获

使用 BCMeshTransformView

    // create an instance
    BCMeshTransformView *meshView = [[BCMeshTransformView alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];

    // add a view hierarchy to a contentView, subviews of contentView will get mesh-transformed
    [meshView.contentView addSubview:label];

    // apply a mesh
    meshView.meshTransform = [self simpleMeshTransform];

    [self.view addSubview:meshView];

请记住,要将您想要进行网格变形的任何子视图添加到 contentView 中,而不仅仅是视图本身。类将在调用其实例的 addSubview: 方法时发出警告。

使用 BCMeshTransform

网格变形由两种不同的基本元素组成:顶点和面。

顶点

单个顶点由 BCMeshVertex 结构表示,并包含 fromto 字段

typedef struct BCMeshVertex {
    CGPoint from;
    BCPoint3D to;
} BCMeshVertex;

顶点定义了视图表面上的点与它在 3D 空间中的转换位置之间的映射。

fromto 字段均在 单位坐标 中定义,类似于 CALayeranchorPoint 属性的工作方式。

面由它所跨的四个顶点定义。顶点通过它们在网格变形中 vertices 数组中的索引进行引用。

typedef struct BCMeshFace {
    unsigned int indices[4];
} BCMeshFace;

深度归一化

由于顶点是在单位坐标中定义的,因此必须将缺失的深度比例定义为其他两个坐标的函数。可以将depthNormalization参数设置为以下六个常量之一

extern NSString * const kBCDepthNormalizationNone;
extern NSString * const kBCDepthNormalizationWidth;
extern NSString * const kBCDepthNormalizationHeight;
extern NSString * const kBCDepthNormalizationMin;
extern NSString * const kBCDepthNormalizationMax;
extern NSString * const kBCDepthNormalizationAverage;

简单网格变换

以下就是最基本的网格变换的实际效果

- (BCMeshTransform *)simpleMeshTransform
{
    BCMeshVertex vertices[] = {
        {.from = {0.0, 0.0}, .to= {0.5, 0.0, 0.0}},
        {.from = {1.0, 0.0}, .to= {1.0, 0.0, 0.0}},
        {.from = {1.0, 1.0}, .to= {1.0, 1.0, 0.0}},
        {.from = {0.0, 1.0}, .to= {0.0, 1.0, 0.0}},
    };

    BCMeshFace faces[] = {
        {.indices = {0, 1, 2, 3}},
    };

    return [BCMeshTransform meshTransformWithVertexCount:4
                                                vertices:vertices
                                               faceCount:1
                                                   faces:faces
                                      depthNormalization:kBCDepthNormalizationNone];
}

此变换将执行一个非常简单的斜切变换,您还可以通过修改to顶点的位置来进一步微调它。查看演示应用中的网格变换,了解如何创建更复杂的效果。

尽管BCMeshTransform是默认的基类,但其可变对应物BCMutableMeshTransform使用起来更为方便。

动画

支持所有基于块的UIView动画版本,除了关键帧和弹簧动画。动画始终从当前状态开始,无论是否设置UIViewAnimationOptionBeginFromCurrentState标志。

要发生动画,当前网格和最终网格必须兼容

  • 它们必须有相同数量的顶点
  • 它们必须有相同数量的面
  • 在相应的索引处,面必须指向相同的顶点,(它们的indices数组必须相等)

光照

BCMeshTransformView支持一种简单的光照模型,即纯白光下的漫反射光照

@property (nonatomic) BCPoint3D lightDirection;
@property (nonatomic) float diffuseLightFactor;

lightDirection属性定义场景中光源的方向。该向量不需要规范化,默认值为{0.0, 0.0, 1.0}

diffuseLightFactor定义漫反射光照对场景一般光照的影响程度。当它等于1.0时,整个场景使用纯漫反射光照;当等于0.0时,场景只由环境光照照亮。介于两者之间的值相应地调整百分比。

辅助变换

BCMeshTransformView支持以下属性形式的任意矩阵变换:

@property (nonatomic) CATransform3D supplementaryTransform;

场景中每个网格顶点都通过supplementaryTransform进行变换。属性可以用来应用透视变换或其他常见操作,如旋转、平移和缩放。

便捷网格方法

从头开始创建BCMutableMeshTransform非常繁琐,因此我创建了一些便捷方法,可以使整个过程更加愉快

单位网格变换

此方法创建具有给定行数和列数的面的网格变换。生成的网格是均匀的,不包含任何干扰——将其应用于BCMeshView不会产生任何视觉效果,但它是对进一步修改的绝佳起点

+ (instancetype)identityMeshTransformWithNumberOfRows:(NSUInteger)rowsOfFaces
                                      numberOfColumns:(NSUInteger)columnsOfFaces;

生成器

您可以使用以下类方法,而不是手动为默认构造函数创建缓冲区存储

+ (instancetype)meshTransformWithVertexCount:(NSUInteger)vertexCount
                             vertexGenerator:(BCMeshVertex (^)(NSUInteger vertexIndex))vertexGenerator
                                   faceCount:(NSUInteger)faceCount
                               faceGenerator:(BCMeshFace (^)(NSUInteger faceIndex))faceGenerator;

这些块将分别被调用vertexCountfaceCount次。

map

一个非常便捷的map方法使修改现有的BCMutableMeshTransform变得非常容易。这对于密集的单位变换非常有用

- (void)mapVerticesUsingBlock:(BCMeshVertex (^)(BCMeshVertex vertex, NSUInteger vertexIndex))block;

注意事项

  • BCMeshTransformView 稳定可靠,但目前仍处于测试阶段。它不会意外崩溃,但我尚未对类进行深入的实战测试,因此仍然可能存在一些边缘情况,导致某些行为不合预期。

  • 网格生成计算量大,在调试模式下可能较慢,尤其是在较老设备上。使用优化编译(默认Release模式已经启用-Os优化)应能提供显著的改善。

  • 由于渲染基于OpenGL,BCMeshTransformView 会默认将其内容剪裁到界限内,无论clipsToBounds属性状态如何。

  • 如果半透明面重叠,只有最前方的面会被渲染。原来的CAMeshTransform会对三角形进行z排序,但是我在这里使用深度缓存来处理三角形的相对z顺序。

  • 不支持对contentView子视图的所有动画,且默认移除。尽管在层的任何更改时,contentView的内容都会自动快照,但这个过程需要超过16毫秒,因此不够高效,无法在每一帧上快照层。