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.
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
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
Eine jsFiddle hinzugefügt, um zu veranschaulichen. – Kolban