Sprawdzenie czy gracz kliknął na obiekt.

0

Witam,
próbuję teraz zrobić grę w OpenGL, w której trzeba będzie znajdywać przedmioty porozrzucane w świecie 3d :) Poruszanie się mam, wyświetlanie, wszystko jest. Niestety za bardzo nie wiem jak odczytać, czy gracz kliknął myszką na przedmiocie który miał znaleźć. Czy ktoś zna jakiś sposób żeby odgadnąć czy gracz kliknął na przedmiot?
Z góry dziękuję za odpowiedzi!

0

Pobierasz informacje o tym gdzie kliknięto a potem sprawdzasz czy jest tam obiekt ;]

0

Hmmm. Właśnie w tym jest problem :/ Nie wiem jak to zrobić. W grze 2d nie było by najmniejszego problemu, natomiast w grze FPS nie wiem jak to zrobić bo dochodzi jeszcze oś Z.

0

Hmm, w 2D to wiadomo, ale w 3D ja bym zrobił promieniem. I sprawdzić czy przecina się z siatką obiektu. W chwili kliknięcia go wypuścić.

Edit:
Ehh pomyślałem trochę o czym innym, to się raczej nie sprawdzi. Hm..

1

Kodu Ci nie podam, bo z opengl bawiłem się parę lat temu, ale osobiście widzę 2 rozwiązania.

  1. Bierzesz rzut sceny na płaszczyznę ekranu i sprawdzasz kolor w współrzędnych kliknięcia - dużą wadą jest to, że każdy obiekt musi mieć inny kolor co się wiąże ze specjalnym wyrenderowaniem klatki na potrzeby testu

  2. Liczysz równanie prostej przechodzącą przez punkt położenia kamery i punkt kliknięcia(tu za z można przyjąć współrzędną Z bliższej płaszczyznę obcinania), sprawdzasz punkty przecięcia tej prostej z obiektami na scenie. Kliknięty obiekt to ten, którego miejsce przecięcia z prostą jest najbliżej płaszczyzny ekranu.

Mam nadzieję, że nie napisałem bzdur ;)

1

Ja takie coś realizowałem przez GL_SELECT: http://glprogramming.com/red/chapter13.html z tym że ograniczałem obszar renderowania do tego naokoło klikniętego miejsca.

1

przydatne mogą być funkcje gluProject(), gluUnProject()

0
byku_guzio napisał(a)

Kodu Ci nie podam, bo z opengl bawiłem się parę lat temu, ale osobiście widzę 2 rozwiązania.

  1. Bierzesz rzut sceny na płaszczyznę ekranu i sprawdzasz kolor w współrzędnych kliknięcia - dużą wadą jest to, że każdy obiekt musi mieć inny kolor co się wiąże ze specjalnym wyrenderowaniem klatki na potrzeby testu

  2. Liczysz równanie prostej przechodzącą przez punkt położenia kamery i punkt kliknięcia(tu za z można przyjąć współrzędną Z bliższej płaszczyznę obcinania), sprawdzasz punkty przecięcia tej prostej z obiektami na scenie. Kliknięty obiekt to ten, którego miejsce przecięcia z prostą jest najbliżej płaszczyzny ekranu.

Mam nadzieję, że nie napisałem bzdur ;)

punkt 1 dało by się zrobić, tylko zajęło by mi to dużo czasu. Obiektów będzie duuużo na jednej mapie i prawdopodobnie będzie problem z pomieszczeniem ich w kolorach RGB ^^
punkt 2 niestety jak dla mnie niewykonalny. Nie wiem jak zrobić.
Jeśli chodzi o GL_SELECT to słyszałem że jest to bardzo nieefektowne i klatkożerne. Być może się mylę.
Co do gluProject to przeraziło mnie to: http://www.opengl.org/wiki/GluProject_and_gluUnProject_code . Dla pewności: gluProject to jedna funkcja pobierająca współrzędne obiektu?

