2016-01-27 1 views
1

Мне нужно сориентировать один узел, чтобы указать его ось Z на другом узле в 3D. Да, идеальная работа для LookAtConstraint. И для большей части моей работы LookAt в порядке. Но когда я применяю LookAt к определенному узлу, я больше не могу анимировать перевод этого узла с помощью SCNAction. Представьте атом водорода, оставляя молекулу при ее ионизации. Ориентация необходима для правильного поворота связи (цилиндра) через водород и атом кислорода на молекуле.SceneKit: ориентируйте один узел на другой в 3Dspace

Я могу ориентировать связь от кислорода к водороду и анимировать. Но это дезориентирует большинство других облигаций, которые отлично подходили к LookAt's.

Я дал эту могучую попробовать, прежде чем понял, что отвечает на несколько иной вопрос: Calculate rotations to look at a 3D point?

+0

Как вы его решаете? Не могли бы вы поделиться своим примером кода? – ooOlly

+0

@OllyGuo https://stackoverflow.com/questions/35384392/swift-orient-y-axis-toward-another-point-in-3-d-space Ключом является использование объекта-контейнера. – bpedit

+0

спасибо большое ;-) – ooOlly

ответ

1

У меня была похожая проблема с проектом. В конце концов я понял, что мне нужно использовать несколько ограничений. Один для перевода (движения), а другой - для поиска ограничений.

Я бы переместил объект, а затем применил взгляд на ограничение; в этом случае это была камера, следующая за объектами, перемещаемыми с использованием действий. Фрагмент кода следующим образом:

let targetNodeConstraint = SCNLookAtConstraint(target: someObject) targetNodeConstraint.gimbalLockEnabled = true
let followObjectConstraint = SCNTransformConstraint(inWorldSpace: true, withBlock: { (node, matrix) -> SCNMatrix4 in let transformMatrix = SCNMatrix4MakeTranslation(
self.someObject.position.x - 1.0,
self.someObject.position.y, self.someObject.position.z + 1.0) return transformMatrix }) // Position the object behind the other object & rotate it to roadCamera.constraints = [followObjectConstraint, targetNodeConstraint]

Важно отметить, порядок, в котором ограничения добавляются к объекту с помощью массива. В приведенном выше коде я игнорирую текущую матрицу, прежде чем применить матрицу преобразования (я должен переписать этот код когда-нибудь)

Полный исходный код этого «эксперимента» находится на GitHub, когда я стараюсь.

https://github.com/ManjitBedi/CubeTrip

Будем надеяться, что это полезно.

+1

Я решил свою проблему, вообще избегая ограничений. Трюк там тоже заключался в том, чтобы использовать пару фиктивных узлов для осуществления ориентации. Спасибо за ответ, я думаю, я должен уделять больше внимания следованию моим сообщениям. – bpedit

0

Мое решение здесь. Сработайте с ситуацией, когда узел постоянно переводится в космос и всегда должен двигаться к позиции.

@discardableResult 
func yew(_ node:SCNNode, toPosition position:SCNVector3) -> Float 
{ 
    var eularAngle = SCNVector3Zero 
    let tranform = node.transform 
    var forward = GLKVector3Make(tranform.m31, tranform.m32, tranform.m33) 
    var toWard = GLKVector3Make(position.x - node.position.x, position.y - node.position.y, position.z - node.position.z) 
    forward = GLKVector3Normalize(GLKVector3Make(forward.x, 0, forward.z)) 
    toWard = GLKVector3Normalize(GLKVector3Make(toWard.x, 0, toWard.z)) 
    var dotProduct = GLKVector3DotProduct(forward,toWard) 
    dotProduct = (dotProduct > 1) ? 1 : ((dotProduct < -1) ? -1 : dotProduct) 
    var yew = acos(dotProduct) 
    if yew < 0 { 
     assert(false) 
    } 
    //toward is clockwise of forward 
    let isCW = GLKVector3CrossProduct(forward, toWard).y < 0 
    if isCW { 
     yew = -yew 
    } 
    eularAngle.y = yew 
    node.eulerAngles = SCNVector3Make(eularAngle.x + wrapperNode.eulerAngles.x, 
             eularAngle.y + wrapperNode.eulerAngles.y, 
             eularAngle.z + wrapperNode.eulerAngles.z) 
    return yew 
} 
@discardableResult 
func pitch(_ node:SCNNode, toPosition position:SCNVector3) -> Float{ 
    var eularAngle = SCNVector3Zero 
    let tranform = node.transform 
    var toWard = GLKVector3Make(position.x - node.position.x, position.y - node.position.y, position.z - node.position.z) 
    var forward = GLKVector3Make(tranform.m31, tranform.m32, tranform.m33) 
    forward = GLKVector3Normalize(forward) 
    toWard = GLKVector3Normalize(toWard) 
    var dotProduct = GLKVector3DotProduct(forward,toWard) 
    dotProduct = (dotProduct > 1) ? 1 : ((dotProduct < -1) ? -1 : dotProduct) 
    var pitch = acos(dotProduct) 
    //toward is clockwise of forward, if right vector of model and crossProfuct.x has same direction 
    let crossProduct = GLKVector3CrossProduct(forward, toWard) 
    let isCW = (crossProduct.x <= 0) != (tranform.m11 <= 0) 
    if isCW { 
     pitch = -pitch 
    } 

    eularAngle.x = pitch 

    node.eulerAngles = SCNVector3Make(eularAngle.x + node.eulerAngles.x, 
             eularAngle.y + node.eulerAngles.y, 
             eularAngle.z + node.eulerAngles.z) 
    return pitch 
} 
func orient(_ node:SCNNode, toPosition position:SCNVector3) { 
    self.yew(node, toPosition: position) 
    self.pitch(node, toPosition: position) 
} 
Смежные вопросы