测试已测试 | ✗ |
语言语言 | Obj-CObjective C |
许可证 | MIT |
发布最新发布 | 2014 年 12 月 |
由 Bartosz Ciechanowski 维护。
BCMeshTransformView
使得将网格变形应用到视图层次结构变得简单。它灵感来自私有 CALayer
属性 meshTransform
和其值类 CAMeshTransform
。我 强烈 推荐您查看 关于这两个属性的博客文章,因为它深入解释了这些概念,并可能解释了我所做出的 API 选择。
UIView
网格动画可动画演示应用程序包含一些网格变形的工作示例以及它可以实现什么。
BCMeshTransformView
通过 CocoaPods 提供
pod 'BCMeshTransformView'
或者,您可以复制 BCMeshTransformView
文件夹的内容并将其包含到项目中,并包含 BCMeshTransformView.h
。
您可以选择包含 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
结构表示,并包含 from
和 to
字段
typedef struct BCMeshVertex {
CGPoint from;
BCPoint3D to;
} BCMeshVertex;
顶点定义了视图表面上的点与它在 3D 空间中的转换位置之间的映射。
from
和 to
字段均在 单位坐标 中定义,类似于 CALayer
的 anchorPoint
属性的工作方式。
面由它所跨的四个顶点定义。顶点通过它们在网格变形中 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;
这些块将分别被调用vertexCount
和faceCount
次。
一个非常便捷的map方法使修改现有的BCMutableMeshTransform
变得非常容易。这对于密集的单位变换非常有用
- (void)mapVerticesUsingBlock:(BCMeshVertex (^)(BCMeshVertex vertex, NSUInteger vertexIndex))block;
BCMeshTransformView
稳定可靠,但目前仍处于测试阶段。它不会意外崩溃,但我尚未对类进行深入的实战测试,因此仍然可能存在一些边缘情况,导致某些行为不合预期。
网格生成计算量大,在调试模式下可能较慢,尤其是在较老设备上。使用优化编译(默认Release模式已经启用-Os优化)应能提供显著的改善。
由于渲染基于OpenGL,BCMeshTransformView
会默认将其内容剪裁到界限内,无论clipsToBounds
属性状态如何。
如果半透明面重叠,只有最前方的面会被渲染。原来的CAMeshTransform
会对三角形进行z排序,但是我在这里使用深度缓存来处理三角形的相对z顺序。
不支持对contentView
子视图的所有动画,且默认移除。尽管在层的任何更改时,contentView
的内容都会自动快照,但这个过程需要超过16毫秒,因此不够高效,无法在每一帧上快照层。