Search code examples
macoscocoascenekitinverse-kinematics

How does SceneKit constraints work with bones?


I have a rigged character. I can retreive the bones nodes, and if I manually apply a rotation to those bones, I see the character switching to its new pose.

Now, if I try to set a constraint to this same bone, it just doesn't move at all. I have tried inverse kinematic constraints, and the simple billboard constraint, but no way.

Here is the code to get the bone :

SCNNode *man = [scene.rootNode childNodeWithName:@"Man" recursively:YES] ;
SCNNode *bodyOfMan = [man childNodeWithName:@"Body" recursively:YES] ;
SCNNode *bodyRealSkeleton = bodyOfMan.skinner.skeleton ;
SCNNode *headBone = [bodyRealSkeleton childNodeWithName:@"mixamorig_Head" recursively:YES] ;

If I do this :

headBone.rotation   = SCNVector4Make(0,1,0,45) ;

I get this result, showing that the head rotates properly

enter image description here

If I do this instead :

SCNBillboardConstraint  *constraint3 = [SCNBillboardConstraint billboardConstraint] ;
headBone.constraints    = @[constraint3] ;

The head remains straight forward, when it should be following the camera.

The billboard constraints works very well if I just add it to a "Box" node, but I couldn't find any way to make it work to my rigged mesh bones... And I couldn't find any way to make the SCNIKConstraint work, at all.


Solution

  • I found what was the root cause of the problem.

    I have added the man mesh to the scene in XCode, which creates a SCNReferenceNode. For some reason, you can't really move/rotate/animation that "reference node" as any other node.

    I couldn't even get its "loaded" boolean to true, though the mesh obviously appeared in my view.

    So what I did instead is remove the reference from the .scn file, and loaded the mesh programmatically in my scene like this ("ManPivot" is just a pivot node I introduced in the .scn file where I want to include my mesh) :

    SCNScene    *manScene   = [SCNScene sceneNamed:@"art.scnassets/Man.dae"] ;
    manScene.rootNode.name  = @"Man" ;
    SCNNode     *manPivot = [scene.rootNode childNodeWithName:@"ManPivot" recursively:YES] ;
    [manPivot addChildNode:[manScene.rootNode clone]] ;
    

    And I can now move/rotate/animation my mesh in any way I want. I even had inverse kinematics working.

    Conclusion : reference nodes and nodes are not the same at all...