Scenekit Pan 2D Traducción a 3D ortográfico solo horizontal

Estoy teniendo un poco más de problema matemático con la progtwigción 3D y ¡espero que me puedas ayudar!

Estoy tratando de crear un juego 3D utilizando Scenekit con un ángulo isométrico.

Este código crea mi camera ortográfica:

var cameraNode = SCNNode() cameraNode.camera = SCNCamera() cameraNode.name = "Camera" cameraNode.position = SCNVector3Make(-5.0, -5.0, 10.0) cameraNode.eulerAngles = SCNVector3Make(PI / 3.0, 0.0, -PI / 4.0) cameraNode.camera?.usesOrthographicProjection = true cameraNode.camera?.orthographicScale = 7.0 scene.rootNode.addChildNode(cameraNode) 

Ahora quiero mover la camera con un gesto de paneo, produciendo una sensación de desplazamiento. Para hacer esto posible, la camera no debe moverse verticalmente, solo horizontalmente. La location táctil en la pantalla y la position no proyectada en el mundo 3D deberían permanecer igual mientras se mueven.

Pensé en calcular la traducción 2D en la diferencia 3D e ignorar el componente vertical. Este código realmente funciona y casi produce el resultado deseado, pero la velocidad no es correcta. Si saco, la camera parece acelerar y no reactjsr correctamente:

 var previousTranslation = CGPointMake(0.0, 0.0) func pan(gesture: UIPanGestureRecognizer) { let view = self.view as SCNView let translation = gesture.translationInView(view) let location = gesture.locationInView(view) let diffTrans = translation - previousTranslation previousTranslation = translation let cameraNode = scene.rootNode.childNodeWithName("Camera", recursively: false) let worldPointTrans = view.unprojectPoint(SCNVector3Make(-Float(diffTrans.x), -Float(diffTrans.y), 0.0)) let worldPoint0 = view.unprojectPoint(SCNVector3Make(0.0, 0.0, 0.0)) var diff = worldPointTrans - worldPoint0 diff.x = diff.x / Float(cameraNode!.camera!.orthographicScale) diff.y = diff.y / Float(cameraNode!.camera!.orthographicScale) diff.z = 0 cameraNode?.position += diff } 

¿Alguien sabe una forma sofisticada de calcular una traducción de pantalla en una traducción 3D horizontal, ignorando el eje vertical?

Gracias de antemano 🙂

EDITAR: La bandeja funciona para la traducción horizontal ahora. Pero no para vertical, porque puse la diferencia en el eje z en cero.

¡Encontré mi propia solución!

Estoy calculando un rayo en la location inicial del gesto (P1-P2) y un rayo en la location traducida (Q1-Q2). Ahora tengo dos rayos y dejo que ambos se crucen con el plano XY para recibir los puntos P0 y Q0

La diferencia de P0 y Q0 es la traducción no proyectada.

Esta técnica también debería funcionar con una camera no ortogonal, pero no probé esto todavía.

Me parece que funciona, pero si alguien pudiera confirmar matemáticamente esta suposition, me gustaría leer eso 🙂

Aquí está el código:

  var previousLocation = SCNVector3(x: 0, y: 0, z: 0) func pan(gesture: UIPanGestureRecognizer) { let view = self.view as SCNView let translation = gesture.translationInView(view) let location = gesture.locationInView(view) let secLocation = location + translation let P1 = view.unprojectPoint(SCNVector3(x: Float(location.x), y: Float(location.y), z: 0.0)) let P2 = view.unprojectPoint(SCNVector3(x: Float(location.x), y: Float(location.y), z: 1.0)) let Q1 = view.unprojectPoint(SCNVector3(x: Float(secLocation.x), y: Float(secLocation.y), z: 0.0)) let Q2 = view.unprojectPoint(SCNVector3(x: Float(secLocation.x), y: Float(secLocation.y), z: 1.0)) let t1 = -P1.z / (P2.z - P1.z) let t2 = -Q1.z / (Q2.z - Q1.z) let x1 = P1.x + t1 * (P2.x - P1.x) let y1 = P1.y + t1 * (P2.y - P1.y) let P0 = SCNVector3Make(x1, y1,0) let x2 = Q1.x + t1 * (Q2.x - Q1.x) let y2 = Q1.y + t1 * (Q2.y - Q1.y) let Q0 = SCNVector3Make(x2, y2, 0) var diffR = Q0 - P0 diffR *= -1 let cameraNode = view.scene!.rootNode.childNodeWithName("Camera", recursively: false) switch gesture.state { case .Began: previousLocation = cameraNode!.position break; case .Changed: cameraNode?.position = previousLocation + diffR break; default: break; } } 

El rojo es la traducción de la pantalla, el azul es la traducción mundial

He calculado las ecuaciones para el paneo isométrico, el código está debajo.

 //camera pan ISOMETRIC logic func pan(gesture: UIPanGestureRecognizer) { let view = self.sceneView as SCNView let cameraNode = view.scene!.rootNode.childNode(withName: "Camera", recursively: false) let translation = gesture.translation(in: view) let constant: Float = 30.0 var translateX = Float(translation.y)*sin(.pi/4.0)/cos(.pi/3.0)-Float(translation.x)*cos(.pi/4.0) var translateY = Float(translation.y)*cos(.pi/4.0)/cos(.pi/3.0)+Float(translation.x)*sin(.pi/4.0) translateX = translateX / constant translateY = translateY / constant switch gesture.state { case .began: previousLocation = cameraNode!.position break; case .changed: cameraNode?.position = SCNVector3Make((previousLocation.x + translateX), (previousLocation.y + translateY), (previousLocation.z)) break; default: break; } } 

Y para get una escala adecuada, debe usar screenheight como una variable para escala ortográfica. La escala que usé aquí es de 30 aumentos, tenga en count que 30 también se usa para la constante en el código anterior.

  let screenSize: CGRect = UIScreen.main.bounds let screenHeight = screenSize.height let cameraNode = SCNNode() cameraNode.camera = SCNCamera() cameraNode.name = "Camera" let cameraDist = Float(20.0) let cameraPosX = cameraDist*(-1.0)*cos(.pi/4.0)*cos(.pi/6.0) let cameraPosY = cameraDist*(-1.0)*sin(.pi/4.0)*cos(.pi/6.0) let cameraPosZ = cameraDist*sin(.pi/6) cameraNode.position = SCNVector3Make(cameraPosX, cameraPosY, cameraPosZ) cameraNode.eulerAngles = SCNVector3Make(.pi / 3.0, 0.0, -.pi / 4.0) cameraNode.camera?.usesOrthographicProjection = true cameraNode.camera?.orthographicScale = Double(screenHeight)/(2.0*30.0) //30x magnification constant. larger number = larger object scene.rootNode.addChildNode(cameraNode)