2017-03-06 3 views
4

Ich war mit GameplayKit der GKAgent3D Klasse experimentieren eine SCNNode innerhalb einer Szene zu bewegen. Ich konnte den SCNNode mit der Position des Agenten aktualisieren, aber nicht mit der Rotation. Das Problem der Rotation des Agenten wird als matrix_float3x3 gespeichert, das keinem der Datentypen entspricht, die SceneKit zum Speichern von Rotationsinformationen verwendet.Converting matrix_float3x3 Rotation SceneKit

Also, was ich möchte, ist wissen, ob es eine einfache Funktion oder Methode, die eine Rotation gespeichert, wie matrix_float3x3 auf alle SceneKit Datentypen umwandeln können?

Antwort

4

Um @rickster 's Antwort zu erweitern, hier ist eine gute Möglichkeit, die obere linke 3x3 einer 4x4 Matrix in Swift zu nehmen, die Vorteile der erweiterten SIMD Unterstützung in der iOS 11/tvOS 11/High Sierra Version von SceneKit:

extension float4 { 
    var xyz: float3 { 
     return float3(x, y, z) 
    } 

    init(_ vec3: float3, _ w: Float) { 
     self = float4(vec3.x, vec3.y, vec3.z, w) 
    } 
} 

extension float4x4 { 
    var upperLeft3x3: float3x3 { 
     let (a,b,c,_) = columns 
     return float3x3(a.xyz, b.xyz, c.xyz) 
    } 

    init(rotation: float3x3, position: float3) { 
     let (a,b,c) = rotation.columns 
     self = float4x4(float4(a, 0), 
         float4(b, 0), 
         float4(c, 0), 
         float4(position, 1)) 
    } 
} 

Dann Ihr Agent aktualisieren Sie Ihre Knotens Ausrichtung übereinstimmen, dann würden Sie schreiben:

agent.rotation = node.simdTransform.upperLeft3x3 

Oder, wenn der betreffende Knoten nicht an der „Wurzel“ Ebene (wie in, ein direktes Kind des rootNode), möchten Sie möglicherweise die WorldTransform des Knotens verwenden:

agent.rotation = node.simdWorldTransform.upperLeft3x3 

EDIT: Wenn der betreffende Knoten eine dynamische Physik Körper angebracht hat, oder mit einem SCNTransaction Block animiert wird, wird der Präsentationsknoten des Knotens wird genauer seine aktuelle Position auf dem Bildschirm reflektieren:

agent.position = node.presentation.simdWorldPosition 
agent.rotation = node.presentation.simdWorldTransform.upperLeft3x3 

BEARBEITEN: Code oben hinzugefügt, um in die andere Richtung zu gehen und den Knoten so zu verschieben, dass er dem Agenten entspricht.

node.simdTransform = float4x4(rotation: agent3d.rotation, position: agent3d.position) 

Beachten Sie, dass, wenn Sie einen Physik Körper an den Knoten angeschlossen ist, es kinematic eher sein sollte als dynamic, wenn Sie direkt auf diese Weise modifiziert werden, gehst zu verwandeln die Knotens.

+0

Danke für das Posten, sehr hilfreich! Dieser Code ist so viel sauberer als das, was mir eingefallen ist. – Phi

+0

Einverstanden, das ist wirklich hilfreich. – possen

5

SceneKit nimmt Matrizen als SCNMatrix4 Transformation und liefert Dienstprogramme für von SIMD Umwandlung matrix_float4x4: init(_ m: float4x4) für Swift und SCNMatrix4FromMat4 für ObjC/C++.

Leider sehe ich keine eingebaute Möglichkeit, zwischen SIMD 3x3 und 4x4 Matrizen zu konvertieren mit der Annahme, dass die 3x3 die obere linke der 4x4 ist. (Scheint so, als würden Sie das in der SIMD-Bibliothek erwarten, also ist es filing a bug to Apple ungefähr wert.)

Aber es ist nicht zu schwer, einen selbst zu erstellen: einfach einen 4x4 aus Spaltenvektoren konstruieren, mit den drei Spaltenvektoren des 3x3 (aufgefüllt zu float4 Vektoren mit Null für die w Komponente) und Identität für die vierte Spalte (0,0,0,1). (Implementation Code links für den Leser, zum Teil, weil ich nicht will, es schreiben für drei Sprachen.) Nach der Umwandlung float3x3-float4x4 Sie SCNMatrix4 umwandeln können.


Edit: In iOS 11/tvOS 11/macOS 10.13 (warum sie nicht nur diesjährige macOS Version 11 nennen, auch?), SceneKit hat einen ganzen parallelen Satz von APIs für die Typen SIMD mit wie float4x4 direkt; z.B. simdTransform. Sie müssen jedoch noch eine 3x3-Matrix in eine 4x4-Matrix konvertieren.

+0

Danke Rickster, ich schätze Ihre ausführliche Antwort es sehr hilfreich war für mich wirklich.Zumindest weiß ich jetzt, was ich tun muss, ich suchte durch simd und andere Bibliotheken, nur hoffend, dass ich vielleicht gerade eine Methode/Funktion übersehen habe. Nur eine letzte Sache, ich habe deine anderen Antworten auf verschiedene Fragen gesehen, du bist ein verdammter Zauberer, ich hoffe, dass ich eines Tages so gut wie du sein kann. Danke noch einmal! – Phi

+0

Hey Ryan Entschuldigung wegen der späten Antwort, ich habe keinen Beispielcode zur Hand, aber wenn Sie eine spezifische Frage zur Implementierung haben, lassen Sie es mich wissen. – Phi

+0

Danke für das Update Rickster, so froh, dass sie SIMD-Typen hinzugefügt haben, ich freue mich wirklich darauf, sie zu verwenden 8). – Phi