2016-06-19 8 views
7

Update-Set: eine jsfiddle hinzugefügt zu erläutern:eines Objekts absolute Rotation um die Weltachse

JSFiddle

Ich habe ein Objekt (ein Würfel), die in der Szene platziert wird. Mein Ziel ist es, 3 Winkel zu liefern, die die Orientierung eines Objekts in der realen Welt repräsentieren. Die Winkel werden gegen die reale X-, Y- und Z-Achse gemessen. Was ich (kläglich) versage ist, wie man einem Objekt diese Winkel gibt und dann, wenn sich die Daten ändern, setze das Objekt auf ein neues Tripel von Winkeln. Was ich zu finden scheint, ist, dass wenn ich einen Anfangssatz von Winkeln einstelle, alles gut ist, aber wenn ich einen neuen Satz von Winkeln einstelle, scheinen sie relativ zur Orientierung des lokalen Objektraums im Gegensatz zum Weltraum eingestellt zu sein. Ich habe versucht, einige der ähnlichen Fragen zu verstehen, die in diesem Bereich gestellt werden, aber diese scheinen sich auf das Drehen eines Objekts um eine Achse zu konzentrieren, anstatt die Winkel eines Objekts explizit gegen die Weltachse zu setzen.

Wenn ein Wert meines x, y oder z Winkel ändert, ich bin derzeit Aufruf:

cube.rotation.set(x, y , z, 'XYZ'); 

weiter zu veranschaulichen, hier ist ein Screenshot von meinem Würfel ... ohne X oder Y zu ändern, I drehen 90 über Z ... siehe die beiden Bilder von vor und nach

enter image description here

und

enter image description here

Beachten Sie, wie die Drehung um die Richtung der Normalen der lila Gesicht und nicht auf der ganzen Welt Z-Achse ...

