0

I am trying to reorient a cone so that it sits with its base flat on the surface of a sphere as I move it around the sphere.

The sphere is radius 4 and centred at the origin.

I tried to deduce the quaternion for the transformation, but it seems easier to use the pivot property of the cone itself.

I can get it to work in simple places on the axes by rotating it through known angles but I can’t figure out how to deduce the transformation from the location vector of the cone. I think I need to take the Vector representing the default orientation of the cone and the location vector of the point on the surface of the sphere and work out the SCNMatrix4 that transforms the default orientation into the new one I need. Then I can use it to transform the pivot of the SCNNode. Part of the problem is that I don’t know what the default orientation Vector is.

This is what I have so far (it doesn't work):

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)

Any help gratefully received

Tim
  • 1,108
  • 13
  • 25

1 Answers1

0

I got this to work by using the cross product to find the axis of rotation and the dot product to find the angle of rotation. You need to convert from SCNVector to GLKVector to use these functions. The code is below:

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)
Tim
  • 1,108
  • 13
  • 25