SceneKit,沿相机方向投影节点
SceneKit, projecting a node along camera orientation
使用 SceneKit,我看到一个连接了相机的节点具有 eulerAngles(弧度角的 SCNVector3)和方向(SCNQuaternion)
我的 cameraNode 位于 0,0,0 并且可以随时改变它的方向。
我需要做 hitTestWithSegmentFromPoint...toPoint...
fromPoint 总是已知的。
但是我需要根据相机方向投影一个位于相机线上的远点。
我的想法还没有正确地抓住四元数,而且我没有得到基于 eulerAngles 的任何地方。
使用一些线性代数
func findNextPoint(p0: SCNVector3, direction: SCNVector3) -> SCNVector3{
var x = Float()
var y = Float()
var z = Float()
let t = 100 as Float
x = p0.x + t * direction.x
y = p0.y + t * direction.y
z = p0.z + t * direction.z
let result = SCNVector3Make(x, y, z)
return result
}
这使用 p0 作为起点,然后在给定方向上找到您想要的下一个点。 t 是向量的长度,或者你想从 p0 开始的距离。
要找到相机指向的方向,您必须获得它的旋转并乘以旋转矩阵。
func calculateCameraDirection(cameraNode: SCNNode) -> GLKVector3 {
let x = -cameraNode.rotation.x
let y = -cameraNode.rotation.y
let z = -cameraNode.rotation.z
let w = cameraNode.rotation.w
let cameraRotationMatrix = GLKMatrix3Make(cos(w) + pow(x, 2) * (1 - cos(w)),
x * y * (1 - cos(w)) - z * sin(w),
x * z * (1 - cos(w)) + y*sin(w),
y*x*(1-cos(w)) + z*sin(w),
cos(w) + pow(y, 2) * (1 - cos(w)),
y*z*(1-cos(w)) - x*sin(w),
z*x*(1 - cos(w)) - y*sin(w),
z*y*(1 - cos(w)) + x*sin(w),
cos(w) + pow(z, 2) * ( 1 - cos(w)))
let cameraDirection = GLKMatrix3MultiplyVector3(cameraRotationMatrix, GLKVector3Make(0.0, 0.0, -1.0))
return cameraDirection
}
然后您只需使用两个坐标执行 hitTest。在这种情况下,我使用了 rayTestWithSegmentFromPoint:ToPoint ,但您可以在那里使用任何其他类型的测试,例如 hitTestWithSegmentFromPoint:toPoint: .
func raycastTest(cameraDirection: GLKVector3) -> SCNVector3{
let nextPoint = findNextPoint(cameraNode.position, direction: SCNVector3Make(cameraDirection.x, cameraDirection.y, cameraDirection.z))
let hitTest = sceneView.scene!.physicsWorld.rayTestWithSegmentFromPoint(cameraNode.position, toPoint: nextPoint, options: nil)
if hitTest.count > 0 {
return (hitTest.first?.worldCoordinates)!
}else{
return nextPoint
}
}
使用 SceneKit,我看到一个连接了相机的节点具有 eulerAngles(弧度角的 SCNVector3)和方向(SCNQuaternion)
我的 cameraNode 位于 0,0,0 并且可以随时改变它的方向。
我需要做 hitTestWithSegmentFromPoint...toPoint...
fromPoint 总是已知的。
但是我需要根据相机方向投影一个位于相机线上的远点。
我的想法还没有正确地抓住四元数,而且我没有得到基于 eulerAngles 的任何地方。
使用一些线性代数
func findNextPoint(p0: SCNVector3, direction: SCNVector3) -> SCNVector3{
var x = Float()
var y = Float()
var z = Float()
let t = 100 as Float
x = p0.x + t * direction.x
y = p0.y + t * direction.y
z = p0.z + t * direction.z
let result = SCNVector3Make(x, y, z)
return result
}
这使用 p0 作为起点,然后在给定方向上找到您想要的下一个点。 t 是向量的长度,或者你想从 p0 开始的距离。
要找到相机指向的方向,您必须获得它的旋转并乘以旋转矩阵。
func calculateCameraDirection(cameraNode: SCNNode) -> GLKVector3 {
let x = -cameraNode.rotation.x
let y = -cameraNode.rotation.y
let z = -cameraNode.rotation.z
let w = cameraNode.rotation.w
let cameraRotationMatrix = GLKMatrix3Make(cos(w) + pow(x, 2) * (1 - cos(w)),
x * y * (1 - cos(w)) - z * sin(w),
x * z * (1 - cos(w)) + y*sin(w),
y*x*(1-cos(w)) + z*sin(w),
cos(w) + pow(y, 2) * (1 - cos(w)),
y*z*(1-cos(w)) - x*sin(w),
z*x*(1 - cos(w)) - y*sin(w),
z*y*(1 - cos(w)) + x*sin(w),
cos(w) + pow(z, 2) * ( 1 - cos(w)))
let cameraDirection = GLKMatrix3MultiplyVector3(cameraRotationMatrix, GLKVector3Make(0.0, 0.0, -1.0))
return cameraDirection
}
然后您只需使用两个坐标执行 hitTest。在这种情况下,我使用了 rayTestWithSegmentFromPoint:ToPoint ,但您可以在那里使用任何其他类型的测试,例如 hitTestWithSegmentFromPoint:toPoint: .
func raycastTest(cameraDirection: GLKVector3) -> SCNVector3{
let nextPoint = findNextPoint(cameraNode.position, direction: SCNVector3Make(cameraDirection.x, cameraDirection.y, cameraDirection.z))
let hitTest = sceneView.scene!.physicsWorld.rayTestWithSegmentFromPoint(cameraNode.position, toPoint: nextPoint, options: nil)
if hitTest.count > 0 {
return (hitTest.first?.worldCoordinates)!
}else{
return nextPoint
}
}