2014-12-07 11 views
8

Ich habe ein wenig mehr mathematisches Problem mit 3D-Programmierung und ich hoffe, Sie können mir helfen!Scenekit Pan 2D Übersetzung zu Orthographic 3D nur horizontal

Ich versuche ein 3D-Spiel mit Scenekit mit einem isometrischen Winkel zu erstellen.

Dieser Code erstellt meine orthogonale Kamera:

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) 

Jetzt habe ich die Kamera mit einer Pfanne Geste bewegen will, ein Scroll-Gefühl zu erzeugen. Um dies zu ermöglichen, sollte sich die Kamera nicht vertikal, sondern nur horizontal bewegen. Der Touch-Standort auf dem Bildschirm und die nicht projizierte Position in der 3D-Welt sollten während der Bewegung gleich bleiben.

Ich dachte über die Berechnung der 2D-Übersetzung in 3D-Differenz und die vertikale Komponente zu ignorieren. Dieser Code funktioniert tatsächlich und erzeugt fast das gewünschte Ergebnis, aber die Geschwindigkeit ist nicht korrekt. Wenn ich schwenken, scheint die Kamera zu beschleunigen und nicht richtig reagieren:

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 
} 

Kennt jemand eine anspruchsvolle Art und Weise einen Bildschirm Übersetzung in eine horizontale 3D-Übersetzung der Berechnung, um die vertikale Achse zu ignorieren?

Vielen Dank im Voraus :)

EDIT: Die Pfanne jetzt horizontal Übersetzung funktioniert. Aber nicht für vertikal, weil ich die Differenz auf der z-Achse auf Null setze.

+0

verwenden Sie nie "diffTrans". Möchten Sie "diffTrans" nicht verwenden, wenn Sie den Schutz aufheben (statt "Übersetzung")? Andernfalls würden Sie die Übersetzungen bei jeder Iteration akkumulieren. – Toyos

+0

Vielen Dank für das Aufzeigen! Ich habe so viele verschiedene Ansätze ausprobiert, dass ich diesen Fehler nicht gesehen habe.Es löst das Problem mit dem horizontalen Schwenken, aber nicht mit vertikal, wegen der unerwünschten vertikalen Komponente der Welt-Übersetzung –

+0

Überprüfen Sie die Antwort Rickster-Antwort hier: http://StackOverflow.com/Questions/25150737/How-To-use- ios-swift-scenekit-scnscenrenderer-unprojectpoint-richtig Er hat am Ende eine Notiz über die Handhabung der Unprojektion, wenn die Kameraebene nicht gleich "Welt" ist. Es könnte ein nützlicher Ausgangspunkt sein. –

Antwort

9

Ich habe meine eigene Lösung gefunden.!

Ich berechne einen Strahl am Startort der Geste (P1-P2) und einen Strahl am übersetzten Ort (Q1-Q2). Jetzt habe ich zwei Strahlen und lasse beide die XY-Ebene schneiden, um die Punkte P0 und Q0 zu empfangen. Die Differenz von P0 und Q0 ist die nicht projizierte Übersetzung.

Diese Technik sollte auch mit einer nicht orthogonalen Kamera funktionieren, aber ich habe dies noch nicht getestet.

Es scheint mir, dass es funktioniert, aber wenn jemand mathematisch diese Annahme bestätigen könnte, würde ich froh sein, dass zu lesen :)

Hier ist der Code:

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; 
    } 
} 

Red is screen translation, Blue is world translation

1

Ich habe die Gleichungen für das isometrische Panning berechnet, der Code ist unten.

//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; 
    } 
} 

Und richtig zu skalieren, müssen Sie screen als Variable für orthographicScale verwenden. Die Skalierung, die ich hier verwendet habe, ist 30-fache Vergrößerung, beachten Sie, dass die 30 auch für die Konstante im obigen Code verwendet wird.

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) 
Verwandte Themen