2016-09-15 1 views
5

Ich habe ein Objekt mit OpenGL ES auf einem iPad angezeigt. Das Modell wird durch Vertices, Normalen und Indizes zu Vertices definiert. Der Ursprung des Modells ist 0,0,0. Mit UIGestureRecognizer kann ich verschiedene Gesten erkennen - zwei Finger horizontal für Rotation um y, vertikal für Rotation um x. Geste mit zwei Fingern zum Drehen um y. Schwenken, um das Modell zu verschieben. Prise/Zoom-Geste zum Skalieren. Ich möchte, dass der Betrachter das Modell manipulieren kann, um zum Beispiel die Rückseite des Modells oder das Ganze auf einmal zu sehen.Wenden Sie die Drehung um die Achse an, die durch den berührten Punkt definiert wurde

Die grundlegende Strategie kommt von Ray Wenderlich's tutorial, aber ich habe dies in Swift neu geschrieben.

Ich verstehe Quaternionen zu einem Vektor und einem Winkel. Die Vektoren up, right und front repräsentieren die drei Achsen:

front = GLKVector3Make(0.0, 0.0, 1.0) 
right = GLKVector3Make(1.0, 0.0, 0.0) 
up = GLKVector3Make(0.0, 1.0, 0.0) 

so die Quaternion Äpfel eine Drehung um jede der drei Achsen (obwohl nur einer von dx, dy, dz einen Wert hat, durch die Gestenerkenner entschieden .)

func rotate(rotation : GLKVector3, multiplier : Float) { 

    let dx = rotation.x - rotationStart.x 
    let dy = rotation.y - rotationStart.y 
    let dz = rotation.z - rotationStart.z 
    rotationStart = GLKVector3Make(rotation.x, rotation.y, rotation.z) 
    rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(dx * multiplier, up), rotationEnd) 
    rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(dy * multiplier, right), rotationEnd) 
    rotationEnd = GLKQuaternionMultiply((GLKQuaternionMakeWithAngleAndVector3Axis(-dz, front)), rotationEnd) 
    state = .Rotation 

} 

Zeichnung verwendet die modelViewMatrix, durch die folgende Funktion berechnet:

func modelViewMatrix() -> GLKMatrix4 { 

    var modelViewMatrix = GLKMatrix4Identity 
    // translation and zoom 
    modelViewMatrix = GLKMatrix4Translate(modelViewMatrix, translationEnd.x, translationEnd.y, -initialDepth); 
    // rotation 
    let quaternionMatrix = GLKMatrix4MakeWithQuaternion(rotationEnd) 
    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, quaternionMatrix) 
    // scale 
    modelViewMatrix = GLKMatrix4Scale(modelViewMatrix, scaleEnd, scaleEnd, scaleEnd); 
    // rotation 

    return modelViewMatrix 
} 

Und meistens funktioniert das. Aber alles ist relativ zum Ursprung. Wenn das Modell gedreht wird, ist der Drehpunkt immer eine Achse, die durch den Ursprung verläuft. Wenn das Ende des Modells vom Ursprung weggezoomt und dann gedreht wird, kann das Modell schnell aus der Sicht schwingen. Wenn das Modell skaliert wird, ist der Ursprung immer der Fixpunkt, wobei das Modell größer oder kleiner wird. Wenn der Ursprung außerhalb des Bildschirms liegt und der Maßstab verkleinert wird, kann das Modell aus der Ansicht verschwinden, wenn es zum Ursprung kollabiert ...

Was passieren sollte ist, dass das Modell unabhängig von der aktuellen Ansicht relativ zur aktuellen Ansicht rotiert oder skaliert. Für eine Drehung um die y-Achse würde das bedeuten, die y-Achse zu definieren, um die die Rotation stattfindet, indem sie vertikal durch die Mitte der aktuellen Ansicht verläuft. Bei einer Skalierungsoperation würde der Fixpunkt des Modells in der Mitte des Bildschirms liegen, wobei das Modell von diesem Punkt aus schrumpft oder nach außen wächst.

Ich weiß, dass in 2D die Lösung immer auf den Ursprung zu übersetzen ist, wenden Sie Rotation an und wenden Sie dann das Inverse der ersten Übersetzung an. Ich sehe nicht, warum dies in 3D anders sein sollte, aber ich kann kein Beispiel dafür finden, dass dies nur mit Quaternionen-Matrizen geschieht. Ich habe versucht, eine Übersetzung und ihre Umkehrung um die Rotation anzuwenden, aber nichts hat eine Wirkung.

So habe ich versucht, dies in der Drehfunktion zu tun:

let xTranslation : Float = 300.0 
let yTranslation : Float = 300.0 
let translation = GLKMatrix4Translate(GLKMatrix4Identity, xTranslation, yTranslation, -initialDepth); 
rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithMatrix4(translation) , rotationEnd) 

rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(dx * multiplier, up), rotationEnd) 
rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(dy * multiplier, right), rotationEnd) 
rotationEnd = GLKQuaternionMultiply((GLKQuaternionMakeWithAngleAndVector3Axis(-dz, front)), rotationEnd) 

// inverse translation 
let inverseTranslation = GLKMatrix4Translate(GLKMatrix4Identity, -xTranslation, -yTranslation, -initialDepth); 
rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithMatrix4(inverseTranslation) , rotationEnd) 

Die Übersetzung ist 300.300, aber es gibt überhaupt keine Wirkung, es um noch schwenkt, wo ich den Ursprung kennen zu. Ich habe lange nach Beispielcode gesucht und keine gefunden.

Die modelViewMatrix in Update angewendet wird() mit:

effect?.transform.modelviewMatrix = modelViewMatrix 

ich auch durch die Einstellung aller Werte im Modell betrügen könnte, so dass 0,0,0 an einem zentralen Punkt fällt - aber das würde immer noch ein fester Ursprung sein und wäre nur marginal besser.

+0

Matrixmultiplikation sehr kontraintuitiv sein kann - meine Anfangsgedanke (da ich das schon oft selbst vermasselt habe) ist, dass du die Matrizen in der falschen Reihenfolge multiplizierst. Ich bin mir nicht sicher, welches Verhalten Sie genau suchen; Vergleichen Sie mit [diese Modell-Anzeige-Site] (https://sketchfab.com/models/7355bbb7edf14fed9273eedadf513f5c), die einen festen Ursprung in Bezug auf die Ansicht behält. Ist es das, wofür du hingehst, oder wie möchtest du, dass dein anders ist? –

+0

Das ist ein gutes Beispiel für festen Ursprung. Übersetzen Sie das Bike weg von der Mitte und dann schwingt es in einem weiten Bogen um die Mitte. Ich möchte, dass die Rotationsachse ein Punkt zwischen den beiden Fingern ist, der die Rotationsbewegung ausführt. Jetzt, das nur einen 2d Punkt definiert, aber das gleiche z wie der Ursprung für die Rotation beibehalten würde, wäre ok. –

+0

Können Sie mehr erklären, was Sie wollen? Zum Beispiel, können Sie eine Liste von Fragen stellen? – ELKA

Antwort

2

Das Problem ist in der letzten Operation, die Sie gemacht, sollten Sie die inverseTranslation mit rotationEnd tauschen:

rotationEnd = GLKQuaternionMultiply(rotationEnd, GLKQuaternionMakeWithMatrix4(inverseTranslation)) 

Und ich denke, dass die Teildrehung (dx, dy, dz) sollte die gleiche Regel folgen.

In der Tat, wenn Sie die Pivot ändern möchten, ist dies, wie Sie Ihre Matrix-Multiplikation durchgeführt werden sollte:

modelMatrix = translationMatrix * rotationMatrix * inverse(translationMatrix) 

und das Ergebnis in homogenen Koordinaten errechnet sich wie folgt:

newPoint = translationMatrix * rotationMatrix * inverse(translationMatrix) * v4(x,y,z,1) 

Beispiel

Dies ist ein 2D-Testbeispiel, das Sie auf einem Spielplatz ausführen können.

enter image description here

let v4 = GLKVector4Make(1, 0, 0, 1) // Point A 

let T = GLKMatrix4Translate(GLKMatrix4Identity, 1, 2, 0); 
let rot = GLKMatrix4MakeWithQuaternion(GLKQuaternionMakeWithAngleAndVector3Axis(Float(M_PI)*0.5, GLKVector3Make(0, 0, 1))) //rotate by PI/2 around the z axis. 
let invT = GLKMatrix4Translate(GLKMatrix4Identity, -1, -2, 0); 

let partModelMat = GLKMatrix4Multiply(T, rot) 
let modelMat = GLKMatrix4Multiply(partModelMat, invT) //The parameters were swapped in your code 
//and the result would the rot matrix, since T*invT will be identity 

var v4r = GLKMatrix4MultiplyVector4(modelMat, v4) //ModelMatrix multiplication with pointA 
print(v4r.v) //(3,2,0,1) 

//Step by step multiplication using the relation described above 
v4r = GLKMatrix4MultiplyVector4(invT, v4) 
v4r = GLKMatrix4MultiplyVector4(rot, v4r) 
v4r = GLKMatrix4MultiplyVector4(T, v4r) 
print(v4r.v) //(3,2,0,1) 

Was die Waage, wenn ich das richtig verstehe, was Sie wollen, würde ich es zu tun, empfehlen wie es hier getan: https://gamedev.stackexchange.com/questions/61473/combining-rotation-scaling-around-a-pivot-with-translation-into-a-matrix

+0

Danke für Ihre ausführliche Erklärung, ich verstehe viel mehr darüber, was jetzt passiert. –

Verwandte Themen