ios - Rotate SCNCamera node looking at an object around an imaginary sphere -
i've got scncamera @ position(30,30,30) scnlookatconstraint on object located @ position(0,0,0). i'm trying camera rotate around object on imaginary sphere using uipangesturerecognizer, while maintaining radius between camera , object. i'm assuming should use quaternion projections math knowledge in area abysmal. known variables x & y translation + radius trying keep. i've written project in swift answer in objective-c equally accepted (hopefully using standard cocoa touch framework).
where:
private var cubeview : scnview!; private var cubescene : scnscene!; private var cameranode : scnnode!;
here's code setting scene:
// setup scnview cubeview = scnview(frame: cgrectmake(0, 0, self.width(), 175)); cubeview.autoenablesdefaultlighting = yes; self.addsubview(cubeview); // setup scene cubescene = scnscene(); cubeview.scene = cubescene; // setup camera let camera = scncamera(); camera.usesorthographicprojection = yes; camera.orthographicscale = 9; camera.znear = 0; camera.zfar = 100; cameranode = scnnode(); cameranode.camera = camera; cameranode.position = scnvector3make(30, 30, 30) cubescene.rootnode.addchildnode(cameranode) // setup target object let box = scnbox(width: 10, height: 10, length: 10, chamferradius: 0); let boxnode = scnnode(geometry: box) cubescene.rootnode.addchildnode(boxnode) // put constraint on camera let targetnode = scnlookatconstraint(target: boxnode); targetnode.gimballockenabled = yes; cameranode.constraints = [targetnode]; // add gesture recogniser let gesture = uipangesturerecognizer(target: self, action: "pandetected:"); cubeview.addgesturerecognizer(gesture);
and here code gesture recogniser handling:
private var position:cgpoint!; internal func pandetected(gesture:uipangesturerecognizer) { switch(gesture.state) { case uigesturerecognizerstate.began: position = cgpointzero; case uigesturerecognizerstate.changed: let aposition = gesture.translationinview(cubeview); let delta = cgpointmake(aposition.x-position.x, aposition.y-position.y); // ??? no idea... position = aposition; default: break } }
thanks!
it might break down issue subproblems.
setting scene
first, think how organize scene enable kind of motion want. talk moving camera if it's attached invisible sphere. use idea! instead of trying work out math set cameranode.position
point on imaginary sphere, think move camera if attached sphere. is, rotate sphere.
if wanted rotate sphere separately rest of scene contents, you'd attach separate node. of course, don't need insert sphere geometry scene. make node position
concentric object want camera orbit around, attach camera child node of node. can rotate node move camera. here's quick demo of that, absent 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 (i've left out animation code here show rotation) cameraorbit.eulerangles.x -= cgfloat(m_pi_4) cameraorbit.eulerangles.y -= cgfloat(m_pi_4*3)
here's see on left, , visualization of how works on right. checkered sphere cameraorbit
, , green cone cameranode
.
there's couple of bonuses approach:
- you don't have set initial camera position in cartesian coordinates. place @ whatever distance want along z-axis. since
cameranode
child node ofcameraorbit
, own position stays constant -- camera moves due rotation ofcameraorbit
. - as long want camera pointed @ center of imaginary sphere, don't need look-at constraint. camera points in -z direction of space it's in -- if move in +z direction, rotate parent node, camera point @ center of parent node (i.e. center of rotation).
handling input
now you've got scene architected camera rotation, turning input events rotation pretty easy. how easy depends on kind of control you're after:
- looking arcball rotation? (it's great direct manipulation, since can feel you're physically pushing point on 3d object.) there questions , answers on -- of them use
glkquaternion
. (update: glk types "sorta" available in swift 1.2 / xcode 6.3. prior versions can math in objc via bridging header.) - for simpler alternative, can map x , y axes of gesture yaw , pitch angles of node. it's not spiffy arcball rotation, it's pretty easy implement -- need work out points-to-radians conversion covers amount of rotation you're after.
either way, can skip of gesture recognizer boilerplate , gain handy interactive behaviors using uiscrollview
instead. (not there isn't usefulness sticking gesture recognizers -- implemented alternative.)
drop 1 on top of scnview
(without putting view inside scrolled) , set contentsize
multiple of frame size... during scrolling can map contentoffset
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 1 hand, have bit more work infinite scrolling if want spin endlessly in 1 or both directions. on other, nice scroll-style inertia , bounce behaviors.
Comments
Post a Comment