2

我需要定向一个节点以将其 Z 轴指向 3D 中的另一个节点。是的,LookAtConstraint 的完美工作。对于我的大部分工作,LookAt 都很好。但是当我将 LookAt 应用于特定节点时,我无法再使用 SCNAction 为该节点的翻译设置动画。想象一个氢原子在离子化时离开一个分子。需要方向来正确旋转分子上氢原子和氧原子之间的键(圆柱体)。

我可以将键从氧定向到氢并激活。但这使大多数其他与 LookAt 相处得很好的债券迷失了方向。

在意识到它回答了一个稍微不同的问题之前,我给了这个强大的尝试: 计算旋转以查看 3D 点?

4

2 回答 2

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

希望这会有所帮助。

于 2016-04-29T17:18:22.483 回答
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)
}
于 2017-06-30T09:19:33.433 回答