2009-07-02 12 views
5

Problem Screen-to-świata na iPhon e
Konwersja współrzędnych ekranu na świat w OpenGLES to łatwe zadanie?

Mam model 3D (kostka) Przedstawiane w EAGLView i chcę, aby być w stanie wykryć, kiedy jestem dotykając środka danej twarzy (Z dowolnego kąta orientacji) sześcianu. Brzmi całkiem proste, ale nie jest ...

Problem:
Jak mogę dokładnie dotyczą ekranu współrzędnych (punkt dotknięcia) to światowej współrzędnych (a położenie w przestrzeni 3D OpenGL)? Oczywiście, przekonwertowanie danego punktu na "procent" ekranu/osi światowej może wydawać się logiczną poprawką, ale pojawią się problemy, gdy potrzebuję powiększyć lub obrócić przestrzeń 3D. Uwaga: obracanie powiększonej i pomniejszonej powierzchni 3D zmieni relację współrzędnych ekranu 2D z współrzędnymi światowymi 3D ... Ponadto musisz uwzględnić "odległość" między punktem widzenia a obiektami w przestrzeni 3D . Na początku może to wydawać się "łatwym zadaniem", ale zmienia się, gdy faktycznie badasz wymagania. I nie znalazłem żadnych przykładów ludzi robiących to na iPhonie. Jak to zwykle się dzieje?

za „proste” zadanie ?:
Jasne, można by podjąć zadanie pisania API działać jako pośrednik między ekranem a światem, ale zadanie stworzenie takich ram wymagałoby poważne projekt i prawdopodobnie zajmie to "czasu" - NIE, co może być jednoosobowe w ciągu 4 godzin ... I 4 godziny to mój ostateczny termin.

Pytanie:

  • Jakie są jednymi z najprostszych sposobów na wiem czy dotknął określone lokalizacje w przestrzeni 3D w iPhone OpenGL ES świecie?
+0

AFAIK nie jest to trywialne Problem rozwiązany, chyba że masz go przed lub o ile nie jest już wsparcie wbudowany w danym środowisku (co nie wydaje się być przypadek). Wiem, że wygląda to łatwiej niż jest, mieliśmy tę samą dyskusję z moimi kolegami. – zoul

Odpowiedz

1

Dwa rozwiązania przedstawiają się. Obaj powinni osiągnąć cel końcowy, choć w inny sposób: zamiast odpowiadać "jaka jest współrzędna światowa pod myszą?", Odpowiadają na pytanie "jaki obiekt jest renderowany pod myszą?".

Jedną z nich jest narysowanie uproszczonej wersji swojego modelu do bufora poza ekranem, dzięki czemu środek każdej twarzy będzie miał inny kolor (i dostosuje oświetlenie, aby kolor był zachowywany w identyczny sposób). Następnie można wykryć te kolory w buforze (np. Pixmap) i odwzorować na nie lokalizacje myszy.

Drugim jest użycie pobierania OpenGL. Jest przyzwoicie wyglądający samouczek: here.Podstawową ideą jest umieszczenie OpenGL w trybie wyboru, ograniczenie widoku do małego (prawdopodobnie 3x3 lub 5x5) okna wokół interesującego punktu, a następnie renderowanie sceny (lub jej uproszczonej wersji) za pomocą "nazw" OpenGL (integer) identyfikatory) w celu zidentyfikowania składników tworzących każdą twarz. Pod koniec tego procesu OpenGL może podać listę nazw, które zostały wyrenderowane w rzutni wyboru. Odwzorowanie tych identyfikatorów z powrotem na oryginalne obiekty pozwoli ci określić, który obiekt znajduje się pod kursorem myszy.

+1

Tylko uwaga dla iPhone'a: ​​brak otwierania OpenGL w Open GL ES 1.1, więc masz pecha. – jv42

0

Google dla opengl screen to world (na przykład istnieje wątek, w którym ktoś chce zrobić dokładnie to, czego szukasz na GameDev.net). Istnieje funkcja gluUnProject, która robi dokładnie to, ale nie jest dostępna na iPhonie, więc musisz ją przenieść (zobacz this source z projektu Mesa). A może jest już jakieś publicznie dostępne źródło?

+0

Czy kojarzy elementy z obszarami w modelach 3D w EAGL? Wydaje się, że w tym temacie jest niewiele informacji. Ten link, który podałeś, nie dostarczył mi żadnych wskazówek, by osiągnąć ten cel w Xcode. Dziękuję za odpowiedź. – RexOnRoids

+0

myślę, że tak naprawdę jest to skomplikowane i że związek odpowiada na to pytanie, ale poczekajmy - może ktoś wymyślić lepszej odpowiedzi. – zoul

+0

EAGLView i OpenGL to tylko narzędzia do rysowania modeli. Nie zajmują się wykrywaniem trafień ani czymś podobnym. Musisz to zrobić. –

2

Wyobraź sobie linię, która rozciąga się od okienka użytkownika
poprzez punkt dotykowy ekranu do przestrzeni modelu 3D.

Jeśli linia ta przecina którąkolwiek z powierzchni sześcianu, to użytkownik dotknął kostki.

+0

To działałoby, gdyby był prostym sześcianem z 8 wierzchołkami. Kopalnia jest rzeczywiście kostka 3D-500 + Lego z wierzchołków (z butli na górze), a dane są automatycznie ładowane z pliku eksportu blendera - to znaczy: nie mam pojęcia, który z ponad 500 wierzchołków, aby śledzić jak moje 8 narożników i dlatego nie mogę śledzić moich twarzy. – RexOnRoids

+0

