Недавно я имел эта же проблема, как преобразовать крутящий момент из локального пространства объекта в мировое пространство, требуемый методом applyTorque
. Проблема с использованием методов узла convertPosition:toNode
и fromNode
s заключается в том, что они также применяют перевод узла к крутящий момент, так что это будет работать только тогда, когда узел равен 0,0,0. Что эти методы делают, так это рассматривать SCNVector3, как если бы это vec4 с aw компонентом 1.0. Мы просто хотим применить вращение, другими словами, мы хотим, чтобы вес компонента vec4 равным 0. В отличие от SceneKit, GLKit дает нам 2 варианта для того, как мы хотим, чтобы наши vec3s быть умножены:
GLKMatrix4MultiplyVector3 где
входной вектор обрабатывается как 4-компонентный вектор с w-компонентой 0.0.
и GLKMatrix4MultiplyVector3WithTranslation, где
Входной вектор обрабатывают, как это было 4-компонентный вектор с ш-составляющей 1,0.
То, что мы хотим здесь, это первое, а не ротация, а не перевод.
Итак, мы можем совершить кругосветное путешествие до GLKit. Для преобразования, например, локальную ось х (1,0,0), например, поворот, шаг к глобальной оси, необходимой для приложения крутящего момента, будет выглядеть следующим образом:
let local = GLKMatrix4MultiplyVector3(SCNMatrix4ToGLKMatrix4(node.presentationNode.worldTransform), GLKVector3(v: (1,0,0)))
node.physicsBody?.applyTorque(SCNVector4(local.x, local.y, local.z, 10), impulse: false)
Однако более Swiftian подход будет для добавления оператора *
для mat4 * vec3, который рассматривает vec3 как vec4 с компонентом 0,0 w.Как это:
func * (left: SCNMatrix4, right: SCNVector3) -> SCNVector3 { //multiply mat4 by vec3 as if w is 0.0
return SCNVector3(
left.m11 * right.x + left.m21 * right.y + left.m31 * right.z,
left.m12 * right.x + left.m22 * right.y + left.m32 * right.z,
left.m13 * right.x + left.m23 * right.y + left.m33 * right.z
)
}
Хотя этот оператор делает предположение о том, как мы хотим, чтобы наши vec3s быть умножены, мои рассуждения в том, что, как convertPosition
методы уже рассматривать ш как 1, было бы излишним иметь *
оператора что тоже сделал это.
Вы также можете добавить mat4 * SCNVector4 оператор, который позволит пользователю выбрать в явной или не хотят они ж быть 0 или 1.
Таким образом, вместо того, чтобы обе стороны от SceneKit к GLKit, мы можем просто написать:
let local = node.presentationNode.worldTransform * SCNVector3(1,0,0)
node.physicsBody?.applyTorque(SCNVector4(local.x, local.y, local.z, 10), impulse: false)
Вы можете использовать этот метод, чтобы применить вращение по нескольким осям с одной applyTorque
вызова. Так скажите, если у вас есть вход для ввода, где вы хотите, чтобы x на палке был рысканием (локальная ось yUp), а y на палке - шаг (локальная ось x), но с типом полета-sim «вниз, чтобы отступить/вверх ", то вы можете установить его на SCNVector3(input.y, -input.x, 0)
большое спасибо за ответ. К сожалению, для меня это не работает. Я подозреваю, что это потому, что мои объекты не находятся в центре моей сцены и не соответствуют миру. У меня есть решение, которое работает (опубликовано), но я не думаю, что оно красивое, точное или оптимизированное. – nekiTamoTip
Это работало как шарм для меня, спасибо! (Если бы обновить некоторый код до Swift 2, но не biggie.) – BFeher