SceneKit skeleton 3D animation

134 Views Asked by At

i am implementing an app for iPhone6S that helps disabled people to gain back their limbs control by training using a virtual trainer.

This virtual trainer performs simple movements such as raising and lowering an arm, raising and lowering a leg, and then combines them in various rhythmic patterns.

Due to the target platform, I cannot make use of the powerful ARKit, and therefore I have to have to rely on SceneeKit alone.

My code is currently able to load a dae, and applying multiple actions to the skeleton. However I am facing problems in understanding the behavior of SCNAction.rotateTo and SCNAction.rotateBy


let DegreesPerRadians = Float(Double.pi/180)

func convertToRadians(angle:Float) -> Float {
    return angle * DegreesPerRadians
}

func convertToRadians(angle:CGFloat) -> CGFloat {
    return CGFloat(CGFloat(angle) * CGFloat(DegreesPerRadians))
}

    var x45  = SCNAction.rotateBy( x: convertToRadians(angle: 45), y: 0, z: 0,  duration: 0.2)
    var x45r = SCNAction.rotateBy( x: convertToRadians(angle: -45), y: 0, z: 0, duration: 0.2)

  func FOL()->SCNAction! {
        let human            = getHuman()
        let bodyOfHuman      = human?.childNode(withName: "Body", recursively: true)
        let bodyRealSkeleton = bodyOfHuman?.skinner?.skeleton
        let leftLegBone         = bodyRealSkeleton?.childNode(withName: "mixamorig_LeftLeg", recursively: true)
        let leftLegKick = SCNAction.customAction(duration: 0.1) { [self]
            (node, elapsedTime) in leftLegBone?.runAction(x45)
        }
        return leftLegKick
    }
    
    func FOLrev()->SCNAction! {
        let human            = getHuman()
        let bodyOfHuman      = human?.childNode(withName: "Body", recursively: true)
        let bodyRealSkeleton = bodyOfHuman?.skinner?.skeleton
        let leftLegBone         = bodyRealSkeleton?.childNode(withName: "mixamorig_LeftLeg", recursively: true)
        let leftLegKick = SCNAction.customAction(duration: 0.1) { [self]
            (node, elapsedTime) in leftLegBone?.runAction(x45r)
        }
        return leftLegKick
    }

var actionSequence=[FOL(),FOLrev()]

The above code is then called with

 _scene?.rootNode.runAction(SCNAction.sequence(actionSequence))

It results into the model properly bending the left leg and straightening it.

However when using instead "rotateTo" it goes into the opposite direction and does not "come back".

screenshot-rotateTo

I watched all DevCon SceneKit materials and sample code but could not find any explanation or guidance.

My real goal is to add more complex actions, such as clapping hands, and when the same approach is tried on those patterns (that require 3-4 rotations) then the results are less predictable.

1

There are 1 best solutions below

0
Luca Toldo On

The answer to this question is that when using rotateTo, in order to go "back" one should use the starting position of the specific angle.

In the specific example, using rotateTo means to use following code

var x45  = SCNAction.rotateTo( x: convertToRadians(angle: 45), y: 0, z: 0,  duration: 0.2)
var x45r = SCNAction.rotateTo( x: 0, y: 0, z: 0, duration: 0.2)