Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Krane

Treue Seele

  • »Krane« ist der Autor dieses Themas

Beiträge: 312

Wohnort: Innsbruck, Tirol

  • Private Nachricht senden

1

11.01.2016, 17:24

Euler Angles zu Vorwärts-Vektor konvertieren

Hallo Leute,
Ich schreibe gerade das Grungerüst für ein 3D Spiel in C++ und OpenGL.
Die "Engine" basiert auf einem simplen Entity-Component-System, also habe ich eine Klasse namens TransformComponent, welche Position, Rotation und Skalierung speichert und Berechnungen mit ihnen durchführt. Meine Rotation wird nicht in einer Quaternion sondern in Euler Angles (3x float) gespeichert.

Nun zum eigentlichen Problem:
Ich möchte eine Funktion schreiben welche mir, Anhand der Euler Angles, den Vorwärts-Vektor zurückgibt.
In 2 Dimensionen ist das ganze kein Problem: V = vec2(sin(angle), cos(angle)).
Leider komme ich aber nach langem Überlegen nicht darauf, wie ich das ganze in 3 Dimensionen umsetze.
Gibt es dafür eine Formel, oder muss ich mein System auf Quaternions umstellen?

Danke im Voraus,
Krane

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

2

11.01.2016, 18:00

Na ja, wenn du den untransformierten Vorwärtsvektor kennst, müsstest du diesen natürlich auch durch deine wahrscheinlich schon bestehende Transformation für Vektoren in das Zielkoordinatensystem jagen können.

Sprich, du hast eine Transformation T von dem lokalen Koordinatensystem des Objekts in den Worldspace. Dann musste der untransformierte Vorwärtsvektor sich in den transformierten Vektor v' durch v' = T * v bringen lassen.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

Krane

Treue Seele

  • »Krane« ist der Autor dieses Themas

Beiträge: 312

Wohnort: Innsbruck, Tirol

  • Private Nachricht senden

3

11.01.2016, 18:19

Hmm, meinst du die Model Matrix des Objektes?
Mit glm kann man leider, soweit ich weiß, keine Vektoren mit 4x4Matrizen multiplizieren.

Hier etwas Code um das ganze besser zu veranschaulichen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include "Component.h"
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <vector>
#include <iostream>

class TransformComponent : public Component
{
    public:
        TransformComponent();
        virtual ~TransformComponent();

        void Update() {}

        void Translate(glm::vec3 delta);
        void Rotate(glm::vec3 delta);
        void RotateAround(glm::vec3 delta) {};
        void Scale(glm::vec3 delta);

        glm::mat4 GetModel() const
        {
            return glm::translate(m_position) * glm::rotate(m_rotation.z, glm::vec3(0,0,1)) * glm::rotate(m_rotation.y, glm::vec3(0,1,0)) * glm::rotate(m_rotation.x, glm::vec3(1,0,0)) * glm::scale(m_scale);
        }

        glm::vec3 getPosition() { return m_position; }
        glm::vec3 getRotation() { return m_rotation; }
        glm::vec3 getScale() { return m_scale; }

        void setPosition(glm::vec3 position) { m_position = position; }
        void setRotation(glm::vec3 rotation) { m_rotation = rotation; }
        void setScale(glm::vec3 scale) { m_scale = scale; }

        glm::vec3 getForward() { return glm::vec3(0,0,1)*GetModel(); } // <-Problem

        void AddChildTransform(TransformComponent* pChildTransform) { m_childTransforms.push_back(pChildTransform); pChildTransform->setParentTransform(this); }
        void setParentTransform(TransformComponent* pParentTransform) { m_pParentTransform = pParentTransform; }

    private:
        glm::vec3 m_position;
        glm::vec3 m_rotation;
        glm::vec3 m_scale;

        std::vector<TransformComponent*> m_childTransforms;
        TransformComponent* m_pParentTransform;
};

Krane

