4

下に反射のある画像を表示するシンプルなiPhoneアプリを作成しようとしています。コアアニメーションを使用して、X軸を中心に画像を回転させたいと考えています。

「ビューベースのアプリケーション」テンプレートを使用して新しいiPhoneアプリを作成することから始めました。「Picture.jpg」画像ファイルを追加してから、これをViewControllerに追加しました。

- (void)awakeFromNib {
    CGFloat zDistance = 1500.0f;

    // Create perspective transformation
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = 1.0f / -zDistance;

    // Create perspective transform for reflected layer
    CATransform3D reflectedTransform = CATransform3DMakeRotation(M_PI, 1.0f, 0.0f, 0.0f);
    reflectedTransform.m34 = 1.0f / -zDistance;

    // Create spinning picture
    CALayer *spinningLayer = [CALayer layer];
    spinningLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
    spinningLayer.contents = (id)[UIImage imageNamed:@"Picture.jpg"].CGImage;
    spinningLayer.transform = transform;    

    // Create reflection of spinning picture
    CALayer *reflectionLayer = [CALayer layer];
    reflectionLayer.frame = CGRectMake(60.0f, 360.0f, 200.0f, 300.0f);
    reflectionLayer.contents = (id)[UIImage imageNamed:@"Picture.jpg"].CGImage;
    reflectionLayer.opacity = 0.4f;
    reflectionLayer.transform = reflectedTransform;

    // Add layers to the root layer
    [self.view.layer addSublayer:spinningLayer];
    [self.view.layer insertSublayer:reflectionLayer below:spinningLayer];

    // Spin the layers
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    anim.fromValue = [NSNumber numberWithFloat:0.0f];
    anim.toValue = [NSNumber numberWithFloat:(2 * M_PI)];
    anim.duration = 3.0f;
    anim.repeatCount = 1e100f;
    [spinningLayer addAnimation:anim forKey:@"anim"];
    [reflectionLayer addAnimation:anim forKey:@"anim"];
}

これはほとんど機能します。問題は、メイン画像の回転と反射の回転が完全に同期していないことです。完璧に非常に近いですが、画像の下部と反射の上部のエッジは数ピクセル離れています。それらは数度異なるように見えます。

画面の左側では、反射が画像の「前方」にあるように見え、右側では、反射が画像の後ろにあります。つまり、上部の画像の下隅が画面に向かって押され、反射の上部の隅が視聴者に向かって引っ張られているように見えます。これは、画像が回転するときに画像の前面と背面の両方を見るときに当てはまります。

増やすzDistanceと効果が目立たなくなります。transform.m34両方のレイヤーをゼロのままにして遠近法の変換を完全に排除すると、画像と反射は完全に同期しているように見えます。したがって、この問題は時刻同期の問題に関連しているとは思いません。

パースペクティブ変換に何かが欠けているのではないかと思いますが、何が悪いのかを判断する方法がわかりません。私は基本的に、この関連するStackOverflowの質問で説明されているのと同じ変換を行っていると思います。

誰かが助けることができますか?

4

2 に答える 2

3

私の質問に対する答えを見つけたかもしれないと思います。元のコードでは、画像の下に反射を配置し、フリップとパースペクティブを適用して反射を作成しました。これを行う正しい方法は、反射を画像と同じ位置に配置し、平行移動と回転の変換を適用して適切な場所に配置してから、遠近法の変換を適用することです。

スピンをアニメーション化するときは、画像のアニメーションの反対方向に反射をスピンする必要があります。

したがって、機能するコードは次のとおりです。

- (void)awakeFromNib {
    CGFloat zDistance = 1500.0f;

    // Create perspective transformation
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = 1.0f / -zDistance;

    // Create perspective transform for reflected layer
    CATransform3D reflectedTransform = CATransform3DMakeTranslation(0.0f, 300.0f, 0.0f);
    reflectedTransform = CATransform3DRotate(reflectedTransform, M_PI, 1.0f, 0.0f, 0.0f);
    reflectedTransform.m34 = 1.0f / -zDistance;

    // Create spinning picture
    CALayer *spinningLayer = [CALayer layer];
    spinningLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
    spinningLayer.contents = (id)[UIImage imageNamed:@"Picture.jpg"].CGImage;
    spinningLayer.transform = transform;    

    // Create reflection of spinning picture
    CALayer *reflectionLayer = [CALayer layer];
    reflectionLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
    reflectionLayer.contents = (id)[UIImage imageNamed:@"Picture.jpg"].CGImage;
    reflectionLayer.opacity = 0.4f;
    reflectionLayer.transform = reflectedTransform;

    // Add layers to the root layer
    [self.view.layer addSublayer:spinningLayer];
    [self.view.layer insertSublayer:reflectionLayer below:spinningLayer];

    // Spin the layers
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    anim.fromValue = [NSNumber numberWithFloat:0.0f];
    anim.toValue = [NSNumber numberWithFloat:(2 * M_PI)];
    anim.duration = 3.0f;
    anim.repeatCount = 1e100f;
    [spinningLayer addAnimation:anim forKey:@"anim"];

    CABasicAnimation *reflectAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    reflectAnim.fromValue = [NSNumber numberWithFloat:0.0f];
    reflectAnim.toValue = [NSNumber numberWithFloat:(-2 * M_PI)];
    reflectAnim.duration = 3.0f;
    reflectAnim.repeatCount = 1e100f;
    [reflectionLayer addAnimation:reflectAnim forKey:@"reflectAnim"];
}

なぜこれが機能するのか正確にはわかりません。反射を元の位置と同じ位置に配置し、それを変換すると、2つの画像が同じ「変換空間」に配置されることは直感的に理解できますが、その背後にある数学について誰かが説明していただければ幸いです。

プロジェクト全体はGitHubで入手できます:https ://github.com/kristopherjohnson/perspectivetest

于 2010-02-14T23:30:42.520 に答える
1

オブジェクトを使用CAAnimationGroupして、同じ時間空間で2つのアニメーションを実行できます。これで同期の問題が解決されます。

編集:ばかげたコードを削除しました。

于 2010-02-14T22:34:59.083 に答える