Получение поворотов костей из 3D-скелета в ARKit 3

Я пытаюсь связать повороты костей с их родителями, но в итоге получаю довольно странные углы.

Я пробовал все, умножение матриц, смещения, перестановку осей, и безуспешно.

guard let bodyAnchor = anchor as? ARBodyAnchor else { continue }

let skeleton = bodyAnchor.skeleton
let jointTransforms = skeleton.jointLocalTransforms

for (i, jointTransform) in jointTransforms.enumerated() {

    //RETRIEVE ANGLES HERE
}

В //RETRIEVE ANGLES HERE я пробовал разные подходы:

let n = SCNNode()
n.transform = SCNMatrix4(jointTransform)
print(n.eulerAngles)

В этой попытке я установил для jointTransformation значение SCNNode.transform, чтобы я мог получить eulerAngles, сделать их удобочитаемыми и попытаться понять, что происходит.

Я работаю над некоторыми суставами, но я думаю, что это чистое совпадение или удача, потому что остальные кости вращаются очень странно.

В другой попытке я получаю их с помощью jointModelTransforms (модель вместо локальной), поэтому все преобразования относятся к корневой кости скелета.

При таком подходе я выполняю умножение матриц следующим образом:

LocalMatrix = Inverse(JointModelMatrix) * (ParentJointModelMatrix)

Чтобы получить вращение относительно своего родителя, но та же ситуация, некоторые кости вращаются нормально, другие вращаются странно. Чистое совпадение, держу пари.

Почему я хочу получить ротацию костей?

Я пытаюсь создать приложение MoCap на своем телефоне, которое передает в Blender вращения, пытаясь создать из него файлы .BVH, чтобы я мог использовать их в Blender.

Это моя собственная установка:

Я делал это раньше с Kinect, но несколько дней безуспешно пытался сделать это на ARKit 3 :(


person Carlos C    schedule 23.09.2019    source источник


Ответы (2)


Использование simd_quatf(from:to:) с правильным вводом должно сделать это. У меня были проблемы со странными углами, пока я не начал нормализовать векторы:

guard let bodyAnchor = anchor as? ARBodyAnchor else { continue }

let skeleton = bodyAnchor.skeleton
let jointTransforms = skeleton.jointLocalTransforms

for (i, jointTransform) in jointTransforms.enumerated() {
    // First i filter out the root (Hip) joint because it doesn't have a parent
    let parentIndex = skeleton.definition.parentIndices[i]
    guard parentIndex >= 0 else { continue } // root joint has parent index of -1

    //RETRIEVE ANGLES HERE
    let jointVectorFromParent = simd_make_float3(jointTransform.columns.3)
    let referenceVector: SIMD3<Float>
    if skeleton.definition.parentIndices[parentIndex] >= 0 {
         referenceVector = simd_make_float3(jointTransforms[parentIndex].columns.3)
    } else {
         // The parent joint is the Hip joint which should have
         // a vector of 0 going to itself
         // It's impossible to calculate an angle from a vector of length 0,
         // So we're using a vector that's just pointing up
         referenceVector = SIMD3<Float>(x: 0, y: 1, z: 0)
    }
    // Normalizing is important because simd_quatf gives weird results otherwise
    let jointNormalized = normalize(jointVectorFromParent)
    let referenceNormalized = normalize(referenceVector)
    let orientation = simd_quatf(from: referenceNormalized, to: jointNormalized)
    print("angle of joint \(i) = \(orientation.angle)")
}

Однако следует иметь в виду одну важную вещь: ARKit3 отслеживает только некоторые суставы (насколько мне известно, названные суставы в ARSkeleton.JointName). Другие суставы экстраполированы с использованием стандартизированного скелета. Это означает, что угол, который вы получаете, например, для локтя, не будет точным углом, который имеет локоть отслеживаемого человека.

person jaetzold    schedule 10.11.2019
comment
Попробую :-) Сообщу - person Carlos C; 10.11.2019
comment
Пробовал, но углы вроде не изменились. Я всегда получаю Т-позу в переменной orientation, независимо от того, движется ли человек. Я делаю это неправильно? Я просто взял переменную orientation для каждой кости и применил ее к своему сфальсифицированному персонажу. Должен ли я что-то сделать с этой ориентацией, прежде чем применить ее к моему персонажу? - person Carlos C; 11.11.2019
comment
Хорошо, TBH, что я на самом деле использую в своем собственном проекте, так это jointModelTransforms, а затем разницу между положением сустава и положением родительского сустава, чтобы получить вектор кости. И это определенно работает для меня. - person jaetzold; 12.11.2019
comment
Можете ли вы уточнить свой ответ с кодом? Так что я понимаю, что вы делаете. Например, я не вижу JointModelTransform в вашем опубликованном ответе. - person Carlos C; 12.11.2019

Просто предположение… это работает?

  let skeleton = bodyAnchor.skeleton
  let jointTransforms = skeleton.jointLocalTransforms

  for (i, jointTransform) in jointTransforms.enumerated() {
    print(Transform(matrix: jointTransform).rotation)
  }
person Tobias Zucali    schedule 20.10.2019
comment
Это то, что я уже пробовал, и я могу сказать, что ArKit 3 на данный момент ужасен для MoCap. T-поза даже не обнулена. :( Если кто-то чего-то добился, оставьте комментарий - person Carlos C; 28.10.2019