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

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

1

16.11.2013, 14:45

Kamera Position aus View- oder Projectionmatrix extrahieren

Hi,

ich hab mal wieder ein kleines mathematisches Problem.
Für mein raytracing (picking) versuche ich die Kameraposition in Weltkoordinaten aus der View- und/oder Projectionmatrix auszulesen. Das muss ich so machen da ich z.B. die ganze Szene mit der Maus drehen möchte und dies dann eben direkt über die Viewmatrix mache.

Ich hab mir mal die Viewmatrix ausgeben lassen (auch invertiert), allerdings ergibt sich jetzt daraus nicht die Kameraposition in Weltkoordinaten, außer die, die ich sowieso kenne. Um mal deutlich zu machen wie ich rechne:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
void Camera::calculateViewMatrix(){
    bb::vec3 rot = (m_lookAt-m_position).cross(m_up);
    rot.normalize();

    m_viewMatrix.setIdentity();
    m_viewMatrix.lookAt(m_position, m_lookAt, m_up);
    m_viewMatrix.rotate(m_rotation.y, rot); // Rotation über die "Rechtsachse"
    m_viewMatrix.rotate(m_rotation.x, 0, 0, 1);
}


Ich kenne also die Kameraposition zu Beginn+Rotation. Durch die Rotation ist nun mal die Position anders. Hier kann man mit der Maus die "Höhe" der Kamera ändern. Initial wird dazu 50° genommen.
Mein Picking funktioniert wenn ich die "echte" Kameraposition eingebe und nicht mit der Maus rotiere.

Vielleicht gibt es auch eine andere Möglichkeit das Picking mit rotierter Kamera durchzuführen? Übrigens können Objekte ja auch z.B. um das Zentrum rotiert sein. Wie gehe ich am besten vor?

Nur falls jemand mal hier draufschauen möchte:

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
Camera::ray Camera::getRay(float x, float y){ // Berechnung des rays
    float w = float(m_viewport[2]-m_viewport[0]);
    float h = float(m_viewport[3]-m_viewport[1]);

    vec3 view = (m_lookAt-m_position).normalize();
    vec3 u = vec3Cross(view, m_up).normalize();
    vec3 v = vec3Cross(u, view).normalize();

    float vLength = tan(m_fov*PI/180.0f/2.0f)*m_zNear;

    v *= vLength;
    u *= vLength*(w/h);

    x -= w/2.0f;
    x /= w/2.0f;
    y -= h/2.0f;
    y /= h/2.0f;

    ray r;
    r.position = m_position+view*m_zNear+u*x+v*y;
    r.direction = (r.position-m_position).normalize();

    return r;
}

a = r.direction.dot(r.direction); // picking in einer system klasse, hier nur der relevante Ausschnitt
b = 2*r.direction.dot(r.position);
c = r.position.dot(r.position)-object3d->m_radius*object3d->m_radius;
disc = b*b-4*a*c; // discriminant