Treue Seele

  • »Krane« ist der Autor dieses Themas

Beiträge: 312

Wohnort: Innsbruck, Tirol

  • Private Nachricht senden

4

17.01.2016, 12:57

Leider habe ich nach langem Suchen immer noch keine Lösung für mein Problem gefunden.
Ich habe meine Rotation von EulerAngles auf Quaternions geändert, doch auch so erhalte ich komplett falsche Werte.

Hier ist meine getForward Funktion:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
        glm::vec3 getForward()
        {
            const float* matrix = glm::value_ptr(m_modelMatrix);

            std::cout << matrix[6] << " - " << matrix[8] << " - " <<  matrix[10] << std::endl;

            return glm::vec3(matrix[6], matrix[8], matrix[10]);
        }


Komischerweise erhöhen sich die Werte von matrix[6] und matrix[8] in jedem Frame, ohne dass irgendwelche Transformationen vorgenommen werden.
Bin gerade echt am verzweifeln. :/

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

17.01.2016, 13:04

Wie genau kommst du auf die Indices 6, 8 und 10? Wieso multiplizierst du Vektor mit Matrix anstatt umgekehrt?

Und natürlich die obligatorische Frage: Aus welchem Grund genau müssen es Eulerwinkel sein?

Krane

Treue Seele

  • »Krane« ist der Autor dieses Themas

Beiträge: 312

Wohnort: Innsbruck, Tirol

  • Private Nachricht senden

6

17.01.2016, 13:12

Laut dieser Seite geben Element 6, 8 und 10 den Vorwärts Vektor des Objektes wieder.
Hier sind keine Indices im Spiel. m_modelMatrix ist eine glm::mat4 Matrix.

Die EulerWinkel wurden durch Quaternions ersetzt. Es werden nur noch EulerWinkel in der Rotate() Funktion verwendet, diese werden aber sofort in eine Quaternion umgewandelt.

Ich poste nochmal den aktuellen Code:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class TransformComponent : public Component
{
    public:
        TransformComponent();
        virtual ~TransformComponent();

        void Update()
        {
            m_modelMatrix = glm::translate(m_position) * mat4_cast(m_rotation) * glm::scale(m_scale);
        }

        void Translate(glm::vec3 delta);
        void Rotate(glm::vec3 delta);
        void RotateAround(glm::vec3 delta) {};
        void Scale(glm::vec3 delta);

        glm::mat4 GetModel() const
        {
            return m_modelMatrix;
        }

        glm::vec3 getPosition() { return m_position; }
        glm::quat getRotation() { return m_rotation; }
        glm::vec3 getScale() { return m_scale; }

        void setPosition(glm::vec3 position) { m_position = position; }
        void setRotation(glm::vec3 eulerAngles) { m_rotation = glm::quat(eulerAngles); }
        void setScale(glm::vec3 scale) { m_scale = scale; }

        glm::vec3 getForward() <-------
        {
            const float* matrix = glm::value_ptr(m_modelMatrix);

            std::cout << matrix[6] << " - " << matrix[8] << " - " <<  matrix[10] << std::endl;

            return glm::vec3(matrix[6], matrix[8], matrix[10]);
        }

        glm::vec3 getRight()
        {
            return glm::vec3(sin(m_rotation.x+glm::radians(-90.0f)), 0.0f, cos(m_rotation.x+glm::radians(-90.0f)));
        }

        void AddChildTransform(TransformComponent* pChildTransform) { m_childTransforms.push_back(pChildTransform); pChildTransform->setParentTransform(this); }
        void setParentTransform(TransformComponent* pParentTransform) { m_pParentTransform = pParentTransform; }

    private:
        glm::vec3 m_position;
        glm::quat m_rotation;
        glm::vec3 m_scale;

        glm::mat4 m_modelMatrix;

        std::vector<TransformComponent*> m_childTransforms;
        TransformComponent* m_pParentTransform;
};

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

