ios - SceneKit Rigged 角色动画提高性能

标签 ios objective-c macos core-animation scenekit

我有 *.DAE 文件,每个角色都有 45-70 根骨头, 我想在屏幕上显示大约 100 个动画角色。

然而,当我有大约 60 个角色时,动画需要大约 13 毫秒的更新循环,这是非常昂贵的,并且几乎没有余地来处理其他任务。

我将动画“CAAnimationGroup”设置为 Mesh SCNNode 当我想交换动画时,我将删除以前的 fadeOut 设置为 0.2 的动画,并添加 FadeIn 也设置为 0.2 的新动画。 -> 不好吗?我应该暂停以前的动画并播放新的动画吗?还是更糟?

是否有更好的方法可以在 SceneKit 中使用 GPU 或其他方式为绑定(bind)的角色设置动画?

请让我开始朝着正确的方向前进,以减少更新循环中的动画开销。

更新 通过 Bug radar 联系 Apple 后,我通过电子邮件收到了这个问题:

This issue is being worked on to be fixed in a future update, we will let you know as soon as we have a beta build you can test and verify this issue.

Thank you for your patience.

所以让我们拭目以待,看看 Apple 的工程师会在多大程度上增强它:)。

最佳答案

如果您的顶点的影响少于 4 个,SceneKit 会在 GPU 上执行骨骼动画。来自文档,转载below :


仅当此几何源中的componentsPerVector 计数等于或小于 4 时,SceneKit 才会在 GPU 上执行骨骼动画。较大的矢量会导致基于 CPU 的动画并显着降低渲染性能。


我使用以下代码来检测动画是否在 GPU 上完成:

- (void)checkGPUSkinningForInScene:(SCNScene*)character
                          forNodes:(NSArray*)skinnedNodes {
  for (NSString* nodeName in skinnedNodes) {
    SCNNode* skinnedNode =
        [character.rootNode childNodeWithName:nodeName recursively:YES];
    SCNSkinner* skinner = skinnedNode.skinner;
    NSLog(@"******** Skinner for node %@ is %@ with skeleton: %@",
          skinnedNode.name, skinner, skinner.skeleton);
    if (skinner) {
      SCNGeometrySource* boneIndices = skinner.boneIndices;
      SCNGeometrySource* boneWeights = skinner.boneWeights;
      NSInteger influences = boneWeights.componentsPerVector;
      if (influences <= 4) {
        NSLog(@" This node %@ with %lu influences is skinned on the GPU",
              skinnedNode.name, influences);
      } else {
        NSLog(@" This node %@ with %lu influences is skinned on the CPU",
              skinnedNode.name, influences);
      }
    }
  }
}

您传递 SCNScene 和附有 SCNSkinner 的节点名称,以检查动画是在 GPU 还是 CPU 上完成。

但是,关于 GPU 上的动画还有一条隐藏的信息,那就是如果您的骨架有超过 60 根骨骼,它将不会在 GPU 上执行。知道这一点的技巧是通过附加一个无效的着色器修改器条目作为 explained in this post 来打印默认的顶点着色器。 .

顶点着色器包含以下蒙皮相关代码:

#ifdef USE_SKINNING
uniform vec4 u_skinningJointMatrices[60];

....

    #ifdef USE_SKINNING
  {
    vec3 pos = vec3(0.);
    #ifdef USE_NORMAL
    vec3 nrm = vec3(0.);
    #endif
  #if defined(USE_TANGENT) || defined(USE_BITANGENT)
    vec3 tgt = vec3(0.);
    #endif
    for (int i = 0; i < MAX_BONE_INFLUENCES; ++i) {
#if MAX_BONE_INFLUENCES == 1
        float weight = 1.0;
#else
        float weight = a_skinningWeights[i];
#endif
      int idx = int(a_skinningJoints[i]) * 3;
      mat4 jointMatrix = mat4(u_skinningJointMatrices[idx], u_skinningJointMatrices[idx+1], u_skinningJointMatrices[idx+2], vec4(0., 0., 0., 1.));
            pos += (_geometry.position * jointMatrix).xyz * weight;
      #ifdef USE_NORMAL
            nrm += _geometry.normal * mat3(jointMatrix) * weight;
      #endif
      #if defined(USE_TANGENT) || defined(USE_BITANGENT)
            tgt += _geometry.tangent.xyz * mat3(jointMatrix) * weight;
      #endif
    }
    _geometry.position.xyz = pos;

这清楚地表明您的骨架应限制在 60 block 骨头以内。

如果您的所有角色都具有相同的骨架,那么我建议您使用上述提示检查动画是在 CPU 还是 GPU 上执行。否则,您可能必须将角色骨架固定为少于 60 根骨骼,并且每个顶点的影响不超过 4 个。

关于ios - SceneKit Rigged 角色动画提高性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41328818/

相关文章:

ios - 如何以编程方式检查设备是否在 iOS 中设置振动模式?

ios - 如何从特定的 TabbarController 启动应用程序

HmacSHA1 的 Java Mac.getInstance 慢

ios - CALayer.contents 无法在 AVMutableComposition 中正确呈现

ios - 如何打印 Unicode 像 "\u{variable}"?

objective-c - 当方向设置为横向时,UIPrintInteractionController 附加一个空白页

android - '错误: the command "android" failed' using cordova

ios - SpriteKit 中自定义绘图的替代方案有哪些?

ios - 多声道音频 iOS(需要 4 个同时输入)

ios - 翔升 : asl_search() can't get logs write by asl_log()