2009-07-02 12 views
5

Il problema Screen-a-mondo sulla iPhon e
Conversione di coordinate schermo-mondo in OpenGLES un compito facile?

Ho un modello 3D (cubo) reso in un EAGLView e voglio essere in grado di rilevare quando sto toccando il centro di una data faccia (Da qualsiasi angolo di orientamento) del cubo. Suona abbastanza facile ma non lo è ...

Il problema:
Come si riferiscono con precisione screen-coordinate (punto di contatto) alla più coordinate (a posizione nello spazio 3D OpenGL)? Certo, la conversione di un dato punto in una "percentuale" dello schermo/asse del mondo potrebbe sembrare la soluzione logica, ma i problemi sorgerebbero quando ho bisogno di zoomare o ruotare lo spazio 3D. Nota: ruotando lo zoom & lo zoom in avanti e indietro nello spazio 3D cambierà la relazione delle schermate 2D con le coordinate 3D del mondo ... Inoltre, dovresti tenere conto della "distanza" tra il punto di vista e gli oggetti nello spazio 3D . All'inizio, questo potrebbe sembrare un 'compito facile', ma questo cambia quando si esaminano effettivamente i requisiti. E non ho trovato esempi di persone che lo fanno su iPhone. Come si fa normalmente?

Un 'facile' compito ?:
Certo, si potrebbe intraprendere il compito di scrivere un'API di agire come un intermediario tra schermo e il mondo, ma il compito di creare un tale quadro richiederebbe alcuni gravi design e probabilmente impiegherebbe del "tempo" per fare - NON qualcosa che può essere con una persona in 4 ore ... E 4 ore è la mia scadenza.

La domanda:

  • Quali sono alcuni dei modi più semplici per sapere se ho toccato posizioni specifiche nello spazio 3D nel mondo iPhone OpenGL ES?
+0

AFAIK questo non è un problema banale a meno che non lo abbiate risolto prima o a meno che non ci sia già un supporto integrato nell'ambiente (che non sembra essere il caso). So che sembra più facile di quello che è, abbiamo avuto la stessa discussione con i miei colleghi. – zoul

risposta

1

Si presentano due soluzioni. Entrambi dovrebbero raggiungere l'obiettivo finale, anche se con un mezzo diverso: piuttosto che rispondere "a quale coordinata del mondo si trova sotto il mouse?", Rispondono alla domanda "quale oggetto viene reso sotto il mouse?".

