Objekt im 3D Raum rotieren/transformieren - Umwandlungsmatrix gesucht

OP (Firma: RUB) #7583910
Lesenswert?

Hallo Forum,

Für ein Spiel möchte ich ein spherisches Objekt erstellen, ähnlich zu einem Conway/Goldberg Polyhedron. Dazu habe ich 5 und 6 eckige Kacheln erstellt und versuche diese jetzt zu platzieren. Die Sphere soll einen Radius von 25 Meter haben. Dazu habe ich die Kacheln mit einem Offset von 25 Meter auf der X Achse zum Koordinatenursprung versehen (die Kacheln liegen also auf der Außenseite einer Kugel mit Radius=25m). Also so, als wenn man einen Stift an eine Schnur bindet, und das andere Ende der Schnur festnagelt. Mein Gedanke dabei war, das ich dann ja "nur" die Winkel x/y/z einstellen brauche, und dann ist die Kachel schon am richtigen Ort.

Für die Spielentwicklung nutze ich die Godot Engine. https://godotengine.org/

Da ich keine Lust habe x solcher Kacheln von Hand zu platzieren, habe ich versucht mir die Objekte automatisiert zu erstellen. Der Editor speichert das Objekt in folgendem Format:

1
transform = Transform3D(x1, x2, x3, y1, y2, y3, z1, z2, z3, w1, w2, w3)

x/y/z sind die Skalierungs und Rotationsvektoren (M=R.S)

w1,w2,w3 sind die x/y/z Entfernung in Meter zum Koordinatenursprung (in diesem Falle 0, wegen dem Offset auf dem Objekt selbst).

Jetzt kommt das "Problem": Im Editor der Engine kann ich ein Objekt um jede Achse einzeln drehen, ohne das die anderen Achsen beeinflusst werden. Um bei dem Beispiel mit dem Stift an der Schnur zu bleiben: Stift um X Grad nach rechts ziehen, und Y Grad nach oben.

Das scheint aber keine Rotation im mathematischen Sinne zu sein.

Als Beispiel habe ich mal die Kachel im Editor um x=17° y=29° und z=35° "rotiert". Wenn ich das Objekt speicher, dann ergeben sich folgende Werte:

1
transform = Transform3D(0.716447, -0.501661, 0.48481, 0.664624, 0.702058, -0.255714, -0.212082, 0.505422, 0.836403, 0, 0, 0)

Wenn ich aber versuche das zu berechnen, also eine Matrix [[1,0,0] [0,1,0] [0,0,1]] nehme, und nacheinander an den Achsen um die jeweiligen Winkel rotiere, dann erhalte ich aus meinem Programm diese Werte:

1
transform = Transform3D(0.716447, 0.664624, -0.212082, -0.501661, 0.702058, 0.505422, 0.484810, -0.255714, 0.836403, 0, 0, 0)

Wenn ich das dann im Editor öffne, zeigt der Editor diese Winkel für das Objekt an:

x: -31,1° y: -12,2° z: -42,9°

Ehrlich gesagt bin ich nicht so fit in Mathe, dass ich da jetzt erkennen könnte, was ich genau machen muss, um die richtigen Werte zu erhalten. Ich bin für jede Hilfe dankbar und freue mich, wenn ihr mir hier etwas helfen könntet.

Grüße

Angehängte Dateien:
OP (Firma: RUB) #7584000
Lesenswert?

Rolf M. schrieb:

Man muss bedenken, dass Matrix-Multiplikationen nicht kommutativ sind. Das heißt, die Reihenfolge ist wichtig.

Richtig, das habe ich auch schon rausgefunden. Das ist aber nicht, was ich möchte. Im Editor ist die Reihenfolge anscheinend nicht wichtig, bzw. scheint dort etwas anderes zu passieren.

Vllt ist es eher transformation/translation statt rotation, oder es fehlt noch ein korrektur schritt?

Moderator #7584007
Lesenswert?

Die in der zweiten Transformation enthaltene Rotationsmatrix (die ersten 9 Elemente) ist die Transponierte der Rotationsmatrix der ersten Transformation. Da hast du bei deiner Berechnung wohl irgendetwas durcheinandergeschmissen.

Edit:

Da bei Rotationsmatrizen die Transponierte gleich der Inversen ist, hast du evtl. statt der Rotation von der Start- zur Zielorientierung versehentlich die rückwärts gerichtete Rotation, also von der Ziel- zur Startorientierung berechnet.

#7584029
Lesenswert?

Kaj G. schrieb:

die Kacheln liegen also auf der Außenseite einer Kugel mit Radius=25m

Das Goldberg-Polyhedron ist ziemlich tricky. Ich hatte mit denen das Problem, dass meine Kacheln nicht planar wurden. Mir hat dann ein hawaiianischer Mathematiker geholfen. Das Resultat findest du unter https://github.com/eddyverl/FreeCad-Pyramids-and-Polyhedrons.

HTH.

LG, Sebastian

OP (Firma: RUB) #7584082
Lesenswert?

Yalu X. schrieb:

Da hast du bei deiner Berechnung wohl irgendetwas durcheinandergeschmissen.

Das steht außer Frage :D

Hier mein Code (Rust) zur Berechnung (hät ich auch gleich posten können -.-* ):

1
use na::{Rotation3, SMatrix, Vector3};
2
use std::{io::Write, process::exit};
3

4
type Matrix3x3 = SMatrix<f32, 3, 3>;
5

6
fn main() {
7
    let base = Matrix3x3::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
8
    let result = rotate(base, 17.0, 29.0, 35.0);
9
    // result[0.716447, 0.664624, -0.212082, -0.501661, 0.702058, 0.505422, 0.484810, -0.255714, 0.836403]
10
}
11

