我需要将一个节点定向为将其Z轴指向另一个3D节点。是的,LookAtConstraint的完美工作。对于我的大多数工作,LookAt都很好。但是,当我将LookAt应用于特定节点时,我无法再使用SCNAction为该节点的转换设置动画。想象一下氢原子在离子化时离开分子。需要使取向适当地旋转分子上的氢和氧原子之间的键(圆柱)。
我可以将氧从氧气定向到氢气和动力。但是这使得大多数其他债券与LookAt的关系变得很糟糕。
在实现它回答一个稍微不同的问题之前,我给了它一个强大的尝试: https://codepen.io/friendfx/pen/RrjpeL
答案 0 :(得分: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 :(得分: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)
}