Skip to content

Instantly share code, notes, and snippets.

@dirkolbrich
Created October 27, 2019 14:52
Show Gist options
  • Select an option

  • Save dirkolbrich/9e4dffb3026d0540d6edf6877f27d1e4 to your computer and use it in GitHub Desktop.

Select an option

Save dirkolbrich/9e4dffb3026d0540d6edf6877f27d1e4 to your computer and use it in GitHub Desktop.

Revisions

  1. dirkolbrich created this gist Oct 27, 2019.
    180 changes: 180 additions & 0 deletions CameraControl2.playground
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,180 @@
    // A SceneKit based Playground to test camera position and movement
    // using a camera orbit
    import SceneKit
    import PlaygroundSupport

    // setup view
    var sceneView = SCNView(frame: CGRect(x:0 , y:0, width: 480, height: 640))
    var scene = SCNScene()
    sceneView.scene = scene

    sceneView.backgroundColor = UIColor.white
    sceneView.autoenablesDefaultLighting = true
    // sceneView.allowsCameraControl = true
    sceneView.showsStatistics = true

    // present
    PlaygroundPage.current.liveView = sceneView

    // add camera to the scene
    let camera = SCNCamera()
    camera.automaticallyAdjustsZRange = true

    let cameraNode = SCNNode()
    cameraNode.camera = camera
    cameraNode.name = "camera"
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 20)

    let cameraOrbit = SCNNode()
    scene.rootNode.addChildNode(cameraOrbit)

    cameraOrbit.addChildNode(cameraNode)

    // MARK: - Spheres

    func addSphere(x: Float, y: Float, z: Float, radius: Float, color: UIColor = UIColor.gray) {
    let material = SCNMaterial()
    material.diffuse.contents = color

    let sphereGeometry = SCNSphere(radius: CGFloat(radius))
    sphereGeometry.firstMaterial = material

    let sphereNode = SCNNode(geometry: sphereGeometry)
    sphereNode.name = "dot"

    sphereNode.position = SCNVector3(x: x, y: y, z: z)

    scene.rootNode.addChildNode(sphereNode)
    }

    let spacing: Float = 2.0
    let radius: Float = 1.0

    addSphere(
    x: 0.0,
    y: 0.0,
    z: 0.0,
    radius: radius)
    addSphere(
    x: -2.0 * spacing,
    y: -2.0 * spacing,
    z: 0.0,
    radius: radius)
    addSphere(
    x: 2.0 * spacing,
    y: 2.0 * spacing,
    z: 0.0,
    radius: radius)
    addSphere(
    x: -2.0 * spacing,
    y: 2.0 * spacing,
    z: 0.0,
    radius: radius)
    addSphere(
    x: 2.0 * spacing,
    y: -2.0 * spacing,
    z: 0.0,
    radius: radius)
    addSphere(
    x: 0.0,
    y: -2.0 * spacing,
    z: -2.0 * spacing,
    radius: radius)
    addSphere(
    x: 0.0,
    y: 2.0 * spacing,
    z: 2.0 * spacing,
    radius: radius)
    addSphere(
    x: 0.0,
    y: 2.0 * spacing,
    z: -2.0 * spacing,
    radius: radius)
    addSphere(
    x: 0.0,
    y: -2.0 * spacing,
    z: 2.0 * spacing,
    radius: radius)
    // sphere off center from square
    addSphere(
    x: 6.0,
    y: 6.0,
    z: 6.0,
    radius: radius)

    // MARK: - Coordinate Symbol

    let coordinates = SCNNode()
    scene.rootNode.addChildNode(coordinates)

    let coordVertices: [SCNVector3] = [
    SCNVector3(0, 0, 0),
    SCNVector3(5, 0, 0),
    SCNVector3(0, 0, 5),
    SCNVector3(-5, 0, 0),
    SCNVector3(0, 0, -5),
    SCNVector3(0, 5, 0)
    ]

    let coordColors: [String: UIColor] = [
    "red": UIColor.red,
    "blue": UIColor.blue,
    "green": UIColor.green,
    ]

    var materials: [String : SCNMaterial] {
    var mat = [String : SCNMaterial]()

    for (key, value) in coordColors {
    let material = SCNMaterial()
    material.lightingModel = SCNMaterial.LightingModel.constant
    material.isDoubleSided = true
    material.diffuse.contents = value

    mat[key] = material
    }

    return mat
    }

    func buildLine(vertice1: SCNVector3, Vertice2: SCNVector3, material: SCNMaterial) -> SCNNode {
    let geometry = SCNGeometry(
    sources: [SCNGeometrySource(vertices: [vertice1, Vertice2])],
    elements: [SCNGeometryElement(indices: [Int32]([0,1]), primitiveType: .line)]
    )
    geometry.firstMaterial = material

    return SCNNode(geometry: geometry)
    }

    coordinates.addChildNode(buildLine(vertice1: coordVertices[1], Vertice2: coordVertices[3], material: materials["red"]!))
    coordinates.addChildNode(buildLine(vertice1: coordVertices[2], Vertice2: coordVertices[4], material: materials["blue"]!))
    coordinates.addChildNode(buildLine(vertice1: coordVertices[0], Vertice2: coordVertices[5], material: materials["green"]!))

    // MARK: - Handle Gesture

    var lastWidthRatio: Float = 0
    var lastHeightRatio: Float = 0

    extension SCNView {
    @objc func handlePanGesture(_ sender: UIPanGestureRecognizer) {
    let translation = sender.translation(in: sender.view)
    let widthRatio = Float(translation.x) / Float(sender.view!.frame.size.width) + lastWidthRatio
    let heightRatio = Float(translation.y) / Float(sender.view!.frame.size.height) + lastHeightRatio

    cameraOrbit.eulerAngles.y = Float(-2 * Double.pi) * widthRatio
    cameraOrbit.eulerAngles.x = Float(-Double.pi) * heightRatio

    if (sender.state == .ended) {
    lastWidthRatio = widthRatio.truncatingRemainder(dividingBy: 1)
    lastHeightRatio = heightRatio.truncatingRemainder(dividingBy: 1)
    }
    }
    }

    // add a tap gesture recognizer
    let gesture = UIPanGestureRecognizer(
    target: sceneView,
    action: #selector(sceneView.handlePanGesture(_:)) as Selector
    )
    sceneView.addGestureRecognizer(gesture)