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

Kaktus

Frischling

  • »Kaktus« ist der Autor dieses Themas

Beiträge: 19

Beruf: Schüler

  • Private Nachricht senden

1

01.09.2012, 10:49

Picking geht daneben

Hallo erstmal, tolles Forum ;) !

Ich entwickle momentan einen Terrain-Editor, bei dem ich per Mausklick das Terrain an einer Stelle erhöhen bzw. absenken will.

Mein Ansatz ist der folgende:
Ich "schieße" einen Strahl von der Kamera aus ab.
Die Richtung ist die Blickrichtung der Kamera rotiert je nach Abstand des Mauszeigers vom Mittelpunkt des Bildschirms.
(z.B. Mausklick ganz links am Rand wäre rotiert um -90° um die Y-Achse).
(Hoffentlich habe ich das nicht zu kompliziert ausgedrückt. :S )

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Maus-Koordinaten auf [-1.0f;1.0f] skalieren.
mousePos.X = (2.0f * mousePos.X) / 800.0f - 1.0f;
mousePos.Y = (2.0f * mousePos.Y) / 600.0f - 1.0f;

// Koordinaten in Grad der Rotation umrechnen.
mousePos.X *= fov;
mousePos.Y *= fov / (800.0f / 600.0f);

// Rotation mit Kamerarotation kombinieren.
Vector3 rot(Camera->GetRotation());
Matrix mRot(RotationXYZ(rot.X + mousePos.Y, rot.Y + mousePos.X, rot.Z));

// Strahl erstellen (Richtung und Ursprung).
Vector3 dir = mRot.TransformNormal(Vector3(0.0f, 0.0f, 1.0f));
Vector3 orig = Camera->GetPos();


Wenn ich testweise mousePos auf (0.0f, 0.0f) setze (also Mitte des Bildschirms) funktioniert es auch (erstes angehängtes Bild), aber ansonsten landet der Strahl leider immer daneben (zwar nicht vollkommen aber schon ein ziemliches Stück).
Im Anhang ist ein Bild davon (grün ist die Stelle wo eigentlich getroffen werden sollte, und rot ist der berechnete Strahl).

Ich bin mittlerweile echt verzweifelt, ich sitze schon über Tage an dem Problem :(

Vielen Dank im Voraus
»Kaktus« hat folgende Bilder angehängt:
  • TerrainEditorPickingRayRight.png
  • TerrainEditorPickingRayWrong.png

2

01.09.2012, 11:05

Nun, gebräuchlicher ist es eigentlich, sich durch Rückprojektion die Bildschirmkoordinaten als Punkte auf der Near- und Farclippingplane zu holen. In OpenGL gibt es dafür die Funktion gluUnproject.

So hab ich das mal gemacht (in openGL):

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
void CalcPicRay(const float XPos, float YPos, float Startpoint[3], float Direction[3])
{
    GLdouble ModelView[16];
    GLdouble Projection[16];
    GLint Viewport[4];

    //die Werte hohlen:
    glGetDoublev(GL_MODELVIEW_MATRIX, ModelView);
    glGetDoublev(GL_PROJECTION_MATRIX, Projection);
    glGetIntegerv(GL_VIEWPORT, Viewport);

    //Ypos invertieren, wegen dem anderen koordinatensystems von ogl
    YPos*=-1;
    YPos+=Viewport[3];



    GLdouble Point[3];

    gluUnProject(XPos, YPos, -1,//Near Clipping Plane
                ModelView, Projection, Viewport,
                &Point[0], &Point[1], &Point[2]);

    Startpoint[0]=static_cast<float>(Point[0]);
    Startpoint[1]=static_cast<float>(Point[1]);
    Startpoint[2]=static_cast<float>(Point[2]);



    gluUnProject(XPos, YPos, 1,//Far Clipping Plane
                ModelView, Projection, Viewport,
                &Point[0], &Point[1], &Point[2]);

    //Direction ist "absolut" und wir müssen ihn jetzt in eine richtung umrechnen:
    Direction[0]=static_cast<float>(Point[0])-Startpoint[0];
    Direction[1]=static_cast<float>(Point[1])-Startpoint[1];
    Direction[2]=static_cast<float>(Point[2])-Startpoint[2];


    //Vector normalisieren:
    float Length=sqrt(
                         (Direction[0]*Direction[0])
                        +(Direction[1]*Direction[1])
                        +(Direction[2]*Direction[2]));
    Direction[0]/=Length;
    Direction[1]/=Length;
    Direction[2]/=Length;
    //fertig 8-)
}


Das ganz links -90 Grad sein soll ist auch unwahrscheinlich, dann hättest du ein Blickfeld von 180 Grad. Eigentlich hat man eher so um die 75-90.
Lieber dumm fragen, als dumm bleiben!

Kaktus

Frischling

  • »Kaktus« ist der Autor dieses Themas

Beiträge: 19

Beruf: Schüler

  • Private Nachricht senden

3

01.09.2012, 11:42

Danke für die schnelle Antwort ;)
//Ypos invertieren, wegen dem anderen koordinatensystems von ogl

YPos*=-1;
YPos+=Viewport[3];

Bei D3D gibt es D3DXVec3Unproject(), was scheinbar dasselbe wie gluUnproject() ist. Kann obiger Code bei D3D wegfallen?
Außerdem ist die Near-Plane bei D3D doch bei 0 und die Far-Plane bei 1, oder (und nicht -1 und 1)?


Das ganz links -90 Grad sein soll ist auch unwahrscheinlich, dann hättest du ein Blickfeld von 180 Grad. Eigentlich hat man eher so um die 75-90.

Stimmt, dann ist links -45°...

EDIT:
Habe den Code von Jonathan_Klein abgewandelt mit D3DXVec3Unproject() ausprobiert, aber es funktioniert nicht:
z.B. für die Mauskoordinaten (627|309) kommt für z=0 (near-plane?) (-735.90033, 543.55322, 1.0070593 ) und für z=1 (far-plane) (-738.56012, 545.80261, 1.0070752) heraus, aber die beiden Punkte können doch nicht so dicht beieinander liegen, oder? ?(

mfg Kaktus

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Kaktus« (01.09.2012, 12:54)


Werbeanzeige