2017-10-24 14 views
0

저는 SceneKit을 사용하여 장면을 렌더링하는 간단한 데모 iOS 프로그램을 작성하는 새로운 프로그래머입니다.panGestureRecognizer를 사용하여 장면을 회전하십시오.

장면의 다른 원근감을보기 위해 카메라를 회전하고 싶습니다. 하지만 원래의 카메라 컨트롤은 조금 까다 롭습니다. 특히 장면을 한 방향으로 회전시키고 싶을 때. 예 : 오른쪽에서 왼쪽으로 스 와이프하면 카메라가 오른쪽에서 왼쪽으로 이동 한 다음 아래쪽으로 이동 한 다음 위쪽으로 이동 한 다음 아래쪽으로 다시 이동하여 결국 다시 왼쪽으로 이동합니다.

오른쪽에서 왼쪽으로 스 와이프하면 카메라가 z 축을 중심으로 회전합니다. 그리고 내 카메라를 위아래로 스 와이프하면 위아래로 움직입니다. 또한 확대/축소 할 수도 있습니다. 또한 카메라가 지하로 가지 않도록 구속 조건을 설정하고 싶습니다.

그래서 초점을 맞추기 위해 카메라를 수정하는 아이디어를 생각해냅니다. 그런 다음 물체를 장면 중앙에 놓습니다. 그리고 화면을 스 와이프 할 때 z 축 주위로 장면을 회전시키고 싶습니다.

panGestureRecognizer를 사용하여 위치 변경을 회전 순서로 변환한다고 가정합니다. 어떻게 구현할 수 있습니까?

또는이 결과를 얻으려는 다른 아이디어가 있습니까? 여기에 제가 지금까지 작성한 간단한 버전이 있습니다. 나는 UIPanGestureRecognizer를 사용하여 시도했지만 작동하지 않았다, 그래서 그것을 삭제하고 난 구면 좌표계를 사용하여이 문제를 해결 allowCameraControl = true

let sceneView = SCNView(frame: self.view.frame) 
    self.view.addSubview(sceneView) 

    let scene = SCNScene() 
    sceneView.scene = scene 

    let camera = SCNCamera() 
    let cameraNode = SCNNode() 
    cameraNode.camera = camera 
    cameraNode.position = SCNVector3(x: -5.0, y: 5.0, z: 5.0) 

    let light = SCNLight() 
    light.type = SCNLight.LightType.spot 
    light.spotInnerAngle = 30 
    light.spotOuterAngle = 80 
    light.castsShadow = true 
    let lightNode = SCNNode() 
    lightNode.light = light 
    lightNode.position = SCNVector3(x: 1.5, y: 1.5, z: 1.5) 

    let ambientLight = SCNLight() 
    ambientLight.type = SCNLight.LightType.ambient 
    ambientLight.color = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0) 
    cameraNode.light = ambientLight 

    let cubeGeometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0.0) 
    let cubeNode = SCNNode(geometry: cubeGeometry) 

    let planeGeometry = SCNPlane(width: 50.0, height: 50.0) 
    let planeNode = SCNNode(geometry: planeGeometry) 
    planeNode.eulerAngles = SCNVector3(x: GLKMathDegreesToRadians(-90), y: 0, z: 0) 
    planeNode.position = SCNVector3(x: 0, y: -0.5, z: 0) 

    cameraNode.position = SCNVector3(x: -3.0, y: 3.0, z: 3.0) 
    let constraint = SCNLookAtConstraint(target: cubeNode) 
    constraint.isGimbalLockEnabled = true 
    cameraNode.constraints = [constraint] 
    lightNode.constraints = [constraint] 

    scene.rootNode.addChildNode(lightNode) 
    scene.rootNode.addChildNode(cameraNode) 
    scene.rootNode.addChildNode(cubeNode) 
    scene.rootNode.addChildNode(planeNode) 

    sceneView.allowsCameraControl = true 
+0

https://www.raywenderlich.com/162745/uigesturerecognizer-tutorial-getting-started –

답변

0

설정합니다.

일반적인 생각은 시작 위치와 각도를 구한 다음 구형 좌표계로 변환하는 것입니다. 그런 다음 두 각도를 변경하여 회전을 수행합니다.

핀치 제스처를 처리 할 때 구형 좌표계를 사용하는 것이 더 쉽습니다. 반경을 변경하기 만하면됩니다.

여기 제가 사용하는 코드가 있습니다.

func handlePan(_ gestureRecognize: UIPanGestureRecognizer) { 
    // retrieve scene 
    let carView = self.view as! SCNView 

    // save node data and pan gesture data 
    let cameraNode = carView.scene?.rootNode.childNode(withName: "Camera", recursively: true)! 
    //let translation = gestureRecognize.translation(in: gestureRecognize.view!) 

    let speed = gestureRecognize.velocity(in: gestureRecognize.view!) 
    var speedX = sign(Float(speed.x)) * Float(sqrt(abs(speed.x))) 
    var speedY = sign(Float(speed.y)) * Float(sqrt(abs(speed.y))) 
    if speedX.isNaN {speedX = 0} 
    if speedY.isNaN {speedY = 0} 

    // record start value 
    let cameraXStart = cameraNode!.position.x 
    let cameraYStart = cameraNode!.position.y 
    let cameraZStart = cameraNode!.position.z - 1.0 

    let cameraAngleStartZ = cameraNode!.eulerAngles.z 
    let cameraAngleStartX = cameraNode!.eulerAngles.x 
    let radiusSquare = cameraXStart * cameraXStart + cameraYStart * cameraYStart + cameraZStart * cameraZStart 

    // calculate delta value 
    let deltaAngleZ = -0.003 * Float(speedX) 
    let deltaAngleX = -0.003 * Float(speedY) 

    // get new Value 
    var cameraNewAngleZ = cameraAngleStartZ + deltaAngleZ 
    var cameraNewAngleX = cameraAngleStartX + deltaAngleX 

    if cameraNewAngleZ >= 100 * Float.pi { 
     cameraNewAngleZ = cameraNewAngleZ - 100 * Float.pi 
    } else if cameraNewAngleZ < -100 * Float.pi { 
     cameraNewAngleZ = cameraNewAngleZ + 100 * Float.pi 
    } else { 
     // set limit 
     if cameraNewAngleX > 1.4 { 
      cameraNewAngleX = 1.4 
     } else if cameraNewAngleX < 0.1 { 
      cameraNewAngleX = 0.1 
     } 
     // use angle value to get position value 
     let cameraNewX = sqrt(radiusSquare) * cos(cameraNewAngleZ - Float.pi/2) * cos(cameraNewAngleX - Float.pi/2) 
     let cameraNewY = sqrt(radiusSquare) * sin(cameraNewAngleZ - Float.pi/2) * cos(cameraNewAngleX - Float.pi/2) 
     let cameraNewZ = -sqrt(radiusSquare) * sin(cameraNewAngleX - Float.pi/2) + 1 

     if cameraNode?.camera?.usesOrthographicProjection == false { 
      cameraNode?.position = SCNVector3Make(cameraNewX, cameraNewY, cameraNewZ) 
      cameraNode?.eulerAngles = SCNVector3Make(cameraNewAngleX, 0, cameraNewAngleZ) 
     } 
     else if cameraNode?.camera?.usesOrthographicProjection == true { 
      cameraNode?.position = SCNVector3Make(0, 0, 10) 
      cameraNode?.eulerAngles = SCNVector3Make(0, 0, cameraNewAngleZ) 
     } 
    } 
}