swiftarkitrealitykitarbodyanchor

How to get Human Body Height from ARBodyAnchor?


I am trying to get real-world human body height from ARBodyAnchor. I understand that I can get real-world distance between body joints. For example hip to foot-joint as in code below. But how do I get distance from top of head to bottom of foot?

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    if anchor is ARBodyAnchor {
        let footIndex = ARSkeletonDefinition.defaultBody3D.index(for: .leftFoot)
        let footTransform = ARSkeletonDefinition.defaultBody3D.neutralBodySkeleton3D!.jointModelTransforms[footIndex]
        let distanceFromHipOnY = abs(footTransform.columns.3.y)
        print(distanceFromHipOnY)
    }
}

Solution

  • Read this post if you need to setup a custom model for MoCap.

    enter image description here

    The default height of ARSkeleton3D from right_toes_joint (or if you wish left_toes_joint) to head_joint is 1.71 meters. And since head_joint in Apple's skeletal system's definition is the upmost skeleton's point, you can use the common skull's height – from eye line to crown.

    In other words, the distance from neck_3_joint to head_joint in virtual model's skeleton is approximately the same as from head_joint to crown.

    enter image description here

    There are 91 joint in ARSkeleton3D:

    print(bodyAnchor.skeleton.jointModelTransforms.count)      // 91
    

    Code:

    extension ViewController: ARSessionDelegate {
    
        func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
        
            for anchor in anchors {
            
                guard let bodyAnchor = anchor as? ARBodyAnchor
                else { return }
    
                let skeleton = bodyAnchor.skeleton
    
                for (i, joint) in skeleton.definition.jointNames.enumerated() {
                    print(i, joint)
    
                    // [10] right_toes_joint
                    // [51] head_joint
                }
            
                let toesJointPos = skeleton.jointModelTransforms[10].columns.3.y
                let headJointPos = skeleton.jointModelTransforms[51].columns.3.y
    
                print(headJointPos - toesJointPos)       // 1.6570237 m
            }
        }
    }
    

    However, we have a compensator:

    bodyAnchor.estimatedScaleFactor
    

    ARKit must know the height of a person in the camera feed to estimate an accurate world position for the person's body anchor. ARKit uses the value of estimatedScaleFactor to correct the body anchor's position in the physical environment.

    The default real-world body is 1.8 meters tall. (some kind of mismatch...)

    The default value of estimatedScaleFactor is 1.0.

    If you set:

    let config = ARBodyTrackingConfiguration()
    config.automaticSkeletonScaleEstimationEnabled = true
    arView.session.run(config, options: [])
    

    ARKit sets this property to a value between 0.0 and 1.0.