2017-08-29 3 views
0

Ich verwende ARKit mit SceneKit. Wenn der Benutzer einen Knopf drückt, erstelle ich einen Anker und an den SCNNode, der ihm entspricht, füge ich ein 3D-Objekt hinzu (geladen aus einer .scn-Datei im Projekt).SceneKit - Objekt um die X- und Z-Achse drehen

Das 3D-Objekt wird mit der gleichen Ausrichtung wie die Kamera zur Kamera ausgerichtet. Ich möchte es so aussehen lassen, als ob das Objekt auf einer ebenen Fläche liegt und nicht geneigt ist, wenn es so ist. Also, wenn ich es richtig verstanden habe, müsste ich eine Rotationstransformation anwenden, so dass die Drehung um die X- und Z-Achse 0 wird.

Mein Versuch ist: nimm die Knoten x und z eulerAngles, invertiere sie drehen, und diesen Betrag um jede Achse

let rotationZ = rotationMatrixAroundZ(radians: -node.eulerAngles.z) 
let rotationX = rotationMatrixAroundX(radians: -node.eulerAngles.x) 

let rotationTransform = simd_mul(rotationTransformX, rotationTransformZ) 
node.transform = SCNMatrix4(simd_mul(simd_float4x4(node.transform), rotationTransform)) 

Dies alles in Ordnung für die meisten Fälle funktioniert, aber in einigen das Objekt in ganz seltsame Weise gedreht. Sollte ich den Drehwinkel auf etwas anderes als nur die Umkehrung des aktuellen Euler-Winkels einstellen? Das direkte Einstellen der Winkel auf 0 hat überhaupt nicht funktioniert.

+0

Verwenden Sie Einschränkungen? –

+0

Nein, ich habe versucht, mit dem SCNLookAtConstraint und der Look (at :) -Methode zu experimentieren, aber keine von ihnen war zufriedenstellend meine Bedürfnisse – leandrodemarco

Antwort

2

Ich habe stolperte darüber und fand heraus, dass ich in gimbal lock rannte. Die Lösung bestand darin, den Knoten um eine Achse zu drehen, ihn zu einem anderen SCNNode() zu rotieren und dann den Elternknoten um die andere Achse zu drehen. Ich hoffe, das hilft.

+0

Danke! Ich dachte mir, ich würde zur Kardansperre rennen, aber ich hatte nicht daran gedacht, es zu lösen! – leandrodemarco

0

Nun, ich schaffte einen Workaround, aber ich bin nicht wirklich glücklich damit, also werde ich die Frage unbeantwortet lassen. Grundsätzlich definiere ich eine Schwelle von 2 Grad und führe diese Rotationen solange aus, bis beide Euler-Winkel um X und Z unterhalb der oben genannten Schwelle liegen.

func layDownNode(_ node: SCNNode) { 
    let maxErrDegrees: Float = 2.0 
    let maxErrRadians = GLKMathDegreesToRadians(maxErrDegrees) 

    while (abs(node.eulerAngles.x) > maxErrRadians || abs(node.eulerAngles.z) > maxErrRadians) { 
     let rotationZ = -node.eulerAngles.z 
     let rotationX = -node.eulerAngles.x 

     let rotationTransformZ = rotationMatrixAroundZ(radians: rotationZ) 
     let rotationTransformX = rotationMatrixAroundX(radians: rotationX) 

     let rotationTransform = simd_mul(rotationTransformX, rotationTransformZ) 

     node.transform = SCNMatrix4(simd_mul(simd_float4x4(node.transform), rotationTransform)) 
    } 
} 
0

Sie auf den Knoten nicht auf einer Matrix-Transformation haben, können Sie einfach drehen sich um eine bestimmte Achse und das könnte etwas einfacher in Bezug auf die Logik zu tun, um die Drehung sein.

Man könnte so etwas wie tun:

node.runAction(SCNAction.rotateBy(x: x, y: y, z: z, duration: 0.0)) 

Nicht sicher, ob dies die Art der Sache ist, die Sie suchen, aber es ist einfacher, als die Rotation mit dem SCNMatrix4 tun

+0

Danke für den Vorschlag, hatte diese Option nicht untersucht. Ich werde es versuchen! – leandrodemarco

Verwandte Themen