if(disc > 0.0f){
    dist = sqrt(disc);

    if(b < 0.0f){
        q = (-b-dist)/2.0f;
    }
    else{
        q = (-b+dist)/2.0f;
    }

    t0 = q/a;
    t1 = c/q;

    if(t0 > t1){
        tmp = t0;
        t0 = t1;
        t1 = tmp;
    }

    if(t1 > 0.0f){ // erfolgreich
        std::cout<<r.position.x<<"|"<<r.position.y<<"|"<<r.position.z<<"|"<<r.direction.x<<"|"<<r.direction.y<<"|"<<r.direction.z<<std::endl;
    }

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

16.11.2013, 15:19

Einfachste Variante: Rechne deine Mausposition in Normalized Device Coordinates um (Bildfläche geht in allen Richtungen von -1 bis 1), bastel dir daraus einen Punkt auf der near Plane §\begin{pmatrix}x & y & -1 & 1\end{pmatrix}§ und einen Punkt auf der far Plane §\begin{pmatrix}x & y & 1 & 1\end{pmatrix}§ (ich ging mal von OpenGL aus, in Direct3D wär die near Plane bei z = 0) und schick diese beiden Punkte durch die Inverse der View Projection Matrix. Ergebnis beide Male durch w teilen und du hast die beiden Punkte im World Space.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (16.11.2013, 15:24)


DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

3

17.11.2013, 13:50

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Camera::ray Camera::getRay(float x, float y){
    ray r;

    calculateViewMatrix();
    calculateProjectionMatrix();

    mat4 pv = (m_projectionMatrix*m_viewMatrix).inverse();
    float w = x/(float(m_viewport[2]-m_viewport[0])/2.0f)-1.0f;
    float h = -(y/(float(m_viewport[3]-m_viewport[1])/2.0f)-1.0f);

    vec4 n = pv*vec4(w, h, -1.0f, 1.0f);
    n /= n.w;
    vec4 f = pv*vec4(w, h, 1.0f, 1.0f);
    f /= f.w;

    r.position = vec3(n);
    r.direction = vec3(f).normalize();

    return r;
}


So device Koordinaten stimmen schon mal, links -1.0 rechts 1.0 oben 1.0 unten -1.0.

Dann meintest du das so in der vierten Zeile? Projektionsmatrix*Viewmatrix?

Dann die beiden vec4 Punkte aufgesetzt * der inversen der pv und / w teilen?

Mögliche Ausgabe:

Quellcode

1
-10.8186|-10.5365|0.289706|-0.71762|-0.696084|0.0221132


Vorne erster Punkt, hinten Richtung...
Vorne x und y kann schon mal sein, wenn ich rauszoome und die Kamera zu Anfang bei -5, -5 steht. Allerdings ändert sich das auch nicht wenn ich rotiere... Dann z vorne könnte auch sein.
Hinten die Richtung ändert sich auch kaum.

Also könnte schon passen, aber ändert sich nicht wenn ich rotiere, so wie vorher.
Das die Matrizen ja richtig berechne sehe ich an der Ausgabe.

Vielleicht liegt es an der Matrixmultiplikation?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
vec4 mat4::operator*(const vec4 &v){
    vec4 r = vec3();

    r.x = values[0]*v.x+values[4]*v.y+values[8]*v.z+v.w*values[12];
    r.y = values[1]*v.x+values[5]*v.y+values[9]*v.z+v.w*values[13];
    r.z = values[2]*v.x+values[6]*v.y+values[10]*v.z+v.w*values[14];
    r.w = values[3]*v.x+values[7]*v.y+values[11]*v.z+v.w*values[15];

    return r;
}


Ich kann mir zwar die Idee hinter dem ganzen Verfahren erklären, aber naja, die lineare Abhängigkeit hier ist mir nicht so ganz klar.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

17.11.2013, 13:57

f ist nicht die Richtung deines Strahls, sondern ein zweiter Punkt. Wenn du die Richtung haben willst, musst du f von n subtrahieren... ;)

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

5

17.11.2013, 18:42

Achja :P Ändert aber nix daran das auch der erste nicht korrekt ist. Bleibt z.B. bei -5.xyz|-5.xyz wenn ich ihn am Anfang auf -5|-5 setze...

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

6

18.11.2013, 13:44

Ah Fehler gefunden, hatte die Viewmatrix an zwei Stellen unterschiedlich berechnet (die bewegbare Kamera leitet von meiner normalen ab) und die Ray Funktion in der Basisklasse, in der dann die Berechnung der Viewmatrix ohne Rotation aufgerufen wird.
Funktioniert soweit, aber die Ray <-> Sphere Kollision passt offenbar noch nicht... aber da guck ich jetzt erstmal selber.

Danke Großmeister dot :) (Zitat von David)

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

18.11.2013, 16:59

:D

Werbeanzeige