Scenekit move object with respect to camera
Here is the solution
guard let front = sceneView.pointOfView?.simdWorldFront else {return}
let horazontalRight = cross(front, simd_float3(0,1,0))
// for moving right
node.position += SCNVector3(horazontalRight * 0.01)
Can I get the SCNView camera position when using allowsCameraControl?
When you enable allowsCameraControl
, SceneKit inserts its own camera node into the scene (as an immediate child of the scene's root node), and sets that node as the view's pointOfView
. Read the properties of that node to find out the camera's position and orientation, or the properties of the node's camera
attribute to find the camera's field of view, depth limits, etc.
SCNNodes disappear after zooming out in Scene Kit?
Configure the zFar
property of the camera to avoid clipping when the camera is further away. (The default value is 100)
For example:cameraNode.camera?.zFar = 500
You can play with this property to get everything visible while trying to keep good performance.
SceneKit camera, how to compensate for euler rules (orientation) changes
if t
is the translation you compute from the WSAD keys, then you should not simply add it (node.position += t
) but first apply a rotation and then add it : node.position += node.rotation * t
Rotate SCNCamera node looking at an object around an imaginary sphere
It might help to break down your issue into subproblems.
Setting the Scene
First, think about how to organize your scene to enable the kind of motion you want. You talk about moving the camera as if it's attached to an invisible sphere. Use that idea! Instead of trying to work out the math to set your cameraNode.position
to some point on an imaginary sphere, just think about what you would do to move the camera if it were attached to a sphere. That is, just rotate the sphere.
If you wanted to rotate a sphere separately from the rest of your scene contents, you'd attach it to a separate node. Of course, you don't actually need to insert a sphere geometry into your scene. Just make a node whose position
is concentric with the object you want your camera to orbit around, then attach the camera to a child node of that node. Then you can rotate that node to move the camera. Here's a quick demo of that, absent the scroll-event handling business:
let camera = SCNCamera()
camera.usesOrthographicProjection = true
camera.orthographicScale = 9
camera.zNear = 0
camera.zFar = 100
let cameraNode = SCNNode()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 50)
cameraNode.camera = camera
let cameraOrbit = SCNNode()
cameraOrbit.addChildNode(cameraNode)
cubeScene.rootNode.addChildNode(cameraOrbit)
// rotate it (I've left out some animation code here to show just the rotation)
cameraOrbit.eulerAngles.x -= CGFloat(M_PI_4)
cameraOrbit.eulerAngles.y -= CGFloat(M_PI_4*3)
Here's what you see on the left, and a visualization of how it works on the right. The checkered sphere is cameraOrbit
, and the green cone is cameraNode
.
There's a couple of bonuses to this approach:
- You don't have to set the initial camera position in Cartesian coordinates. Just place it at whatever distance you want along the z-axis. Since
cameraNode
is a child node ofcameraOrbit
, its own position stays constant -- the camera moves due to the rotation ofcameraOrbit
. - As long as you just want the camera pointed at the center of this imaginary sphere, you don't need a look-at constraint. The camera points in the -Z direction of the space it's in -- if you move it in the +Z direction, then rotate the parent node, the camera will always point at the center of the parent node (i.e. the center of rotation).
Handling Input
Now that you've got your scene architected for camera rotation, turning input events into rotation is pretty easy. Just how easy depends on what kind of control you're after:
- Looking for arcball rotation? (It's great for direct manipulation, since you can feel like you're physically pushing a point on the 3D object.) There are some questions and answers about that already on SO -- most of them use
GLKQuaternion
. (UPDATE: GLK types are "sorta" available in Swift 1.2 / Xcode 6.3. Prior to those versions you can do your math in ObjC via a bridging header.) - For a simpler alternative, you can just map the x and y axes of your gesture to the yaw and pitch angles of your node. It's not as spiffy as arcball rotation, but it's pretty easy to implement -- all you need to do is work out a points-to-radians conversion that covers the amount of rotation you're after.
Either way, you can skip some of the gesture recognizer boilerplate and gain some handy interactive behaviors by using UIScrollView
instead. (Not that there isn't usefulness to sticking with gesture recognizers -- this is just an easily implemented alternative.)
Drop one on top of your SCNView
(without putting another view inside it to be scrolled) and set its contentSize
to a multiple of its frame size... then during scrolling you can map the contentOffset
to your eulerAngles
:
func scrollViewDidScroll(scrollView: UIScrollView) {
let scrollWidthRatio = Float(scrollView.contentOffset.x / scrollView.frame.size.width)
let scrollHeightRatio = Float(scrollView.contentOffset.y / scrollView.frame.size.height)
cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * scrollWidthRatio
cameraOrbit.eulerAngles.x = Float(-M_PI) * scrollHeightRatio
}
On the one hand, you have to do a bit more work for infinite scrolling if you want to spin endlessly in one or both directions. On the other, you get nice scroll-style inertia and bounce behaviors.
Related Topics
Empty Class in Swift Playground Gives _Lldb_Expr_ Error
How Assistant Model Works in Swift
Resizing Large Resolution Images Producing 1000X1000 Pixels Size When Size Is Set to 500X500 Pixels
Error "{ Expected After If Statement"
Can't Change Uiimageview Image in Function (Swift)
Binary Operator '==' Cannot Be Applied to Operands of Type 'Uilabel' and 'String'
Swift Uitableviewautomaticdimension Is Not Working
Value' Is Inaccessible Due to 'Internal' Protection Level
How to Comprehend the "First-Class Function" in Swift
Uibutton Causing Unrecognized Selector Sent to Instance
Generate Labels and Align in Middle
Swift - Creating Shadow with 2 Different Colours for Imageview
Why Reloaddata Is Showing Error for My Tableview Inside Viewcontroller
How to Execute Different Implementation of a Method of a Generic Struct Based on the Generic Type
How to Know When to Call a Closure with () or Without Parentheses in Handler: