我想以编程方式更改在iOS中使用SceneKit呈现的对象的材质。但我想使用动画图像文件。对于像UIImageViews这样的东西,PNG序列在iOS中运行良好 - 我如何将它们用作SceneKit中的素材?
像这样的东西不能工作:
floor.firstMaterial.diffuse.contents = [UIImage animatedImageNamed:@"ANIMATION_" duration:6.0f];
谢谢!
答案 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,我也提交了一份错误报告。