Dlaczego nie obliczysz/nie przyjmiesz prostokąta ograniczającego dla twojego klocka lego, a następnie sprawdź to dla skrzyżowania. No dalej, wiesz, że chcesz. –

+0

Jak bym „Sprawdź” obwiednię na skrzyżowaniu w odniesieniu do dotyku, który jest punktem 2D na ekranie? – RexOnRoids

3

Potrzebne są macierze rzutowania i wzorcowania OpenGL. Pomnóż je, aby uzyskać matrycę projekcji odwzorowania modelu. Odwróć tę macierz, aby uzyskać macierz przekształcającą współrzędne spacji w współrzędne globalne. Zmień swój punkt dotyku tak, aby odpowiadał współrzędnym klipu: środek ekranu powinien wynosić zero, a krawędzie powinny wynosić odpowiednio + 1/-1 dla X i Y.

skonstruuj dwa punkty, jeden na (0,0,0) i jeden na (touch_x, touch_y, -1) i przekształć oba za pomocą macierzy odwrotnej projekcji modelu.

Wykonaj odwrotność podziału perspektywy.

Powinieneś otrzymać dwa punkty opisujące linię ze środka kamery na "daleki dystans" (farplane).

Zbieramy na podstawie uproszczonych ramek ograniczających modeli. Powinieneś być w stanie znaleźć wiele algorytmów przecięcia promieni/skrzyń w Internecie.

Innym rozwiązaniem jest pomalowanie każdego z modeli w nieco innym kolorze w bufor poza ekranem i odczytanie koloru w punkcie styku stamtąd, informując o tym, który z nich został dotknięty.

Oto źródło kursorem pisałem dla małego projektu z wykorzystaniem fizyki pocisku:

float x=((float)mpos.x/screensize.x)*2.0f -1.0f; 
    float y=((float)mpos.y/screensize.y)*-2.0f +1.0f; 
    p2=renderer->camera.unProject(vec4(x,y,1.0f,1)); 
    p2/=p2.w; 
    vec4 pos=activecam.GetView().col_t; 
    p1=pos+(((vec3)p2 - (vec3)pos)/2048.0f * 0.1f); 
    p1.w=1.0f; 

    btCollisionWorld::ClosestRayResultCallback rayCallback(btVector3(p1.x,p1.y,p1.z),btVector3(p2.x,p2.y,p2.z)); 
    game.dynamicsWorld->rayTest(btVector3(p1.x,p1.y,p1.z),btVector3(p2.x,p2.y,p2.z), rayCallback); 
    if (rayCallback.hasHit()) 
    { 
     btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject); 
     if(body==game.worldBody) 
     { 
      renderer->setHighlight(0); 
     } 
     else if (body) 
     { 
      Entity* ent=(Entity*)body->getUserPointer(); 

      if(ent) 
      { 
       renderer->setHighlight(dynamic_cast<ModelEntity*>(ent)); 
       //cerr<<"hit "; 
       //cerr<<ent->getName()<<endl; 
      } 
     } 
    } 
7

Teraz można znaleźć gluUnProject w http://code.google.com/p/iphone-glu/. Nie mam związku z projektem iphone-glu i jeszcze go nie wypróbowałem, chciałem tylko udostępnić link.

Jak skorzystasz z takiej funkcji? This PDF wspomina, że:

Biblioteka Utility rutyna gluUnProject() wykonuje to odwrócenie transformacji. Biorąc pod uwagę trójwymiarowe współrzędne okna dla lokalizacji i wszystkie transformacje, które na nie wpłynęły, gluUnProject() zwraca współrzędne światowe z miejsca, z którego pochodzi.

int gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz, 
const GLdouble modelMatrix[16], const GLdouble projMatrix[16], 
const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz); 

mapie określonych współrzędnych okienne (Winx, winny, Winz) na współrzędne obiektu za pomocą transformacji zdefiniowanych przez matrycę ModelView (modelMatrix), macierz projekcji (projMatrix), a okna (rzutni) . Wynikowe współrzędne obiektu są zwracane w objx, objy i objz. Funkcja zwraca GL_TRUE, co wskazuje na sukces, lub GL_FALSE, wskazując na niepowodzenie (takie jak niewymienialna matryca). Ta operacja nie próbuje przypiąć współrzędnych do widoku lub wyeliminować wartości głębokości, które nie mieszczą się poza glDepthRange().

Istnieją nieodłączne trudności w próbie odwrócenia procesu transformacji.Dwuwymiarowa lokalizacja ekranu mogła pochodzić z dowolnego miejsca na całej linii w przestrzeni trójwymiarowej. Disambiguate wynik, gluUnProject() wymaga, aby koordynować głębokość okno (Winz) być dostarczone oraz że Winz być określone pod względem glDepthRange(). Dla wartości domyślnych glDepthRange(), Winz na 0,0 zwróci świat współrzędne punktu przekształconej w najbliższej wycinek płaszczyzny, natomiast Winz przy 1,0 zwróci się do punktu na płaszczyźnie daleko wycinek.

Przykład 3-8 (znów zobaczyć the PDF) wykazuje gluUnProject(), odczytując położenie myszy i określenia punktów trójwymiarowych, przy blisko i daleko od płaszczyzny odcinania, która została przekształcona. Obliczone współrzędne świata są drukowane na standardowe wyjście, ale samo renderowane okno jest po prostu czarne.

Pod względem wydajności, I found this quickly via Google jako przykład tego, co może nie chcą zrobić za pomocą gluUnProject, z linkiem do what might lead to a better alternative. Nie mam absolutnie pojęcia, jak ma to zastosowanie w przypadku iPhone'a, ponieważ wciąż jestem nowicjuszem w OpenGL ES. Zapytaj mnie ponownie za miesiąc. ;-)

Powiązane problemy