12
fn deg_to_rad(deg: f32) -> f32 {
13
    deg * std::f32::consts::PI / 180f32
14
}
15

16
fn rotate(m: Matrix3x3, x: f32, y: f32, z: f32) -> Matrix3x3 {
17
    let x_axis = Vector3::x_axis();
18
    let y_axis = Vector3::y_axis();
19
    let z_axis = Vector3::z_axis();
20

21
    let x_angle = deg_to_rad(x);
22
    let y_angle = deg_to_rad(y);
23
    let z_angle = deg_to_rad(z);
24

25
    let x_rotation = Rotation3::from_axis_angle(&x_axis, x_angle);
26
    let y_rotation = Rotation3::from_axis_angle(&y_axis, y_angle);
27
    let z_rotation = Rotation3::from_axis_angle(&z_axis, z_angle);
28

29
    let mut m = m;
30
    m *= x_rotation;
31
    m *= y_rotation;
32
    m *= z_rotation;
33

34
    m
35
}
Moderator #7584265
Lesenswert?

Wenn ich deinem Code noch ein

1
    println!("{}", result);

hinzufüge, erhalte ich folgende Ausgabe:

1
  ┌                                     ┐
2
  │   0.7164465  -0.5016613   0.4848096 │
3
  │  0.66462433  0.70205754 -0.25571406 │
4
  │ -0.21208239   0.5054217  0.83640295 │
5
  └                                     ┘

Die Rotationsmatrix stimmt mit der von Godot angezeigten überein (s. Anhang).

Wenn ich das richtig sehe, wird die Transformation im .tscn-File wie folgt abgespeichert:

1
Transform3D(r₁₁, r₁₂, r₁₃, r₂₁, r₂₂, r₂₃, r₃₁, r₃₂, r₃₃, t₁, t₂, t₃)

Die Rotationsmatrix wird also zeilenweise abgelegt, gefolgt vom Translationsvektor. Du bist irrtümlicherweise davon ausgegangen, dass die Matrix spaltenweise abgelegt wird, so dass die drei Elemente der Basisvektoren jeweils direkt hintereinander in der Argumentliste auftauchen.

Rolf M. schrieb:

Die Multiplikation ist falsch herum.

Nein, das stimmt so. Godot bezieht die Winkel auf intrinsische Rotationen (mitdrehendes Koordinatensystem), während Kaj in seinem Rust-Programm mit extrinsischen Rotationen (feststehendes Koordinatensystem) rechnet. Diesen Unterschied hat Kaj (bewusst oder unbewusst) dadurch kompensiert, dass er die Reihenfolge der drei Einzelrotationen umgedreht hat.

Kaj G. schrieb:

Das scheint es gewesen zu sein. Danke :)

Ich glaube nicht, denn durch Umdrehen der Rotationsreihenfolge erhältst du ganz andere Zahlenwerte.

Angehängte Dateien:
OP (Firma: RUB) #7584317
Lesenswert?

Yalu X. schrieb:

Die Rotationsmatrix stimmt mit der von Godot angezeigten überein (s. Anhang).

Ja, das stimmt schon. Aber es wird (anscheinend) anders abgespeichert.

1
fn get_rotation(m: Matrix3x3, x: f32, y: f32, z: f32) -> Matrix3x3 {
2
    let x_axis = Vector3::x_axis();
3
    let y_axis = Vector3::y_axis();
4
    let z_axis = Vector3::z_axis();
5

6
    let x_angle = deg_to_rad(x);
7
    let y_angle = deg_to_rad(y);
8
    let z_angle = deg_to_rad(z);
9

10
    let x_rotation = Rotation3::from_axis_angle(&x_axis, x_angle);
11
    let y_rotation = Rotation3::from_axis_angle(&y_axis, y_angle);
12
    let z_rotation = Rotation3::from_axis_angle(&z_axis, z_angle);
13

14
    z_rotation * (y_rotation * (x_rotation * m))
15
}

liefert mir genau das, was ich haben möchte (abgesehen vom vorzeichen).

Moderator #7584392
Lesenswert?

Kaj G. schrieb:

Yalu X. schrieb:

Die Rotationsmatrix stimmt mit der von Godot angezeigten überein (s. Anhang).

Ja, das stimmt schon. Aber es wird (anscheinend) anders abgespeichert.

Eben. Und genau das (und nur das) ist der Grund für die ganze Verwirrung.

Kaj G. schrieb:

z_rotation * (y_rotation * (x_rotation * m)) } liefert mir genau das, was ich haben möchte (abgesehen vom vorzeichen).

Das liefert

1
  ┌                                     ┐
2
  │   0.7164465 -0.43240356   0.5474775 │
3
  │   0.5016613   0.8646603  0.02642797 │
4
  │  -0.4848096  0.25571406  0.83640295 │
5
  └                                     ┘

Du wolltest aber doch diese Werte hier sehen:

Kaj G. schrieb:

Als Beispiel habe ich mal die Kachel im Editor um x=17° y=29° und z=35° "rotiert". Wenn ich das Objekt speicher, dann ergeben sich folgende Werte: transform = Transform3D(0.716447, -0.501661, 0.48481, 0.664624, 0.702058, -0.255714, -0.212082, 0.505422, 0.836403, 0, 0, 0)

Selbst wenn man die Werte geeignet anordnet, stimmen nur zwei davon mit denen der obigen Matrix überein. Drei weitere haben das falsche Vorzeichen, und die restlichen vier sind völlig verschieden.

Die mit deinem modifizierten Rust-Programm berechneten Werte erhältst du auch in Godot, wenn du dort die "Rotation Order" von "XYZ" in "ZYX" änderst.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren