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

David_pb

Community-Fossil

  • »David_pb« ist der Autor dieses Themas

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

11

04.03.2010, 16:55

Zitat von »"Nox"«

Naja gut, aber wenn wir dir helfen sollen, brauchen wir schon ein paar infos mehr. Ggf. algorithmus etc. Grundidee scheint ja zu passen.


Meine Frage war eher theoretischer Natur, ob jemand ggf einen Hinweis hat wie das Problem zu stande kommen könnte. Meine Vermutung ist, wie gesagt, dass der Gauss'sche Algorithmus zu instabil ist. Aber den Code kannst du natürlich trotzdem gern sehen, vielleicht fällt dir ja was fahrlässiges auf:

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
int Mat3::EigenSolve( Vec3 v[3], float values[3], float epsilon ) const
{
    float m00 = m[0][0];
    float m11 = m[1][1];
    float m22 = m[2][2];
    float m02 = m[0][2];
    float m20 = m[2][0];
    float m00_11 = m00 * m11;
    float m20_02 = m20 * m02;
    float m10_01 = m[1][0] * m[0][1];
    float m12_21 = m[1][2] * m[2][1];
    float m10_21 = m[1][0] * m[2][1];
    float m01_12 = m[0][1] * m[1][2];

    float a = m00 + m11 + m22;
    float b = m10_01 + m20_02 + m12_21 - m00_11 - m00 * m22 - m11 * m22;
    float c = m00_11 * m22 - m12_21 * m00 - m10_01 * m22 + m10_21 * m02 + m01_12 * m20 - m20_02 * m11;

    int result = Polynomial::RootsCubic( -1, a, b, c, values );
    int numEigenVectors = 0;
    for ( int i = 0; i < result; ++i )
    {
        Mat3 tmp = *this;
        tmp[0][0] -= values[i];
        tmp[1][1] -= values[i];
        tmp[2][2] -= values[i];

        int r = 0;
        for ( int c = 0; c < 3; ++c )
        {
            int pivot = r;
            float max = FAbs( tmp[r][c] );
            for ( int k = r+1; k < 3; ++k )
            {
                float entry = FAbs( tmp[k][c] );
                if ( entry > max ) {
                    max = entry;
                    pivot = k;
                }
            }

            if ( FAbs( max ) < epsilon )
                continue;

            if ( pivot != r ) {
                Swap( tmp[r], tmp[pivot] );
            }

            tmp[r] /= tmp[r][c];

            for ( int k = 0; k < 3; ++k )
            {
                if ( k == r )
                    continue;

                tmp[k] -= tmp[k][c] * tmp[r];
            }

            ++r;
        }

        tmp.TransposeSelf();

        for ( int j = 0; j < 3; ++j )
        {
            if ( FAbs( tmp[j][j] ) < epsilon ) 
            {
                Vec3 vec = tmp[j] * -1;
                vec[j] = 1;
                v[numEigenVectors++] = Normalize( vec );
            }
        }
    }

    return result;
}

xardias

Community-Fossil

Beiträge: 2 731

Wohnort: Santa Clara, CA

Beruf: Software Engineer

  • Private Nachricht senden

12

05.03.2010, 08:59

Ich hab mich selbst direkt mit dem Problem noch nicht beschäftigt aber mit meinem Chef viel darüber diskutieren müssen. Das Problem ist gerade beim suchen nach Eigenwerten, dass die numerische Genauigkeit ziemlich hoch sein muss, sonst landet man in einer Sackgasse. Gerade mit dem Gaussalgorithmus. Deswegen wird der soweit ich weiß so gut wie nie praktisch verwendet.

Es gibt jedoch auch andere Algorithmen um Eigenvektoren und -werte zu bestimmen, unter anderem auch sehr gute Iterative. Ich habe keine Namen parat aber "iterative eigensolver" sollte bei google was liefern.

13

05.03.2010, 09:43

Zitat von »"xardias"«

Ich habe keine Namen parat aber "iterative eigensolver" sollte bei google was liefern.

Mir würde spontan das hier einfallen:
http://de.wikipedia.org/wiki/Jacobi-Verfahren_%28Eigenwerte%29
Lieber dumm fragen, als dumm bleiben!

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

14

05.03.2010, 10:44

Mal der Neugier halber, da ich von dem ganzen Thema in der Praxis bisher noch nie etwas gehört habe:
Wo braucht man diese Werte und was macht man... praktisch... damit... zum Beispiel im Falle einer Punktwolke.

LG
Alyx

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

15

05.03.2010, 14:39

Zitat von »"Alyx"«

Mal der Neugier halber, da ich von dem ganzen Thema in der Praxis bisher noch nie etwas gehört habe:
Wo braucht man diese Werte und was macht man... praktisch... damit... zum Beispiel im Falle einer Punktwolke.

LG
Alyx


Eigenwete werden an verschiedenen Orten gebraucht. Z.b. kann man sie auch benutzen, um Vorschläge nach User Bewertungen zu machen. (google benutzt sie auch)

Ich kann dir einen interessanten Artikel dazu nachliefern, aber das WLAN ist hier im Vorlesungssaal so lahhm.. *gähhn*.. (reiche es am Abend nach, falls ichs vergesse einfach PM ;))

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

16

05.03.2010, 15:36

Zitat von »"Alyx"«

Mal der Neugier halber, da ich von dem ganzen Thema in der Praxis bisher noch nie etwas gehört habe:
Wo braucht man diese Werte und was macht man... praktisch... damit... zum Beispiel im Falle einer Punktwolke.


Die 3 Eigenvektoren geben dir die 3 Richtungen der maximalen Ausdehnung der Punktwolke. Damit kannst du z.B eine orientierte Bounding Box für die Punktwolke berechnen.

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

17

06.03.2010, 00:25

Danke dir, damit kann ich nun was anfangen :-).

LG
Alyx

David_pb

Community-Fossil

  • »David_pb« ist der Autor dieses Themas

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

18

08.03.2010, 14:02

@dot: Genau. Ich hab am Freitag noch zwei Numerische Verfahren ausprobiert (das von Jonathan bereits erwähnte Jacobi Verfahren und auf eine Householder-Reduzierte Matrix angewendete QL Verfahren). Beide sind numerisch wunderbar stabil und liefern das gewünschte Ergebnis:


(Link)

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

19

08.03.2010, 14:18

Uiuiui... genial... die perfekte Bounding Box... würdest du die Lösung hier posten? :-D

LG
Alyx

David_pb

Community-Fossil

  • »David_pb« ist der Autor dieses Themas

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

20

08.03.2010, 22:16

Zitat von »"Alyx"«

Uiuiui... genial... die perfekte Bounding Box... würdest du die Lösung hier posten? :-D

LG
Alyx


Der Algorithmus liefert nicht die perfekte Bounding Box. Aber es wird versucht eine gute Approximation zu finden. Genaueres findest du dazu im Gottschalk Paper [1]. Da werden noch zwei weitere Methoden zum Bilden der Kovarianzmatrix vorgestellt die z.B. keine Probleme bei ungleichmäßiger Verteilung von Punkten, Extrama usw machen.
Zum Thema Eigenwerte/Eigenvektoren hab ich (u.A.) folgende Quellen verwendet: [2], [3], [4].

Die Implementierung ist eigentlich relativ "straightforward":

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
void OBB::FromPoints( const Vec3* points, int num )
{
    if ( !points || num < 1 ) {
        return;
    }

    Vec3 mean = points[0];
    for ( int i = 1; i < num; ++i ) {
        mean += points[i];
    }

    float invnum = 1.0f / num;
    mean *= invnum;

    // Build covariant matrix

    Mat3 covariants;
    covariants.Zero();
    for ( int i = 0; i < num; ++i ) 
    {
        Vec3 dir = points[i] - mean;
        covariants[0][0] += dir.x * dir.x;
        covariants[0][1] += dir.x * dir.y;
        covariants[0][2] += dir.x * dir.z;
        covariants[1][1] += dir.y * dir.y;
        covariants[1][2] += dir.y * dir.z;
        covariants[2][2] += dir.z * dir.z;
    }

    covariants[1][0] = covariants[0][1];
    covariants[2][0] = covariants[0][2];
    covariants[2][1] = covariants[1][2];
    covariants *= invnum;

    covariants.EigenSolveSymmetric( &mAxes[0], mExtends.ToFloatPtr() );

    Vec3 min( 99999.0f, 99999.0f, 99999.0f );
    Vec3 max = -min;

    for ( int i = 0; i < num; ++i )
    {
        float p0 = points[i] * mAxes[0];
        float p1 = points[i] * mAxes[1];
        float p2 = points[i] * mAxes[2];

        if ( p0 > max.x ) max.x = p0;
        if ( p0 < min.x ) min.x = p0;
        if ( p1 > max.y ) max.y = p1;
        if ( p1 < min.y ) min.y = p1;
        if ( p2 > max.z ) max.z = p2;
        if ( p2 < min.z ) min.z = p2;
    }

    mCenter = ( min + max ) * 0.5f;
    mExtends = max - mCenter;
    mCenter *= mAxes;
}


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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
void Mat3::EigenSolveSymmetric( Vec3 v[3], float values[3], float epsilon ) const
{
    static const int maxIter = 64;

    float m00 = m[0][0];
    float m01 = m[0][1];
    float m02 = m[0][2];
    float m11 = m[1][1];
    float m12 = m[1][2];
    float m22 = m[2][2];

    float theta, theta2, theta2Plus1, c, s, m_ik;

    v[0] = Vec3(1, 0, 0),
        v[1] = Vec3(0, 1, 0),
        v[2] = Vec3(0, 0, 1);

    for ( int i = 0; i < maxIter; ++i )
    {
        if ( FAbs( m01 ) < epsilon && FAbs( m02 ) < epsilon && FAbs( m12 ) < epsilon ) {
            break;
        }

        // (i = 0, j = 1, k = 2)

        if ( m01 != 0 )
        {
            theta = ( m11 - m00 ) * 0.5f / m01; // tan(2t)

            theta2 = theta * theta;
            theta2Plus1 = theta2 + 1.0f;
            if ( theta2Plus1 != theta2 ) 
            {
                theta = ( theta < 0.0f ) 
                    ? -( Sqrt( theta2Plus1 ) - FAbs( theta ) )
                    : +( Sqrt( theta2Plus1 ) - FAbs( theta ) );
            }
            else {
                theta = .5f / theta;
            }

            c = InvSqrt( 1.0f + theta * theta );
            s = theta * c;

            m_ik = c * m02 - s * m12;
            m12 = s * m02 + c * m12;
            m02 = m_ik;
            m00 -= theta * m01;
            m11 += theta * m01;
            m01 = 0;

            for ( int j = 0; j < 3; ++j )
            {
                float tmp = c * v[0][j] - s * v[1][j];
                v[1][j]   = s * v[0][j] + c * v[1][j];
                v[0][j]   = tmp;
            }
        }

        // (i = 0, j = 2, k = 1)

        if ( m02 != 0 )
        {
            theta = ( m22 - m00 ) * 0.5f / m02;
            theta2 = theta * theta;
            theta2Plus1 = theta2 + 1.0f;
            if ( theta2Plus1 != theta2 ) 
            {
                theta = ( theta < 0.0f ) 
                    ? -( Sqrt( theta2Plus1 ) - FAbs( theta ) )
                    : +( Sqrt( theta2Plus1 ) - FAbs( theta ) );
            }
            else {
                theta = .5f / theta;
            }

            c = InvSqrt( 1.0f + theta * theta );
            s = theta * c;

            m_ik = c * m01 - s * m12;
            m12 = s * m01 + c * m12;
            m01 = m_ik;
            m00 -= theta * m02;
            m22 += theta * m02;
            m02 = 0;

            for ( int j = 0; j < 3; ++j )
            {
                float tmp = c * v[0][j] - s * v[2][j];
                v[2][j]   = s * v[0][j] + c * v[2][j];
                v[0][j]   = tmp;
            }
        }

        // (i = 1, j = 2, k = 0)

        if ( m12 != 0 )
        {
            theta = ( m22 - m11 ) * 0.5f / m12;
            theta2 = theta * theta;
            theta2Plus1 = theta2 + 1.0f;
            if ( theta2Plus1 != theta2 ) 
            {
                theta = ( theta < 0.0f ) 
                    ? -( Sqrt( theta2Plus1 ) - FAbs( theta ) )
                    : +( Sqrt( theta2Plus1 ) - FAbs( theta ) );
            }
            else {
                theta = .5f / theta;
            }

            c = InvSqrt( 1.0f + theta * theta );
            s = theta * c;

            m_ik = c * m01 - s * m02;
            m02 = s * m01 + c * m02;
            m01 = m_ik;
            m11 -= theta * m12;
            m22 += theta * m12;
            m12 = 0;

            for ( int j = 0; j < 3; ++j )
            {
                float tmp = c * v[1][j] - s * v[2][j];
                v[2][j]   = s * v[1][j] + c * v[2][j];
                v[1][j]   = tmp;
            }
        }
    }

    values[0] = m00;
    values[1] = m11;
    values[2] = m22;
}


[1] Collision Queries using Oriented Bounding Boxes
[2] Jacobi Eigenvalue Algorithm
[3] The Householder-QR/QL Algorithm
[4] Householder Reduction of linear equations

Werbeanzeige