Uno consiste nel disegnare una versione semplificata del modello su un buffer fuori schermo, rendendo il centro di ogni faccia utilizzando un colore distinto (e regolando l'illuminazione in modo che il colore sia preservato in modo identico). È quindi possibile rilevare quei colori nel buffer (ad esempio pixmap) e mappare le posizioni del mouse su di essi.

L'altro è utilizzare il prelievo OpenGL. C'è un tutorial dall'aspetto decente here.L'idea di base è di mettere OpenGL in modalità select, limitare il viewport a una piccola finestra (forse 3x3 o 5x5) attorno al punto di interesse, e quindi renderizzare la scena (o una versione semplificata di essa) usando i "nomi" OpenGL (intero identificatori) per identificare i componenti che compongono ciascuna faccia. Alla fine di questo processo, OpenGL può darti un elenco dei nomi che sono stati resi nella finestra di selezione. Mappare questi identificatori di nuovo agli oggetti originali ti permetterà di determinare quale oggetto si trova sotto il cursore del mouse.

+1

Solo una nota per l'iPhone: nessun prelievo OpenGL in Open GL ES 1.1, quindi sei sfortunato. – jv42

0

Google per opengl screen to world (ad esempio, c'è un thread in cui qualcuno vuole fare esattamente quello che stai cercando per il GameDev.net). C'è una funzione gluUnProject che fa esattamente questo, ma non è disponibile su iPhone, quindi devi portarlo (vedi this source dal progetto Mesa). O forse c'è già qualche fonte pubblicamente disponibile da qualche parte?

+0

L'associazione di tocchi con aree su modelli 3D in un EAGLView è complicata? Sembra esserci poca copertura su questo argomento .. Il collegamento che hai fornito in realtà non mi ha fornito alcun indizio per ottenere questo risultato in Xcode. Grazie per la risposta, comunque. – RexOnRoids

+0

Penso che sia davvero complicato e che il link risponda alla tua domanda, ma aspettiamo - forse qualcuno troverà una risposta migliore. – zoul

+0

EAGLView e OpenGL sono solo strumenti per disegnare i tuoi modelli. Non si occupano della rilevazione dei colpi o di qualcosa del genere. Devi farlo. –

2

Immaginate una linea che si estende dall'occhio dello spettatore
attraverso il touch point dello schermo nel vostro spazio modello 3D.

Se quella linea interseca una delle facce del cubo, l'utente ha toccato il cubo.

+0

Funzionerebbe se fosse solo un semplice cubo con 8 vertici. Il mio è in realtà un cubo 3D-Lego con oltre 500 vertici (dai cilindri in alto) e i dati vengono caricati automaticamente da un file di esportazione del frullatore, ad esempio: non ho idea di quale dei 500+ vertici tracciare come i miei 8 angoli e quindi non posso seguire le mie facce. – RexOnRoids

+0

Perché non si calcola/ospite un prisma rettangolare vincolante per il blocco lego, quindi controllare quello per l'intersezione. Vai, lo sai che vuoi. –

+0

Come dovrei 'controllare' un riquadro di delimitazione per un'intersezione rispetto ad un tocco che è un punto 2D sullo schermo? – RexOnRoids

3

È necessario disporre delle proiezioni opengl e delle matrici modelview. Moltiplicali per ottenere la matrice di proiezione modelview. Invertire questa matrice per ottenere una matrice che trasforma le coordinate dello spazio clip in coordinate del mondo. Trasforma il tuo punto di tocco in modo che corrisponda alle coordinate della clip: il centro dello schermo dovrebbe essere zero, mentre i bordi dovrebbero essere + 1/-1 per X e Y rispettivamente.

costruire due punti, uno a (0,0,0) e uno a (touch_x, touch_y, -1) e trasformare entrambi dalla matrice di proiezione inversa di modelview.

Esegue l'inverso di una divisione di prospettiva.

Si dovrebbero ottenere due punti che descrivono una linea dal centro della telecamera in "la lontananza" (il farplane).

Effettuare il prelievo in base a caselle di delimitazione semplificate dei modelli. Dovresti essere in grado di trovare algoritmi di intersezione ray/box in abbondanza sul web.

Un'altra soluzione è dipingere ciascuno dei modelli in un colore leggermente diverso in un buffer fuori schermo e leggere il colore al punto di contatto da lì, che ti dice quale tocco è stato toccato.

Ecco fonte per un cursore che ho scritto per un piccolo progetto con proiettile fisica:

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

È possibile ora trovare gluUnProject in http://code.google.com/p/iphone-glu/. Non ho alcuna associazione con il progetto iphone-glu e non l'ho ancora provato, volevo solo condividere il link.

Come utilizzeresti tale funzione? This PDF afferma che:

L'utilità Biblioteca di routine gluUnProject() esegue questa inversione delle trasformazioni. Date le coordinate tridimensionali della finestra per una posizione e tutte le trasformazioni che le hanno influenzate, gluUnProject() restituisce le coordinate del mondo da dove ha avuto origine.

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); 

mappa le coordinate della finestra specificate (winx, vinoso, Winz) in oggetto coordinate, utilizzando le trasformazioni definite da una matrice modelview (modelMatrix), matrice di proiezione (projMatrix), e finestra (finestra) . Le coordinate dell'oggetto risultanti vengono restituite in objx, objy e objz. La funzione restituisce GL_TRUE, che indica il successo, oppure GL_FALSE, che indica un errore (ad esempio una matrice non iniziabile). Questa operazione non tenta di ritagliare le coordinate sul viewport o eliminare i valori di profondità che non rientrano in glDepthRange().

Esistono difficoltà intrinseche nel tentativo di invertire il processo di trasformazione.Una posizione dello schermo bidimensionale potrebbe essere originata da qualsiasi punto su un'intera linea nello spazio tridimensionale. Per disambiguare il risultato, gluUnProject() richiede che sia fornita una coordinata della profondità della finestra (winz) e che winz sia specificato in termini di glDepthRange(). Per i valori di default di glDepthRange(), winz a 0.0 richiederà le coordinate del mondo del punto trasformato sul piano di clipping vicino, mentre winz a 1.0 richiederà il punto sul piano di ritaglio lontano.

Esempio 3-8 (si veda ancora the PDF) dimostra gluUnProject() leggendo la posizione del mouse e determinare i punti tridimensionali ai vicini e lontani piani di ritaglio da cui è stato trasformato. Le coordinate del mondo calcolato vengono stampate sullo standard output, ma la finestra di rendering stessa è solo nera.

In termini di prestazioni, I found this quickly via Google come esempio di cosa non si potrebbe voler fare usando gluUnProject, con un collegamento a what might lead to a better alternative. Non ho assolutamente idea di quanto sia applicabile all'iPhone, dato che sono ancora un newb con OpenGL ES. Chiedimi di nuovo tra un mese. ;-)

Problemi correlati