2009-07-02 20 views
5

El problema-Screen-a mundo en el iPhon e
La conversión de coordenadas de la pantalla al mundo en OpenGLES es una tarea fácil?

tengo un modelo 3D (cubo) dictada en un EAGLView y yo quiero ser capaz de detectar cuando estoy tocando el centro de una cara dada (Desde cualquier ángulo de orientación) del cubo. Suena bastante fácil pero no lo es ...

El problema:
¿Cómo me relaciono con precisión las coordenadas de pantalla (punto de contacto) a las coordenadas mundiales (una ubicación en el espacio 3D OpenGL)? Claro, la conversión de un punto dado en un 'porcentaje' de la pantalla/eje del mundo puede parecer la solución lógica, pero surgirían problemas cuando necesite hacer zoom o rotar el espacio 3D. Nota: al girar & al acercar y alejar el espacio 3D, cambiará la relación de los coords de la pantalla 2D con los coords mundiales tridimensionales ... Además, debe permitir la "distancia" entre el punto de vista y los objetos en el espacio 3D . Al principio, esto podría parecer una 'tarea fácil', pero eso cambia cuando realmente se examinan los requisitos. Y no he encontrado ejemplos de personas haciendo esto en el iPhone. ¿Cómo se hace esto normalmente?

Un 'fácil' tarea ?:
Claro, se podría llevar a cabo la tarea de escribir una API para actuar como un intermediario entre la pantalla y el mundo, pero la tarea de crear un marco de este tipo requeriría algunos graves diseño y probablemente tomaría "tiempo" para hacer - NO es algo que puede ser one-manned en 4 horas ... Y 4 horas pasa a ser mi fecha límite.

La pregunta:

  • ¿Cuáles son algunas de las maneras más simples de saber si tocaba lugares específicos en el espacio 3D en el mundo iPhone OpenGL ES?
+0

AFAIK esto no es un problema trivial a menos que lo haya resuelto antes o a menos que ya haya compatibilidad integrada en su entorno (lo que no parece ser el caso). Sé que parece más fácil de lo que es, hemos tenido la misma discusión con mis colegas. – zoul

Respuesta

1

Se presentan dos soluciones. Ambos deberían alcanzar el objetivo final, aunque por otros medios: en lugar de responder "¿qué coordenadas del mundo hay debajo del mouse?", Responden a la pregunta "¿qué objeto se representa con el mouse?".

Una es para dibujar una versión simplificada de su modelo a un búfer fuera de la pantalla, haciendo que el centro de cada cara use un color distinto (y ajuste la iluminación para que el color se conserve idénticamente). A continuación, puede detectar esos colores en el búfer (por ejemplo, pixmap) y asignarles ubicaciones de mouse.

El otro es usar la selección de OpenGL. Hay un tutorial de aspecto decente here.La idea básica es poner OpenGL en el modo de selección, restringir la ventana gráfica a una ventana pequeña (tal vez de 3x3 o 5x5) alrededor del punto de interés, y luego renderizar la escena (o una versión simplificada) usando OpenGL "nombres" (entero identificadores) para identificar los componentes que componen cada cara. Al final de este proceso, OpenGL puede darle una lista de los nombres que se representaron en la ventana de selección. La asignación de estos identificadores a los objetos originales le permitirá determinar qué objeto se encuentra debajo del cursor del mouse.

+1

Solo una nota para el iPhone: no hay elección de OpenGL en Open GL ES 1.1, así que no tienes suerte. – jv42

0

Google para opengl screen to world (por ejemplo, hay un hilo donde alguien quiere hacer exactamente lo que está buscando en GameDev.net). Hay una función gluUnProject que hace precisamente esto, pero no está disponible en el iPhone, por lo que debe portarlo (consulte this source desde el proyecto Mesa). ¿O tal vez ya hay alguna fuente públicamente disponible en alguna parte?

+0

¿Es complicado asociar toques con áreas en modelos 3D en un EAGLView? Parece que hay poca cobertura sobre este tema. El enlace que proporcionó realmente no me proporcionó ninguna pista para lograr esto en Xcode. Gracias por la respuesta, sin embargo. – RexOnRoids

+0

Creo que realmente es tan complicado y que el enlace responde su pregunta, pero esperemos, quizás alguien obtenga una mejor respuesta. – zoul

+0

EAGLView y OpenGL son solo herramientas para dibujar sus modelos. No se encargan de la detección de golpes ni nada por el estilo. Tienes que hacer eso. –

2

