6

The code below is meant to simulate the default camera controls in SceneKit, specifically the zoom and rotate functionality.

However, the code isn't nearly as smooth and versatile as the default controls.

For instance, if you load these two models, the default zoom works consistently for both models. The code below only works well, however, for model 1 but zooms far too fast for model 2.

Any help would be appreciated.

Model 1: https://poly.google.com/view/6mRHqTCZHxw

Model 2: https://poly.google.com/view/cKryD9VnDEZ

    // Create camera
    let camera = SCNCamera()
    camera.automaticallyAdjustsZRange = true
    camera.xFov = 30 
    camera.yFov = 0

    // Compute distance to place camera
    let theta = GLKMathDegreesToRadians(Float(camera.xFov/2))
    let adjacentLength = oppositeLength / Float(tan(theta))

    // Add camera to <cameraNode>
    cameraNode.camera = camera
    cameraNode.position = SCNVector3(x: 0, y: 0, z: adjacentLength)

    // Add <cameraNode> to <orbitNode>
    orbitNode.addChildNode(cameraNode)

    // Add <orbitNode>
    scene.rootNode.addChildNode(orbitNode)

    // Handle pinches
    let pinchRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(didSceneViewPinch))
    pinchRecognizer.delegate = self
    sceneView.addGestureRecognizer(pinchRecognizer)

    // Handle pans
    let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didSceneViewPanOneFinger))
    panRecognizer.minimumNumberOfTouches = 1
    panRecognizer.maximumNumberOfTouches = 1
    panRecognizer.delegate = self
    sceneView.addGestureRecognizer(panRecognizer)

func rotate(recognizer: UIPanGestureRecognizer) {
    // Set throttle value to slow down rotation
    let throttleFactor = Float(40)

    // Compute rotation
    let translation = recognizer.translation(in: recognizer.view!)
    let xRadians = GLKMathDegreesToRadians(Float(translation.x)) / throttleFactor
    let yRadians = GLKMathDegreesToRadians(Float(translation.y)) / throttleFactor

    // Orbit camera via <orbitNode>
    orbitNode.eulerAngles.x -= yRadians
    orbitNode.eulerAngles.y -= xRadians
}


func zoom(recognizer: UIPinchGestureRecognizer) {
    // Set zoom properties
    let minVelocity = CGFloat(0.10)
    let zoomDelta = 0.5

    // Only zoom when gesture changing and when velocity exceeds <minVelocity>
    if recognizer.state == .changed {
        // Ignore gesture on tiny movements
        if abs(recognizer.velocity) <= minVelocity {
            return
        }

        // If here, zoom in or out based on velocity
        let deltaFov = recognizer.velocity > 0 ? -zoomDelta : zoomDelta
        var newFov = cameraNode.camera!.xFov + deltaFov

        // Make sure FOV remains within min and max values
        if newFov <= minXFov {
            newFov = minXFov
        } else if newFov >= maxXFov {
            newFov = maxXFov
        }

        // Update FOV?
        if cameraNode.camera?.xFov != newFov {
            cameraNode.camera?.xFov = newFov
        }
    }
}
Crashalot
  • 33,605
  • 61
  • 269
  • 439
  • Sorry to bother you, @mnuages. Can you help with this? Or know someone that can? – Confused Mar 16 '18 at 15:59
  • this line: var newFov = cameraNode.camera!.xFov + deltaFov should probably be modified in something non-linear. you want small for to update slower than large fov. maybe try a factor instead - something like var newFov = cameraNode.camera!.xFov * (1 + deltaFov) with a smaller zoomDelta – Toyos Mar 17 '18 at 18:54
  • 1
    @Toyos yup, we realized that after some more testing, thanks for the suggestion! :) any suggestions for making rotation smoother? do you guys just use animation in the end state of the pan gesture? please ask tim cook to hire more people for your team! :) – Crashalot Mar 17 '18 at 23:18
  • They let Chris Lattner exist as a mere Apple employee, without the kinds of stock options and prestige worthy of a great programmer, and without the kind of empowerment and course determination enticing enough to keep him intrigued and passionate about Apple and its directions. Tim Cook oversaw that. The entire tech community fails to acknowledge special talent, or the need for empowerment of special talent to be special. @Toyos and the team at SCNKit are yet another example of special talent being disempowered, underfunded and subjected to the nonsensical whims of a clueless management. BWWIK – Confused Mar 19 '18 at 09:00
  • @Confused if you want the code for this just ask. still unclear why apple doesn't open-source the code. every hour spent implementing what apple did was an hour not spent creating a differentiated and improved user experience. waste of time. – Crashalot Mar 22 '18 at 00:26
  • Sorry, I think this is going to be a maths problem. And that's something I suck at. Probably a combination of matrix math and rotation maths to get this to work right... plus you'd need to have a split screen with a default camera to figure out what it's doing. I agree with you. Given the current state of the game engine space, something that's come about over decades, there are only two options. Premium engines with massive resources (of which Unity now has), or truly OPEN source, with a PAID backbone of THE best and brightest upon which the rest of the community can build = Unreal Engine – Confused Mar 22 '18 at 03:04
  • Apple can do this, with Scene Kit, they could throw a few bones to the boys that made SceneKit, and spend a year or two making it amazing, massively improving it, teaching it and empowering users, then open source it. They managed to do this with Swift... – Confused Mar 22 '18 at 03:05

1 Answers1

2

I tried recreating SCNCamera rotation as such in default camera controller. But it was not as smooth as the default camera. So I added pan gesture with two minimum touches and left the function empty doing nothing. This makes use of default camera rotation property alone and avoiding below two properties of the default camera as mentioned in https://developer.apple.com/documentation/scenekit/scnview/1523171-allowscameracontrol

1.Pan with two fingers to translate the camera on its local xy-plane 2.Pan with three fingers vertically to move the the camera forward backward

//Pan Gesture
let gesture = UIPanGestureRecognizer(target: self, action: #selector(panDetected(sender:)))
gesture.maximumNumberOfTouches = 3
gesture.minimumNumberOfTouches = 2
self.sceneView.addGestureRecognizer(gesture);

//Doing nothing in pan gesture other than  printing
@objc func panDetected (sender: UIPanGestureRecognizer) {
    print("two pan detected")
}

Next add pinch gesture to the scene view so that minimum and maximum zoom level can be controlled


//pinch gesture
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinched(sender:)))
    

self.sceneView.addGestureRecognizer(pinchGesture);
@objc func pinched(sender:UIPinchGestureRecognizer){
    let pinchVelocity = Double.init(sender.velocity)
    //print("PinchVelocity \(pinchVelocity)")

    self.sceneView.pointOfView?.camera!.orthographicScale -= (pinchVelocity/pinchAttenuation)

    if (self.sceneView.pointOfView?.camera!.orthographicScale)! <= 0.5 {
        self.sceneView.pointOfView!.camera!.orthographicScale = 0.5
    }

    if self.sceneView.pointOfView!.camera!.orthographicScale >= 1 {
        self.sceneView.pointOfView?.camera!.orthographicScale = 1
    }
}

Add UIRotationGestureRecognizer incase you want to disable or modify default camera rotation(Rotate with two fingers to roll the camera (rotate on the camera node's z-axis)

tospig
  • 7,762
  • 14
  • 40
  • 79