Reputation: 533
I am trying to make a game in which you are given a sphere, it’s radius and a point on the surface of the sphere. I used SceneKit as my basic framework. The sphere is a SCNSphere
, the radius is a SCNCylinder
which is carefully placed such that it seems like the radius of the sphere (height of the cylinder is equal to the radius of the sphere and it is located at the centre of the sphere). The point on the surface of the sphere is a SKScene applied on the surface of the sphere as its material.
My goal is to make one end of the cylinder fixed at the centre of the sphere and rotate it such that its tip can every point on the surface of the sphere.
I am trying to achieve the same by using SCNAction
but it is nowhere near what I want it to be.
My code is :
struct SceneKitView: UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<SceneKitView>) -> SCNView {
//SCNScene
let sceneView = SCNView()
sceneView.scene = SCNScene()
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = UIColor.white
sceneView.frame = CGRect(x: 0, y: 10, width: 0, height: 1)
//A SKScene used as a material for a Sphere
let surfacematerial = SKScene(size: CGSize(width: 300, height: 200))
let point = SKShapeNode(circleOfRadius: 2)
surfacematerial.backgroundColor = SKColor.blue
point.fillColor = SKColor.red
point.lineWidth = 0
point.position = CGPoint(x: surfacematerial.size.width/2.0, y: surfacematerial.size.height/2.0)
surfacematerial.addChild(point)
//The SCNSphere
let sphere = SCNSphere(radius: CGFloat(2))
let spherematerial = SCNMaterial()
spherematerial.diffuse.contents = surfacematerial
sphere.materials = [spherematerial]
let spherenode = SCNNode(geometry: sphere)
spherenode.position = SCNVector3(x: 1.0, y: 1.0, z: 1.0)
spherenode.opacity = CGFloat(0.6)
//The radius of the sphere( a SCNCylinder )
let cylinder = SCNCylinder(radius: 0.02, height: 2.0)
let cylindernode = SCNNode(geometry: cone)
cylindernode.position = SCNVector3(x: 1, y: 2, z: 1)
cylinder.firstMaterial?.diffuse.contents = UIColor.green
//Rotating the radius
func degreesToRadians(_ degrees: Float) -> CGFloat {
return CGFloat(degrees * .pi / 180)
}
let rotate = SCNAction.rotate(by: degreesToRadians(90.0), around: SCNVector3(x: 1, y: 0 , z: 0), duration: 10)
sceneView.scene?.rootNode.addChildNode(conenode)
sceneView.scene?.rootNode.addChildNode(spherenode)
return sceneView
}
func updateUIView(_ uiView: SCNView, context: UIViewRepresentableContext<SceneKitView>) {
}
typealias UIViewType = SCNView
}
Please help me with this problem.
Upvotes: 0
Views: 280
Reputation: 1213
A few different ways to do this and I'm not clear on exactly how you want to rotate once you get past the sample of 90 degrees, which will make a difference.
Here is how to draw a line with vectors using a cylinder (search for post 35002232). Several choices, I like the answer: "class CylinderLine: SCNNode" and have used a version of it. That will let you work with vectors BUT you have to draw and remove each time it changes.
You could also try the lookat approach IF you have a target node. This works well if you want to move a target node (could be an invisible node) around and have your cylinder follow it:
baseNode.constraints = []
let vConstraint = SCNLookAtConstraint(target: targetNode)
vConstraint.isGimbalLockEnabled = true
baseNode.constraints = [vConstraint]
It works best with a base node, then add your cylinder node as a subnode so that it is fixed to your base node. Then your baseNode focuses on the target and your cylinder will automatically rotate with it.
You also have to start off by drawing it in the right spot. This is an example of a 3D tank with a fire tube inside. Setting the target of vNode rotates everything together. Just change SCNBox to Sphere - it works the same.
let BoxGeometry = SCNBox(width: 0.8, height: 0.8, length: 0.8, chamferRadius: 0.0)
let vNode = SCNNode(geometry: BoxGeometry)
BoxGeometry.materials = setDefenseTextures(vGameType: vGameType)
let tubeGeometry = SCNTube(innerRadius: 0.03, outerRadius: 0.05, height: 0.9)
let fireTube = SCNNode(geometry: tubeGeometry)
tubeGeometry.firstMaterial?.diffuse.contents = data.getTextureColor(vTheme: 0, vTextureType: .barrelColor)
fireTube.position = SCNVector3(0, 0.2, -0.3)
let vRotateX = SCNAction.rotateBy(x: CGFloat(Float(GLKMathDegreesToRadians(-90))), y: 0, z: 0, duration: 0)
fireTube.runAction(vRotateX)
vNode.addChildNode(fireTube)
Upvotes: 1