Imagine una línea que se extiende desde el ojo del espectador
a través del punto de contacto de la pantalla en el espacio modelo 3D.

Si esa línea intersecta cualquiera de las caras del cubo, el usuario ha tocado el cubo.

+0

Eso funcionaría si fuera solo un cubo simple con 8 vértices. El mío es en realidad un cubo 3D-Lego con más de 500 vértices (de los cilindros en la parte superior) y los datos se cargan automáticamente desde un archivo exportador de licuadora, es decir: no tengo idea de cuál de los más de 500 vértices seguir como mis 8 esquinas y por lo tanto no puede rastrear mis caras. – RexOnRoids

+0

¿Por qué no calcula/estima un prisma rectangular de límite para su bloque de lego, luego verifique que para la intersección. Continúa, sabes que quieres. –

+0

¿Cómo puedo 'marcar' un cuadro delimitador para una intersección con respecto a un toque que es un punto 2D en la pantalla? – RexOnRoids

3

Necesita tener las matrices de proyección openlight y modelview. Multiplíquelos para obtener la matriz de proyección de modelview. Invierta esta matriz para obtener una matriz que transforma las coordenadas del espacio del clip en coordenadas mundiales. Transforme su punto de contacto para que corresponda a las coordenadas del clip: el centro de la pantalla debe ser cero, mientras que los bordes deben ser + 1/-1 para X e Y respectivamente.

construcción de dos puntos, uno en (0,0,0) y uno al (touch_x, touch_y, -1) y transformar tanto por la matriz inversa de proyección modelview.

Haga lo inverso de una división de perspectiva.

Debe obtener dos puntos que describen una línea desde el centro de la cámara en "la distancia lejana" (Farplane).

Do picking basado en cuadros delimitadores simplificadas de sus modelos. Debería poder encontrar algoritmos de intersección de rayos/casillas en abundancia en la web.

Otra solución es pintar cada uno de los modelos en un color ligeramente diferente en un búfer fuera de la pantalla y leer el color en el punto de contacto a partir de ahí, que le dice lo que brich fue tocado.

Aquí es fuente de un cursor que escribí para un pequeño proyecto usando la física de bala:

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

Ahora puede encontrar gluUnProject en http://code.google.com/p/iphone-glu/. No tengo ninguna asociación con el proyecto iphone-glu y aún no lo he probado, solo quería compartir el enlace.

¿Cómo usarías esa función? This PDF menciona que:

La biblioteca de utilidades rutina gluUnProject() realiza esta inversión de las transformaciones. Dadas las coordenadas tridimensionales de la ventana para una ubicación y todas las transformaciones que las afectaron, gluUnProject() devuelve las coordenadas mundiales desde donde se originó.

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

el mapa los coordenadas de ventana especificados (winx, vinoso, Winz) en coordenadas del objeto, usando transformaciones definidas por una matriz modelview (modelMatrix), matriz de proyección (projMatrix), y ventana (ventana) . Las coordenadas del objeto resultante se devuelven en objx, objy y objz. La función devuelve GL_TRUE, el éxito que indica, o GL_FALSE, que indica un fallo (tal como una matriz no invertible). Esta operación no intenta recortar las coordenadas de la ventana gráfica ni eliminar los valores de profundidad que quedan fuera de glDepthRange().

existen dificultades inherentes al tratar de revertir el proceso de transformación.Una ubicación de pantalla bidimensional podría haberse originado desde cualquier parte de una línea completa en el espacio tridimensional. Para desambiguar el resultado, gluUnProject() requiere que se proporcione una coordenada de profundidad de ventana (winz) y que winz se especifique en términos de glDepthRange(). Para los valores predeterminados de glDepthRange(), winz en 0.0 solicitará las coordenadas mundiales del punto transformado en el plano de recorte cercano, mientras que winz en 1.0 solicitará el punto en el plano de recorte lejano.

Ejemplo 3-8 (de nuevo, ver the PDF) demuestra gluUnProject() mediante la lectura de la posición del ratón y la determinación de los puntos tridimensionales en los planos de cerca y de lejos de recorte desde el que fue transformado. Las coordenadas mundiales calculadas se imprimen a la salida estándar, pero la ventana renderizada en sí misma es simplemente negra.

En términos de rendimiento, I found this quickly via Google como un ejemplo de lo que puede que no desee hacer usando gluUnProject, con un enlace a what might lead to a better alternative. No tengo ni idea de qué tan aplicable es para el iPhone, ya que todavía soy un principiante con OpenGL ES. Pregúntame nuevamente en un mes. ;-)

Cuestiones relacionadas