我可以在SceneKit对象上使用PNG序列作为动画素材吗?

时间:2015-01-28 19:12:24

标签: ios animation 3d scenekit

我想以编程方式更改在iOS中使用SceneKit呈现的对象的材质。但我想使用动画图像文件。对于像UIImageViews这样的东西,PNG序列在iOS中运行良好 - 我如何将它们用作SceneKit中的素材?

这样的东西不能工作:

floor.firstMaterial.diffuse.contents = [UIImage animatedImageNamed:@"ANIMATION_" duration:6.0f];

谢谢!

3 个答案:

答案 0 :(得分:4)

有一个更简单的解决方案(或者至少我认为它更简单)虽然我无法证明它是否更有效。我已经在iPad mini(第一代)上测试了它,它运行正常。

您可以在其中放置一个SKScene对象,而不是将一个spritesheet纹理放入材质的内容中(并使用着色器)。

这样您就可以在SKScene中使用SKSpriteNode对象,并使用SCNAction对象为它们设置动画。然后,无需触摸着色器代码即可轻松控制所有动画,并且更加强大。

    NSArray<SKTexture*> *cursorTextures =
    @[
      [SKTexture textureWithImageNamed:@"tilecursor1.png"],
      [SKTexture textureWithImageNamed:@"tilecursor2.png"],
      [SKTexture textureWithImageNamed:@"tilecursor3.png"],
      [SKTexture textureWithImageNamed:@"tilecursor4.png"],
      [SKTexture textureWithImageNamed:@"tilecursor5.png"]
      ];

    SKSpriteNode *cursorSprite = [SKSpriteNode spriteNodeWithTexture:cursorTextures[0]];
    cursorSprite.position = CGPointMake(cursorSprite.size.width/2.0, cursorSprite.size.height/2.0);
    [cursorSprite runAction:[SKAction repeatActionForever:[SKAction animateWithTextures:cursorTextures timePerFrame:0.1]]];

    SKScene *cursorScene = [SKScene sceneWithSize:cursorSprite.size];
    cursorScene.backgroundColor = [UIColor clearColor];
    [cursorScene addChild:cursorSprite];

    ...

    self.cursor.material.diffuse.contents = cursorScene;

答案 1 :(得分:3)

没有任何东西可以直接使用。

我会使用着色器修饰符来完成此操作。如果将所有图像打包在单个图像中,则可以使用修饰符(在SCNShaderModifierEntryPointGeometry入口点)根据u_time更新对象的纹理坐标,以便每个 t ms使用另一个图像(或图集的子图像)。

答案 2 :(得分:2)

Swift 4.1 / Xcode 9.3 / iOS 11.3

您可以使用 CADisplayLink

滚动自己的动画来解决此问题

将图片加载到 UIImage

的数组中
var images : [UIImage] = [
    UIImage(named: "image1.png"),
    UIImage(named: "image2.png"),
    ...
]

然后,开始动画:

var animationImageFrameIndex : Double = 0
var displayLink : CADisplayLink?

func startAnimation() {
    animationImageFrameIndex = 0
    displayLink = CADisplayLink(target: self, selector: #selector(animationStep(_:)))
    displayLink!.preferredFramesPerSecond = 60
    displayLink!.add(to: .current, forMode: .defaultRunLoopMode)
}

preferredFramesPerSecond是您希望调用 animationStep 方法的所需速率。但是, CADisplayLink 并不保证会按您要求的费率调用它。

通过 CADisplayLink 定期调用animationStep函数,它实际上循环显示图像:

@objc func animationStep(_ displayLink: CADisplayLink) {
    let desiredFPS : Double = 24
    let realFPS = 1 / (displayLink.targetTimestamp - displayLink.timestamp)

    material.diffuse.contents = images[Int(animationImageFrameIndex)]
    animationImageFrameIndex += desiredFPS / realFPS
    if Int(animationImageFrameIndex) >= images.count {
        displayLink.remove(from: .current, forMode: .defaultRunLoopMode)
    }
}

在上述方法中, desiredFPS 是您实际想要在动画中使用的帧速率。

Bitbucket上有一个完整的示例项目,here

应该能够使用简单的 CAKeyframeAnimation 为这个(一系列图像)制作动画,但经过大量测试后,很明显它不起作用,出现了成为Apple的一个错误。其他人有一个开放的雷达here,我也提交了一份错误报告。