17.01.2016, 13:22

Laut dieser Seite geben Element 6, 8 und 10 den Vorwärts Vektor des Objektes wieder.

Wo genau willst du das dort gelesen haben? Wenn dann wohl Elemente 8, 9 und 10; aber auch das funktioniert nur wirklich für eine bestimmte Klasse von Transformationsmatrizen und gilt nicht allgemein, im Gegensatz zu dem, was auf dieser Seite so steht...

Die EulerWinkel wurden durch Quaternions ersetzt. Es werden nur noch EulerWinkel in der Rotate() Funktion verwendet, diese werden aber sofort in eine Quaternion umgewandelt.

Diese Aussage macht keinen Sinn. Quaternionen sind nur ein Weg um eine bestimmte Klasse von Transformationen (Rotationen) zu repräsentieren. Wenn du aus Eulerwinkeln eine Quaternion baust, verwendest du immer noch Eulerwinkel und wirst eine Quaternion erhalten die beispielsweise völlig äquivalent zu einer aus den selben Eulerwinkeln gebauten Matrix ist...

Krane

Treue Seele

  • »Krane« ist der Autor dieses Themas

Beiträge: 312

Wohnort: Innsbruck, Tirol

  • Private Nachricht senden

8

17.01.2016, 13:31


Wo genau willst du das dort gelesen haben? Wenn dann wohl Elemente 8, 9 und 10; aber auch das funktioniert nur wirklich für eine bestimmte Klasse von Transformationsmatrizen und gilt nicht allgemein, im Gegensatz zu dem, was auf dieser Seite so steht...


Mein Fehler. Meinte natürlich 9,8,10. Leider erhalte ich so aber auch nur den untransformierten Vorwärts Vektor. Also (0,0,1).
Diese Methode scheidet also leider aus.


Hmm, ich orientiere mich in meiner Architektur stark an der Unity Engine. Diese nimmt auch 3 Winkel als Argumente für die Rotate-Funktion, obwohl die Rotation in einer Quaternion gespeichert wird.
Ich denke ich muss mich etwas mehr über Quaternions, vor allem wie man sie einsetzt, informieren.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

17.01.2016, 13:33

Mein Fehler. Meinte natürlich 9,8,10. Leider erhalte ich so aber auch nur den untransformierten Vorwärts Vektor. Also (0,0,1).
Diese Methode scheidet also leider aus.

Aus welcher Matrix liest du die nun aus?

Hmm, ich orientiere mich in meiner Architektur stark an der Unity Engine. Diese nimmt auch 3 Winkel als Argumente für die Rotation, obwohl die Rotation in einer Quaternion gespeichert wird.
Ich denke ich muss mich etwas mehr über Quaternions, vor allem wie man sie einsetzt, informieren.

Der große Vorteil von Quaternionen ist, dass man zwischen zwei Quaternionen einfach interpolieren kann und man sich bei dieser Interpolation immer auf dem Großkreis von der einen Orientierung in die andere bewegt. Mit Matrizen geht das nicht einfach so. Abgesehen davon haben Quaternionen auch numerische Vorteile, die vor allem bei tiefen Transformationshierarchien interessant werden. Dafür können sie aber nur Rotationen darstellen und Rotationen allein sind in der Regel nicht ausreichend...

Gute Erklärung zur Problematik mit Eulerwinkeln: https://www.youtube.com/watch?v=zc8b2Jo7mno

Krane

Treue Seele

  • »Krane« ist der Autor dieses Themas

Beiträge: 312

Wohnort: Innsbruck, Tirol

  • Private Nachricht senden

10

17.01.2016, 13:35

Aus der Model Matrix die wie folgt definiert ist:

C-/C++-Quelltext

1
m_modelMatrix = glm::translate(m_position) * mat4_cast(m_rotation) * glm::scale(m_scale);

Werbeanzeige