【问题标题】:SceneKit get current SCNNode position form Animated SCNNodeSceneKit 从 Animated SCNNode 获取当前 SCNNode 位置
【发布时间】:2017-04-15 06:20:06
【问题描述】:

我想从动画SCNNode 中获取当前节点位置 我知道presentationNode 并且我试图在那里提取位置表格,但没有运气

这是我的代码

SCNNode * pelvis = [_unit childNodeWithName:@"Bip01_Pelvis" recursively:YES];
SCNNode * present = pelvis.presentationNode;



SCNVector3 position = [self convertPosition:present.position toNode:self.parentNode];

我的位置是SCNNode 在应用CAAnimation 之前处于“休息”模式的位置。

如何从“presentationNode”获取位置等属性?

编辑

类本身的相关部分:

@interface UndeadSimple : RepresentationNode <CAAnimationDelegate>
{
    //Animations
    SCNNode * _undead;

    CAAnimation * _currentAnimation;
    NSString    * _currAnimationkey;

    CAAnimation * _death1;
    ...

    SCNNode        * _audioNode;
    SCNAudioSource * _deathSource;
    SCNAudioPlayer * _player;
}

初始化:

NSString * sceneName = @ZOMBIE;
SCNScene *scene2 = [SCNScene sceneNamed:sceneName];

_undead = [SCNNode node];
for(SCNNode * node in scene2.rootNode.childNodes)
{
    [_undead addChildNode:node];
    [node removeAllAnimations];
}
[_undead setScale:(SCNVector3Make(0.024, 0.02, 0.024))];

[self addChildNode:_undead];
[_undead removeAllAnimations];

_currentAnimation = _idleAnimation;
_currAnimationkey = @"resting";

[_undead addAnimation:_currentAnimation forKey:_currAnimationkey];

动画和事件:

SCNAnimationEvent * event2 = [SCNAnimationEvent animationEventWithKeyTime:0.9 block:^(CAAnimation * _Nonnull animation, id  _Nonnull animatedObject, BOOL playingBackward)
{
    [self.delegate finishedDeathAnimation];
}];

_death1 = anims.death1.mutableCopy;
[_death1 setDelegate:self];
[_death1 setFillMode:kCAFillModeForwards];
_death1.removedOnCompletion = NO;
[_death1 setAnimationEvents:@[event2]];

动画调用:

- (void)die
{

    if([_currAnimationkey isEqualToString:@"dead"])
    {
        return;
    }

   [_undead removeAllAnimations];
   CAAnimation * death = nil;



    int anim = arc4random_uniform(3);
    if(anim < 1)
    {
        death = _death1;
    }
    else if(anim < 2)
    {
        death = _death2;
    }
    else
    {
        death = _death3;
    }

    _currAnimationkey = @"dead";
    _currentAnimation = death;

}

//获取表示节点的Helper方法

- (SCNNode *)getSnapNode
{
    SCNNode * repNode = [_undead presentationNode];
    _undead.transform = repNode.transform;
    repNode = _undead.clone;
    return repNode;
}

//回调调用并尝试获取位置:

- (void)finishedDeathAnimation
{
    SCNPlane * bloodgeometry = [SCNPlane planeWithWidth:4 height:4];
    bloodgeometry.firstMaterial.diffuse.contents = [NSImage imageNamed:@"blood"];

    SCNNode * bloodNode = [SCNNode node];
    [bloodNode setEulerAngles:SCNVector3Make(-M_PI_2, 0, 0)];
    bloodNode.geometry = bloodgeometry;

    //Bip01_Pelvis
    SCNNode * deadBody = [_unit getSnapNode];

    SCNNode * pelvis = [deadBody childNodeWithName:@"Bip01_Pelvis" recursively:YES];

    SCNNode * present = pelvis.presentationNode;
    SCNVector3 position = [self convertPosition:present.position toNode:self.parentNode];

   NSLog(@"pelvis position %lf,%lf,%lf", present.position.x, present.position.y, present.position.z); //Always {0,0,0}


    bloodNode.position = SCNVector3Make(position.x, 0.0001, position.z);

    [self.parentNode addChildNode:bloodNode];

    [self removeFromParentNode];
}

编辑 2

我也试着简化一下:

另一个辅助方法:

//在亡灵/单位类中

- (SCNVector3)getPosition
{
    SCNNode * repNode = [[_undead childNodeWithName:@"Bip01_Pelvis" recursively:YES] presentationNode];
    return repNode.position;
}

回调时:

- (void)finishedDeathAnimation
{
    position = [_unit getPosition];
    NSLog(@"pelvis position %lf,%lf,%lf", position.x, position.y, position.z); //Alway 0,0,0 as well :(
}

【问题讨论】:

    标签: macos cocoa scenekit caanimation scnnode


    【解决方案1】:

    很难找到像我这样的人仍然相信 Objective C 而不是 swift 这就是我愿意提供全面帮助的原因。

    对于从 Blender 作为 Collada 导出的动画,我遇到了这个问题,但在几次尝试后成功获得了实际位置。

    使用presentationNode 是正确的方法,但是您需要在制作动画时从孩子那里获取它,例如,这是为一个名为_monkey 的节点运行动画的方法,请注意,在最后的代码中,我从孩子那里得到了_present。 presentationNode 不是来自 _monkey.presentationNode 也必须在枚举期间而不是之后获取

    所以首先我需要定义

    NSNode * _present; 
    

    然后我会播放动画

       [_monkey enumerateChildNodesUsingBlock:^(SCNNode *child, BOOL *stop)
         {
             for(NSString *key in child.animationKeys)
             {               // for every animation key
                 CAAnimation *animation = [child animationForKey:key]; // get the animation
                 animation.usesSceneTimeBase = NO;                     // make it system time based
                 animation.repeatCount = FLT_MAX;                      // make it repeat forever
                 animation.speed = 0.2;
                 [child addAnimation:animation forKey:key];            // animations are copied upon addition, so we have to replace the previous animation
             }
             _present = child.presentationNode;
         }];
    

    然后在渲染下,我可以检查随着动画移动而变化的结果(另外,如果你使用过 iOS11,你可以检查 worldPosition 而不是 position,它也会得到很好的结果)。

    - (void)renderer:(id <SCNSceneRenderer>)renderer didSimulatePhysicsAtTime:(NSTimeInterval)time
    {
         NSLog(@" Location X:%f Y:%f Z:%f", _present.position.x, _present.position.y, _present.position.z);
    
    }
    

    结果出来了

    Y:-2.505034 Z:4.426160
    2017-10-11 04:42:19.700435+0200 monkey[547:137368]  Location X:-5.266642 Y:-2.480119 Z:4.427162
    2017-10-11 04:42:19.720763+0200 monkey[547:137368]  Location X:-5.215315 Y:-2.455228 Z:4.428163
    2017-10-11 04:42:19.740449+0200 monkey[547:137346]  Location X:-5.163589 Y:-2.430143 Z:4.429171
    2017-10-11 04:42:19.760397+0200 monkey[547:137368]  Location X:-5.112190 Y:-2.405216 Z:4.430173
    2017-10-11 04:42:19.780557+0200 monkey[547:137346]  Location X:-5.060925 Y:-2.380355 Z:4.431173
    2017-10-11 04:42:19.800418+0200 monkey[547:137342]  Location X:-5.008560 Y:-2.355031 Z:4.432024
    

    这给了我很好的结果。希望它对你有用。

    【讨论】:

      【解决方案2】:

      没有动画正在运行,至少在您向我们展示的代码中没有。在动画播放时检查演示节点的位置,可能在 renderer:updateAtTime: 中(请参阅 SCNRendererDelegate)。

      【讨论】:

      • 我确保动画正在运行,我制作了一个 SCNAnimationEvent 以在它接近尾声时获取委托 - 并尝试从演示节点提取位置 - 但它总是返回 SCNVectorZero :-(
      • 请编辑您的问题,向我们展示您实际使用的代码,包括启动动画的代码。这些东西的时间和顺序很重要,你没有给我们太多的继续。
      • 先生。哈尔,我编辑了我的问题并添加了几乎所有相关代码
      • 好吧,我刚刚放弃了,我会在需要的位置从 Max 中导出 DAE - 可悲非常可悲 :(。一般我认为 SceneKit 团队应该重新制作动画 - 使其更适合游戏开发和优化不知何故,因为现在动画占用了我 80% 的循环时间,这迫使我在不到 2 毫秒的时间内完成所有更新逻辑,这太糟糕了。
      • 您的演示节点克隆对我来说看起来很狡猾。但我还没有时间深入调查。请提交雷达!
      猜你喜欢
      • 2021-05-22
      • 1970-01-01
      • 2018-03-28
      • 2016-03-25
      • 2014-12-05
      • 2017-01-18
      • 2019-05-02
      • 2019-10-29
      • 2016-12-20
      相关资源
      最近更新 更多