ich :-(

+0

Siehe http://stackoverflow.com/questions/14774633/how-to-rotate-an-object-and-reset-its-rotation-to-zero/14776900#14776900 und http://stackoverflow.com/questions/19385534/rotate-object-around-world-axis/19386917 # 19386917 dir helfen. – WestLangley

+0

Testen ... ... ich dachte, es funktionierte, als ich den Code von cube.rotation.set (x, y, z, 'XYZ') änderte; zu cube.rotation.set (x, y, z, 'ZYX'); aber es hat das Problem nur auf eine andere Achse verschoben. – Kolban

+0

Eine jsFiddle hinzugefügt, um zu veranschaulichen. – Kolban

Antwort

1

stapfte bin aufgetreten Sie haben ein hinzufügen Drehpunkt zur Szene, dies wird das Zentrum der Drehungen sein. Der Würfelmaische muss zum Drehpunkt hinzugefügt werden, und dann können Sie den Drehpunkt drehen.

ich Ihre jsFiddle hier aktualisiert: https://jsfiddle.net/x5w31f33/

var cube = new THREE.Mesh(geometry, material); 
cube.position.set(2, 0, 0); 

var pivotPoint = new THREE.Object3D(); 
scene.add(pivotPoint); 
pivotPoint.add(cube); 

pivotPoint.rotation.set(x, y , z, 'XYZ'); 
3

cube.rotation.set(), wie Sie bereits entdeckt haben, schafft eine Drehung entlang der lokalen Achsen des Objekts. Während der ersten Drehung, etwa entlang X, ist die lokale X-Achse in Weltkoordinaten genau gleich der Welt-X-Achse. Nach der Drehung sind die lokalen Y- und Z-Achsen in den Weltkoordinaten jedoch nicht mehr gleich den Y- und Z-Weltachsen. Daher werden nachfolgende Rotationen entlang dieser Achsen nicht mehr wie Rotationen entlang der Weltachsen aussehen. Wenn Sie die Reihenfolge der Rotationen ändern, wird wiederum nur die erste Rotation in einem lokalen Raum stattfinden, der übrigens mit dem Weltall identisch ist. Alle nachfolgenden Rotationen werden im lokalen Raum berechnet, der nicht mehr identisch ist.

Sie möchten Ihr Objekt dreimal rotieren: einmal entlang der X-Achse der Welt, einmal entlang der Y-Achse der Welt und einmal entlang der Z-Achse der Welt. Aber wir wissen jetzt, dass alle Rotationen im lokalen Raum stattfinden. Der Schlüssel zu den Drehungen im Weltall ist die Frage: "Wie sieht diese Weltachse im lokalen Raum meines Objekts aus?" Wenn Sie eine Weltachse verwenden, sie als Vektor im lokalen Bereich des Objekts ausdrücken und dann eine Drehung entlang dieses Vektors ausführen können, haben Sie selbst eine Drehung entlang eines Weltvektors, unabhängig vom spezifischen lokalen Raum.

Lassen Sie uns diese Idee in Ihre Geige integrieren:

var x = toRadians($("#rotateX").slider("option", "value")); 
var y = toRadians($("#rotateY").slider("option", "value")); 
var z = toRadians($("#rotateZ").slider("option", "value")); 

var rotation = new THREE.Matrix4(); 
rotation.multiply(new THREE.Matrix4().makeRotationX(x)); 

var worldYAxis = new THREE.Vector3(0, 1, 0).applyMatrix4(new THREE.Matrix4().getInverse(rotation)); 
var rotationWorldY = new THREE.Matrix4().makeRotationAxis(worldYAxis, y); 
rotation.multiply(rotationWorldY); 

var worldZAxis = new THREE.Vector3(0, 0, 1).applyMatrix4(new THREE.Matrix4().getInverse(rotation)); 
var rotationWorldZ = new THREE.Matrix4().makeRotationAxis(worldZAxis, z); 
rotation.multiply(rotationWorldZ); 

cube.matrixAutoUpdate = false; 
cube.matrix = rotation; 

Wenn Sie diesen Code versuchen, werden Sie feststellen, dass X Umdrehungen bemerken sind entlang der X-Achse Welt, wenn Y und Z Drehungen Null sind, sind Y Drehungen entlang die Welt-Y-Achse, wenn Z-Rotation ist Null und Z-Rotationen sind immer entlang der Z-Achse.

Aber was ist, wenn nach dem Setzen eines X, dann ein Y, dann eine Z-Drehung, wir den X-Schieber wieder drehen? Sie werden feststellen, dass die Rotation nicht mehr entlang der X-Achse der Welt verläuft, sondern entlang der lokalen X-Achse. Der Grund dafür ist einfach, obwohl die Erklärung, warum es so ist, nicht sein kann. Mit einem Wort - Rotationen pendeln nicht. Sie sehen, die Rotationen X(a) * Y(b) * Z(c) * X(d) ist im Allgemeinen nicht gleich X(a + d) * Y(b) * Z(c). Das heißt, wenn Sie entlang Welt X von a, dann entlang Welt Y von b, dann entlang Welt Z von c, und dann wieder entlang Welt X von d, dann ist das Ergebnis nicht das gleiche wie die Rotation, die Sie bekommen hätten wenn du dich von Anfang an entlang der Welt X um a + d gedreht hättest. Der Grund dafür ist, dass "Welt X" am Anfang der Transformationen und "Welt X" am Ende der Transformationen zwei verschiedene Vektoren sind, deren Werte von allen Transformationen abhängen, die bis zu diesem Punkt ausgeführt wurden. Sie repräsentieren daher verschiedene Drehachsen im lokalen Raum.

Ich werde versuchen, die nächste Frage zu antizipieren: "Wie kann ich es so machen, dass, egal wie ich meine Schieberegler nach links und rechts bewege, das Objekt immer nur entlang der Weltachsen rotiert?" Die Antwort darauf basiert auf dem, was wir bereits über Drehungen um Weltachsen wissen - die Weltachse muss als Vektor im lokalen Raum ausgedrückt werden und die Rotation muss um diesen Vektor herum stattfinden. Eine Umsetzung der Idee folgt:

var prevX = 0, prevY = 0, prevZ = 0; 
function doRotate() { 
    var x = toRadians($("#rotateX").slider("option", "value")); 
    var y = toRadians($("#rotateY").slider("option", "value")); 
    var z = toRadians($("#rotateZ").slider("option", "value")); 

    var inverse = new THREE.Matrix4().getInverse(cube.matrix); 

    var rotation = cube.matrix; 
    var worldXAxis = new THREE.Vector3(1, 0, 0).applyMatrix4(new THREE.Matrix4().getInverse(rotation)); 
    var rotationWorldX = new THREE.Matrix4().makeRotationAxis(worldXAxis, x - prevX); 
    rotation.multiply(rotationWorldX); 
    var worldYAxis = new THREE.Vector3(0, 1, 0).applyMatrix4(new THREE.Matrix4().getInverse(rotation)); 
    var rotationWorldY = new THREE.Matrix4().makeRotationAxis(worldYAxis, y - prevY); 
    rotation.multiply(rotationWorldY); 
    var worldZAxis = new THREE.Vector3(0, 0, 1).applyMatrix4(new THREE.Matrix4().getInverse(rotation)); 
    var rotationWorldZ = new THREE.Matrix4().makeRotationAxis(worldZAxis, z - prevZ); 
    rotation.multiply(rotationWorldZ); 

    prevX = x; 
    prevY = y; 
    prevZ = z; 

    cube.matrixAutoUpdate = false; 
    cube.matrix = rotation; 
} 

Fiddle: https://jsfiddle.net/2whv0e8o/13/

Die obige Funktion als slide Ereignishandler aller Schieber gebunden ist: "slide": doRotate. Nun, wenn Sie versuchen, hin und her zu rotieren, werden Sie feststellen, dass unabhängig von der aktuellen Ausrichtung der Box die Bewegung des Schiebers immer zu Rotationen entlang der Weltachsen führt. Es gibt jedoch eine Einschränkung: Die Werte der Schieberegler repräsentieren nicht mehr die tatsächlichen Drehwinkel um eine bestimmte Achse. Sie werden feststellen, dass die Funktion doRotate nur eine Delta-Rotation entlang der Weltachsen anwendet, wie sie derzeit in lokalen Koordinaten ausgedrückt werden. Wir haben das Ziel erreicht, inkrementelle Rotationen anwenden zu können, die immer entlang der Weltachsen ausgeführt werden, aber wir haben die Bedeutung der absoluten Werte der X-, Y- und Z-Schieberegler verloren. Aber wenn die Werte nichts bedeuten, was kann möglicherweise verwendet werden, um die aktuelle Rotation des Objekts als die Rotation zu speichern? Nach meiner Erfahrung ist es am besten, die Transformationsmatrix des Objekts nur groß zu speichern. Das heißt, anstatt zu versuchen, drei bestimmte Rotationswinkel plus einen Translationsvektor und eventuell Skalierungsparameter zu speichern, speichern Sie einfach die gesamte Matrix als Teil des Objekts.

Verwandte Themen