0

punkt 1 dało by się zrobić, tylko zajęło by mi to dużo czasu. Obiektów będzie duuużo na jednej mapie i prawdopodobnie będzie problem z pomieszczeniem ich w kolorach RGB ^^

Ale obiekty nieaktywne lub w danym momencie nieinteresujące mogą mieć jeden kolor. Poza tym możesz użyć 32 bitów, a nie 24. Chociaż wiadomo, że im mniej bitów tym szybciej będzie działać renderowanie.

0

pkt 2 jest jak najbardziej wykonalny
sam koniec artykułu: http://warsztat.gd/articles.php?x=view&id=279

0

Poszukaj hasełka: "OpenGL + picking"

0

możesz jeszcze użyć jakiejś biblioteki w której masz możliwość sprawdzania kolizji, następnie wystrzelić niewidzialny pocisk z miejsca położenia myszy prostopadle do ekranu wgłąb i sprawdzić z czym ten pocisk się zderzył. Aczkolwiek, jeśli znasz położenia wszystkich obiektów to możesz po prostu sprawdzić punkty przecięcia prostej z kulą.

Jak wyznaczyć prostą?
Pobierasz macierz położenia kamery. Wydaje mi się, że jest to macierz jednorodna, nie jestem tylko pewien czy dostaniesz macierz opisującą współrzędne lewego górnego rogu ekranu czy środka ekranu względem globalnego układu współrzędnych.

Macierz jednorodna jest zbudowana tak:
[wx,wy,wz, T; p,s]

i teraz tak:
wx,wy,wz są to wektory 3x1 opisujące kierunki osi układu współrzędnych kamery względem globalnego układu współrzędnych (wersory, ich długości powinny być równe 1):

    gx
w = gy
    gz

T jest to wektor 3x1 opisujący po prostu położenie układu współrzędnych we współrzędnych globalnych [x;y;z]

p jest to wektor 1x3 związany z perspektywą (nawet nie wiem do końca jak działa), niezbyt Cię powinna interesować, s jest to skalar (1x1) opisujący skalę (prawdopodobnie będzie równy 1)

z macierzy rotacji [wx,wy,wz] możesz wyciągnąć kierunek w który się patrzysz patrząc na monitor i tym samym wystrzelić w odpowiednią stronę niewidzialny pocisk.

0
oldman napisał(a)

pkt 2 jest jak najbardziej wykonalny
sam koniec artykułu: http://warsztat.gd/articles.php?x=view&id=279

Przykład tam zamieszczony odnosi się bardziej do DirectX'a, a z nim niestety nie miałem styczności. Mimo wszystko dziękuję za wskazanie mi tego poradnika.
krwq, dzięki z radę, postaram się coś zrobić jak ty mówisz :)

0
St4rKiller070 napisał(a)
oldman napisał(a)

pkt 2 jest jak najbardziej wykonalny
sam koniec artykułu: http://warsztat.gd/articles.php?x=view&id=279

Przykład tam zamieszczony odnosi się bardziej do DirectX'a, a z nim niestety nie miałem styczności. Mimo wszystko dziękuję za wskazanie mi tego poradnika.
krwq, dzięki z radę, postaram się coś zrobić jak ty mówisz :)

Nieprawda artykuł dotyczy

  1. działania kamery - czyli jak przejść z macierzy widoku i projekcji, które są także w opengl jak mniemam, chociaż któraś jest tam pod inną nazwą, mylę się? do obiektu jakim jest kamera - a artykuł obejmuje po prostu potrzebne algorytmy na macierzach i to wszystko, a to, że są tam wywołania D3DX*(przykład implementacji na dx) to po prostu funkcje do operacji na macierzach, które z samą funkcjonalnością d3d9 nie mają nic wspólnego.
    Potem masz efekt cząsteczkowy, ale tylko w kontekście współpracy z kamerą, czyli znowu chodzi o same operacje na macierzach - które nie są zależne od api (jedynie po prostu przykład masz w dx).
    Następnie liczenie kolizji brył otaczających (bounding box) z bryłą kamery - znowu wszystko to algorytmy geometryczne...
    I ostatnia rzecz czyli to co cię interesuje - ray casting, czyli test kolizji bryły otaczającej z "promieniem wysokości" "bryły kamery" - znów algorytm na test geometryczny
    ...i teraz gdzie tu direct3d?

