【问题标题】:How do I stack images to simulate depth using Core Animation?如何使用 Core Animation 堆叠图像以模拟深度?
【发布时间】:2010-05-14 14:41:29
【问题描述】:

我有一系列 UIImages 我需要用它们来模拟深度。我不能使用缩放,因为我需要能够旋转父视图,并且图像应该看起来像它们明显堆叠在彼此前面,而不是在同一平面上。

我创建了一个新的基于 ViewController 的项目并将其放入 viewDidLoad(以及附加的三个 120x120 像素图像,分别名为 1.png、2.png 和 3.png):

- (void)viewDidLoad {

    // display image 3
    UIImageView *three = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"3.png"]];
    three.center = CGPointMake(160 + 60, 240 - 60);
    [self.view addSubview:three];

    // rotate image 3 around the z axis
    // THIS IS INCORRECT
    CATransform3D theTransform = three.layer.transform;
    theTransform.m34 = 1.0 / -1000;
    three.layer.transform = theTransform;

    // display image 2
    UIImageView *two = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"2.png"]];
    two.center = CGPointMake(160, 240);
    [self.view addSubview:two];

    // display image 1
    UIImageView *one = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1.png"]];
    one.center = CGPointMake(160 - 60, 240 + 60);
    [self.view addSubview:one];

    //  rotate image 3 around the z axis
    // THIS IS INCORRECT
    theTransform = one.layer.transform;
    theTransform.m34 = 1.0 / 1000;
    one.layer.transform = theTransform;

    // release the images
    [one release];
    [two release];
    [three release];

    // rotate the parent view around the y axis
    theTransform = self.view.layer.transform;
    theTransform.m14 = 1.0 / -500;
    self.view.layer.transform = theTransform;

    [super viewDidLoad];
}

我有非常具体的原因为什么我不使用 EAGLView 以及为什么我不将图像作为 CALayers 加载(即为什么我对每个图像都使用 UIImageViews)。这只是一个快速演示,我可以用它来确定我在父应用程序中需要什么。

是否有一些矩阵方法可以沿 z 轴平移这些 2d 图像,使它们看起来像我想要表示的那样?我浏览了其他 StackOverflow 文章以及 Wikipedia 参考资料,但没有找到我正在寻找的内容——尽管我可能不一定会为我正在尝试做的事情使用正确的术语。

【问题讨论】:

    标签: iphone core-animation


    【解决方案1】:

    为了堆叠您的视图并应用透视,您需要先将它们放置在不同的 Z 位置,然后将透视效果应用到包含层。

    我相信下面的代码会做到这一点,但我没有测试过(我用纯CALayers做过类似的事情,所以一般原则是正确的):

    - (void)viewDidLoad {
    
        UIImageView *three = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"3.png"]];
        three.center = CGPointMake(160 + 60, 240 - 60);
        [self.view addSubview:three];
    
        three.layer.zPosition = -100;
    
        UIImageView *two = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"2.png"]];
        two.center = CGPointMake(160, 240);
        [self.view addSubview:two];
    
        two.layer.zPosition = 0;
    
        UIImageView *one = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1.png"]];
        one.center = CGPointMake(160 - 60, 240 + 60);
        [self.view addSubview:one];
    
        one.layer.zPosition = 100;
    
        // release the images
        [one release];
        [two release];
        [three release];
    
        CATransform3D theTransform = self.view.layer.sublayerTransform;
        theTransform.m34 = 1.0 / -500;
        self.view.layer.sublayerTransform = theTransform;
    
        [super viewDidLoad];
    }
    

    在您的代码中,您只是在每个视图的层上设置 CATransform3D 的透视部分(这就是 CATransform3D 矩阵的 m34 组件所做的)。您实际上并没有在 Z 平面上移动它们。您可以为此使用转换,但我发现 CALayers 的 zPosition 属性提供了一种更简洁的方式来定位 3-D 图层。

    一旦您将图层彼此相对放置(负值远离用户的视点),您需要对主视图中托管的所有图层应用透视效果。为此,我发现设置托管视图层的sublayerTransform 是必要的,以便将透视正确应用于所有托管层。

    如果您希望旋转一系列图像,请在主托管视图层的 sublayerTransform 上使用 CATransform3DRotate()

    有关对 CALayers 进行 3D 操作并应用透视图的示例应用程序,请查看我在文章 here 的第二次更新中链接到的项目。

    【讨论】:

    • sublayerTransform 确实有帮助,但 zPosition 没有做任何事情。看起来 zPosition 就像 CSS z-index 属性——它改变了哪些层在哪些其他层之上,但不会在 z 轴上物理移动它们。
    • @Jeffrey Berthiaume - 它确实改变了 CALayers 在连续 3-D 空间中的位置。例如,请参阅此示例:sunsetlakesoftware.com/sites/default/files/LayerExample2.zip 并查看红色、绿色和蓝色层的位置。改变 Z 位置,您可以看到它们以不同的间距堆叠。请注意,透视是相对于图层中心应用的,因此图层需要稍微偏离中心才能看到堆叠(或者您可以对子图层变换应用旋转)。
    • 我确实改变了 Z 位置,但这似乎没有任何作用(即使我让父视图旋转)。它看起来仍然像所有东西都平放在彼此之上。我确实找到了这个:mmsguru.com/blogger/?action=entry&id=1242656318“另外一个 CALayer 有一个名为 zPosition 的属性......原来 CoreAnimation,即使它具有所有这些属性(通过平移和 z 位置属性的 z 坐标)不允许部分隐藏使用第三维的子层....顶层的所有子层最终都渲染到同一层上。”
    • @Jeffrey Berthiaume - 所有子层都在一个层中合成在一起,留下一个扁平层。如果要在 3-D 中旋转图层,则需要将旋转变换应用于 sublayerTransform,而不是主变换,就像我在此示例中所做的那样:sunsetlakesoftware.com/2008/10/22/…。您还可以在 CATransformLayer 中托管您的图层。如果你只是变换一个普通层,它所做的只是旋转合成子层的扁平化结果。
    【解决方案2】:

    我终于通过使用 CATransform3DMakeTranslation 解决了这个问题,这似乎是在 z 轴上下移动图层的唯一方法:

    UIImageView *three = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"3.png"]];
    three.layer.transform = CATransform3DMakeTranslation(0.0f, 0.0f, 20.0f);
    three.center = CGPointMake(160 + 60, 240 - 60);
    [self.view addSubview:three];
    

    (我还在 z 轴上将 UIImageView 移动了一个 -20.0f 像素。这最终得到了我想要的效果。)

    【讨论】:

    • 嗨,我正在尝试您的代码,但我没有看到按照我们给定的值在 Z 轴上显示视图。我的要求是让 UIView 在 Z 轴方向上从相机视图中缩小。你能分享你的完整文件吗?
    • 另外,如果只是想要高于所有其他视图的内容,请尝试:myview.layer.zPosition = CGFloat(Float.greatestFiniteMagnitude);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 2019-05-23
    • 2019-09-06
    • 1970-01-01
    相关资源
    最近更新 更多