如何找到将 SCNNode 从球体上的一个点移动到另一个点的 SCNMatrix4 变换?
How do I find the SCNMatrix4 transformation that moved an SCNNode from one point on a sphere to another?
我正在尝试重新调整圆锥体的方向,使其在我围绕球体移动时底部平放在球体表面上。
球体的半径为 4,以原点为中心。
我试图推导转换的四元数,但使用圆锥本身的枢轴 属性 似乎更容易。
我可以通过将其旋转已知角度使其在轴上的简单位置工作,但我无法弄清楚如何从圆锥体的位置向量推断出变换。我想我需要采用表示锥体默认方向的 Vector 和球体表面上点的位置向量,并计算出将默认方向转换为我需要的新方向的 SCNMatrix4。然后我可以用它来转换 SCNNode 的枢轴。部分问题是我不知道默认方向向量是什么。
这是我目前所拥有的(它不起作用):
let distanceFromCentre = Float(4.0)
let newConeNode = SCNNode(geometry: SCNCone(topRadius: 0, bottomRadius: 0.5, height: 1.0))
let radialLocationVector = SCNVector3Make(0.0, 1.0, 1.0)
let radialLocationVectorMagnitude = pow((pow(radialLocationVector.x,2) + pow(radialLocationVector.y,2) + pow(radialLocationVector.z,2)),0.5)
let radialLocationUnitVector = SCNVector3Make(radialLocationVector.x/radialLocationVectorMagnitude, radialLocationVector.y/radialLocationVectorMagnitude, radialLocationVector.z/radialLocationVectorMagnitude)
let surfaceLocationVector = SCNVector3Make(radialLocationUnitVector.x*distanceFromCentre, radialLocationUnitVector.y*distanceFromCentre, radialLocationUnitVector.z*distanceFromCentre)
newConeNode.position = surfaceLocationVector
let nodePivotRotationMatrix = SCNMatrix4MakeRotation(0,radialLocationUnitVector.x, radialLocationUnitVector.y, radialLocationUnitVector.z) //This doesn't work
let nodePivotTranslationMatrix = SCNMatrix4MakeTranslation(0, -0.5, 0)
newConeNode.pivot = SCNMatrix4Mult(nodePivotRotationMatrix, nodePivotTranslationMatrix)
newConeNode.name = "MyCone"
newConeNode.geometry?.firstMaterial?.diffuse.contents = UIColor(red: 0.2, green: 0, blue: 0.8, alpha: 1.0)
scnView.scene?.rootNode.addChildNode(newConeNode)
感谢收到的任何帮助
我通过使用叉积找到旋转轴并使用点积找到旋转角度来实现这一点。您需要将 SCNVector 转换为 GLKVector 才能使用这些函数。代码如下:
let distanceFromCentre = globeNode!.geometry!.boundingSphere.radius
let newConeNode = SCNNode(geometry: SCNCone(topRadius: 0, bottomRadius: 0.5, height: 1.0))
let northPoleLocationVector = SCNVector3Make(0.0, distanceFromCentre, 0)
newConeNode.position = northPoleLocationVector
let newLocationDirectionVector = SCNVector3Make(1.0, 2.0, 3.0)
let magnitudeLocation = Float(pow((pow(newLocationDirectionVector.x,2) + pow(newLocationDirectionVector.y,2) + pow(newLocationDirectionVector.z,2)),0.5))
let newLocationUnitVector = SCNVector3Make(newLocationDirectionVector.x/magnitudeLocation, newLocationDirectionVector.y/magnitudeLocation, newLocationDirectionVector.z/magnitudeLocation)
let newLocationOnSurface = SCNVector3Make(newLocationUnitVector.x*distanceFromCentre, newLocationUnitVector.y*distanceFromCentre, newLocationUnitVector.z*distanceFromCentre)
let locationTranslationVector = SCNVector3Make(northPoleLocationVector.x-newLocationOnSurface.x, northPoleLocationVector.y-newLocationOnSurface.y, northPoleLocationVector.z-newLocationOnSurface.z) //Not sure why this works - the vector from A to B should be b-a not a-b
let surfaceTranslationMatrix = SCNMatrix4MakeTranslation(locationTranslationVector.x, locationTranslationVector.y, locationTranslationVector.z)
let northPoleLocationVectorGLK = GLKVector3Make(northPoleLocationVector.x, northPoleLocationVector.y, northPoleLocationVector.z)
let magnitudeSLV = GLKVector3Length(northPoleLocationVectorGLK)
let newLocationOnSurfaceVectorGLK = GLKVector3Make(newLocationOnSurface.x, newLocationOnSurface.y, newLocationOnSurface.z)
let magnitudeNLV = GLKVector3Length(newLocationOnSurfaceVectorGLK)
let normalToTransformGLK = GLKVector3CrossProduct(northPoleLocationVectorGLK, newLocationOnSurfaceVectorGLK)
let angleOfRotation = acos(GLKVector3DotProduct(northPoleLocationVectorGLK, newLocationOnSurfaceVectorGLK)/(magnitudeNLV*magnitudeSLV))
let coneRotationMatrix = SCNMatrix4MakeRotation(-angleOfRotation, normalToTransformGLK.x, normalToTransformGLK.y, normalToTransformGLK.z)
let combinedTransformMatrix = SCNMatrix4Mult(surfaceTranslationMatrix, coneRotationMatrix)
newConeNode.pivot = combinedTransformMatrix
newConeNode.name = "MyCone"
newConeNode.geometry?.firstMaterial?.diffuse.contents = UIColor(red: 0.2, green: 0, blue: 0.8, alpha: 1.0)
scnView.scene?.rootNode.addChildNode(newConeNode)
我正在尝试重新调整圆锥体的方向,使其在我围绕球体移动时底部平放在球体表面上。
球体的半径为 4,以原点为中心。
我试图推导转换的四元数,但使用圆锥本身的枢轴 属性 似乎更容易。
我可以通过将其旋转已知角度使其在轴上的简单位置工作,但我无法弄清楚如何从圆锥体的位置向量推断出变换。我想我需要采用表示锥体默认方向的 Vector 和球体表面上点的位置向量,并计算出将默认方向转换为我需要的新方向的 SCNMatrix4。然后我可以用它来转换 SCNNode 的枢轴。部分问题是我不知道默认方向向量是什么。
这是我目前所拥有的(它不起作用):
let distanceFromCentre = Float(4.0)
let newConeNode = SCNNode(geometry: SCNCone(topRadius: 0, bottomRadius: 0.5, height: 1.0))
let radialLocationVector = SCNVector3Make(0.0, 1.0, 1.0)
let radialLocationVectorMagnitude = pow((pow(radialLocationVector.x,2) + pow(radialLocationVector.y,2) + pow(radialLocationVector.z,2)),0.5)
let radialLocationUnitVector = SCNVector3Make(radialLocationVector.x/radialLocationVectorMagnitude, radialLocationVector.y/radialLocationVectorMagnitude, radialLocationVector.z/radialLocationVectorMagnitude)
let surfaceLocationVector = SCNVector3Make(radialLocationUnitVector.x*distanceFromCentre, radialLocationUnitVector.y*distanceFromCentre, radialLocationUnitVector.z*distanceFromCentre)
newConeNode.position = surfaceLocationVector
let nodePivotRotationMatrix = SCNMatrix4MakeRotation(0,radialLocationUnitVector.x, radialLocationUnitVector.y, radialLocationUnitVector.z) //This doesn't work
let nodePivotTranslationMatrix = SCNMatrix4MakeTranslation(0, -0.5, 0)
newConeNode.pivot = SCNMatrix4Mult(nodePivotRotationMatrix, nodePivotTranslationMatrix)
newConeNode.name = "MyCone"
newConeNode.geometry?.firstMaterial?.diffuse.contents = UIColor(red: 0.2, green: 0, blue: 0.8, alpha: 1.0)
scnView.scene?.rootNode.addChildNode(newConeNode)
感谢收到的任何帮助
我通过使用叉积找到旋转轴并使用点积找到旋转角度来实现这一点。您需要将 SCNVector 转换为 GLKVector 才能使用这些函数。代码如下:
let distanceFromCentre = globeNode!.geometry!.boundingSphere.radius
let newConeNode = SCNNode(geometry: SCNCone(topRadius: 0, bottomRadius: 0.5, height: 1.0))
let northPoleLocationVector = SCNVector3Make(0.0, distanceFromCentre, 0)
newConeNode.position = northPoleLocationVector
let newLocationDirectionVector = SCNVector3Make(1.0, 2.0, 3.0)
let magnitudeLocation = Float(pow((pow(newLocationDirectionVector.x,2) + pow(newLocationDirectionVector.y,2) + pow(newLocationDirectionVector.z,2)),0.5))
let newLocationUnitVector = SCNVector3Make(newLocationDirectionVector.x/magnitudeLocation, newLocationDirectionVector.y/magnitudeLocation, newLocationDirectionVector.z/magnitudeLocation)
let newLocationOnSurface = SCNVector3Make(newLocationUnitVector.x*distanceFromCentre, newLocationUnitVector.y*distanceFromCentre, newLocationUnitVector.z*distanceFromCentre)
let locationTranslationVector = SCNVector3Make(northPoleLocationVector.x-newLocationOnSurface.x, northPoleLocationVector.y-newLocationOnSurface.y, northPoleLocationVector.z-newLocationOnSurface.z) //Not sure why this works - the vector from A to B should be b-a not a-b
let surfaceTranslationMatrix = SCNMatrix4MakeTranslation(locationTranslationVector.x, locationTranslationVector.y, locationTranslationVector.z)
let northPoleLocationVectorGLK = GLKVector3Make(northPoleLocationVector.x, northPoleLocationVector.y, northPoleLocationVector.z)
let magnitudeSLV = GLKVector3Length(northPoleLocationVectorGLK)
let newLocationOnSurfaceVectorGLK = GLKVector3Make(newLocationOnSurface.x, newLocationOnSurface.y, newLocationOnSurface.z)
let magnitudeNLV = GLKVector3Length(newLocationOnSurfaceVectorGLK)
let normalToTransformGLK = GLKVector3CrossProduct(northPoleLocationVectorGLK, newLocationOnSurfaceVectorGLK)
let angleOfRotation = acos(GLKVector3DotProduct(northPoleLocationVectorGLK, newLocationOnSurfaceVectorGLK)/(magnitudeNLV*magnitudeSLV))
let coneRotationMatrix = SCNMatrix4MakeRotation(-angleOfRotation, normalToTransformGLK.x, normalToTransformGLK.y, normalToTransformGLK.z)
let combinedTransformMatrix = SCNMatrix4Mult(surfaceTranslationMatrix, coneRotationMatrix)
newConeNode.pivot = combinedTransformMatrix
newConeNode.name = "MyCone"
newConeNode.geometry?.firstMaterial?.diffuse.contents = UIColor(red: 0.2, green: 0, blue: 0.8, alpha: 1.0)
scnView.scene?.rootNode.addChildNode(newConeNode)