Jeszcze dla ułatwienia typy które tam widzisz:
D3DXVECTOR to nic innego jak struct { float x, y, z; }; + parę metod i konstruktory dla ułatwienia. D3DXMATRIX to tak samo w uproszczeniu struct { float [4][4]; }; + metody i konstruktory, oraz widzisz tam parę funkcji D3DXMatrix*, które robią coś z macierzą - np. D3DXMatrixInverse to chyba wiadomo :>
Pisząc własną grę w końcu przyjdzie Ci podłączyć jakąś

  1. biblioteczkę do operacji matematycznych na macierzach, wektorach, itd. - np. D3DX - która jest oddzielnym komponentem od Direct3D
  2. napisać własną libkę do tego - dobra rzecz jeśli zależy Ci na nauce tego
    Nawet nic nie stoi na przeszkodzi (no chyba, że przenośność), aby dołączyć do projektu d3dx9.h i podlinkować d3dx9.lib i sobie tego używać z opengl-em :>
0

Jeżeli jeszcze aktualny ten temat to przypadkiem znalazłem coś takiego (dokumentacja XNA):

Demonstrates how to check whether the mouse is positioned over a 3D object by creating a ray starting at the camera's near clipping plane and ending at its far clipping plane. Note
This example applies only to Windows development. The Mouse and MouseState objects are not supported on Xbox 360.

The Complete Sample
The code in this topic shows you the technique. You can download a complete code sample for this topic, including full source code and any additional supporting files required by the sample.

Download Sample.

Detecting Whether a User Clicked a 3D Object
To check whether the mouse is positioned over a 3D object
Get the current state of the mouse by using GetState.

C#

MouseState mouseState = Mouse.GetState();

Get the current screen coordinates of the mouse from X and Y.

C#

int mouseX = mouseState.X;
int mouseY = mouseState.Y;

Using Viewport.Unproject, determine points in world space on the near and far clipping planes. For the point on the near plane, pass a source vector with x and y set to the mouse position, and z set to 0.

For the point on the far plane, pass a source vector with x and y set to the mouse position, and z set to 1.

Create a translation matrix for a point that is the origin, (0,0,0).

For both points, pass Unproject the current projection matrix, the view matrix.

C#

Vector3 nearsource = new Vector3((float)mouseX, (float)mouseY, 0f);
Vector3 farsource = new Vector3((float)mouseX, (float)mouseY, 1f);

Matrix world = Matrix.CreateTranslation(0, 0, 0);

Vector3 nearPoint = GraphicsDevice.Viewport.Unproject(nearsource,
    proj, view, world);

Vector3 farPoint = GraphicsDevice.Viewport.Unproject(farsource,
    proj, view, world);

Create a Ray whose origin is at the near point and whose direction points to the far point.

C#

// Create a ray from the near clip plane to the far clip plane.
Vector3 direction = farPoint - nearPoint;
direction.Normalize();
Ray pickRay = new Ray(nearPoint, direction);

Loop throught each object in the scene using the Intersects method to check whether the Ray intersects each object.

If the Ray intersects an object, check whether it is the closest object intersected so far. If it is, store the object and the distance at which it was intersected, replacing any previously stored object.

When you completely loop through the objects, the last object stored will be the closest object underneath the area the user clicked.

Może ci się przyda. Co prawda C#, ale nie chodzi o kod a sposób.

1 użytkowników online, w tym zalogowanych: 0, gości: 1