【问题标题】:Can I use a PNG sequence as an animated material on a SceneKit object?我可以在 SceneKit 对象上使用 PNG 序列作为动画材质吗?
【发布时间】:2015-03-27 20:07:46
【问题描述】:

我想以编程方式更改在 iOS 中使用 SceneKit 渲染的对象的材质。但我想使用动画图像文件。 PNG 序列在 iOS 中非常适用于 UIImageViews 之类的东西——我如何在 SceneKit 中将它们用作材质?

这样的东西不起作用

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

谢谢!

【问题讨论】:

    标签: ios animation 3d scenekit


    【解决方案1】:

    有一个更简单的解决方案(或者至少我认为它更简单),但我无法证明它是否更有效。我已经在 iPad mini(第 1 代)上进行了测试,效果很好。

    您可以在其中放置一个 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;
    

    【讨论】:

    • 这似乎不是很高效,但对我来说足够好。不过,我还没有对着色器方法进行适当的性能比较。
    • 请注意,在处理透明度时不会这样做,因为SKTextures 似乎不支持图像的透明度。
    • 如果您使用 PNG 或其他支持它的格式,透明度就可以正常工作。如果您想要透明度,请不要使用 JPEG。上面的代码是直接从我的应用 World of Hex 中提取的,我在每一张图片中都使用了透明度。
    【解决方案2】:

    没有什么可以开箱即用。

    我会使用着色器修改器来做到这一点。如果您将所有图像打包在一个图像中,您可以使用修改器(在SCNShaderModifierEntryPointGeometry 入口点)根据u_time 更新对象的纹理坐标,以便每 t ms 另一个图像(或地图集的子图像)。

    【讨论】:

    • 好计划。您可能会考虑使用多个图像文件并在计时器或动画块中设置contents,但不要——使用包含所有帧的单个图像并在着色器中翻转纹理坐标会更高效。跨度>
    • 试过了,但奇怪的是:一段时间后图像质量下降并变得模糊。 (以一种奇怪的方式。)
    • 如果您不断增加 UV,可能是由于浮点精度问题。你能分享你的代码吗?
    • 着色器代码:NSString *shaderCode = @"_geometry.texcoords[0] = vec2((_geometry.texcoords[0].x+floor(u_time*30.0))/7.0, (_geometry.texcoords[0].y+floor(u_time*30.0/7.0))/3.0);";
    • 当我将着色器更改为此它显示错误,但抖动似乎停止发生:@"_geometry.texcoords[0] = vec2(_geometry.texcoords[0].x, (_geometry.texcoords[0].y+floor(u_time*30.0/10.0))/7.0);"
    【解决方案3】:

    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 不保证会按照您要求的速率调用它。

    animationStep 函数被 CADisplayLink 定期调用,它实际上是在图像之间循环:

    @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,我还提交了一个错误报告。

    【讨论】:

      猜你喜欢
      • 2021-04-30
      • 2017-07-31
      • 2019-08-25
      • 1970-01-01
      • 2012-02-05
      • 2018-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多