Android OpenGL ES 2.0 coordina las coordenadas con las coordenadas mundiales
opengl-es-2.0 coordinate-transformation (3)
Estoy creando una aplicación para Android que utiliza OpenGL ES 2.0 y me he encontrado con una pared. Estoy tratando de convertir las coordenadas de la pantalla (donde el usuario toca) en coordenadas mundiales. He intentado leer y jugar con GLU.gluUnProject pero lo estoy haciendo mal o simplemente no lo entiendo.
Este es mi intento ...
public void getWorldFromScreen(float x, float y) {
int viewport[] = { 0, 0, width , height};
float startY = ((float) (height) - y);
float[] near = { 0.0f, 0.0f, 0.0f, 0.0f };
float[] far = { 0.0f, 0.0f, 0.0f, 0.0f };
float[] mv = new float[16];
Matrix.multiplyMM(mv, 0, mViewMatrix, 0, mModelMatrix, 0);
GLU.gluUnProject(x, startY, 0, mv, 0, mProjectionMatrix, 0, viewport, 0, near, 0);
GLU.gluUnProject(x, startY, 1, mv, 0, mProjectionMatrix, 0, viewport, 0, far, 0);
float nearX = near[0] / near[3];
float nearY = near[1] / near[3];
float nearZ = near[2] / near[3];
float farX = far[0] / far[3];
float farY = far[1] / far[3];
float farZ = far[2] / far[3];
}
Los números que estoy obteniendo no parecen correctos, ¿es esta la forma correcta de utilizar este método? ¿Funciona para OpenGL ES 2.0? ¿Debería hacer de la Matriz Modelo una matriz de identidad antes de estos cálculos (Matrix.setIdentityM (mModelMatix, 0))?
Como seguimiento, si esto es correcto, ¿cómo selecciono la salida Z? Básicamente, siempre sé a qué distancia quiero que estén las coordenadas del mundo, pero el parámetro Z en GLU.gluUnProject parece ser algún tipo de interpolación entre el plano cercano y el plano lejano. ¿Es solo una interpolación lineal?
Gracias por adelantado
En mi humilde opinión no es necesario volver a implementar esta función ... Experimenté con la solución de Erol y funcionó, así que muchas gracias por ello, Erol. Además, jugué con
Matrix.orthoM(mtrxProjection, 0, left, right, bottom, top, near, far);
y funciona bien también en mi pequeño proyecto de noob 2D 2D OpenGL ES 2.0:
Espero que mi pregunta (y respuesta) te ayude:
Cómo encontrar la posición absoluta de clic mientras se acerca.
No solo tiene el código, sino también los diagramas y diagramas y los diagramas que lo explican :) Me tomó años para descubrirlo también.
/**
* Calculates the transform from screen coordinate
* system to world coordinate system coordinates
* for a specific point, given a camera position.
*
* @param touch Vec2 point of screen touch, the
actual position on physical screen (ej: 160, 240)
* @param cam camera object with x,y,z of the
camera and screenWidth and screenHeight of
the device.
* @return position in WCS.
*/
public Vec2 GetWorldCoords( Vec2 touch, Camera cam)
{
// Initialize auxiliary variables.
Vec2 worldPos = new Vec2();
// SCREEN height & width (ej: 320 x 480)
float screenW = cam.GetScreenWidth();
float screenH = cam.GetScreenHeight();
// Auxiliary matrix and vectors
// to deal with ogl.
float[] invertedMatrix, transformMatrix,
normalizedInPoint, outPoint;
invertedMatrix = new float[16];
transformMatrix = new float[16];
normalizedInPoint = new float[4];
outPoint = new float[4];
// Invert y coordinate, as android uses
// top-left, and ogl bottom-left.
int oglTouchY = (int) (screenH - touch.Y());
/* Transform the screen point to clip
space in ogl (-1,1) */
normalizedInPoint[0] =
(float) ((touch.X()) * 2.0f / screenW - 1.0);
normalizedInPoint[1] =
(float) ((oglTouchY) * 2.0f / screenH - 1.0);
normalizedInPoint[2] = - 1.0f;
normalizedInPoint[3] = 1.0f;
/* Obtain the transform matrix and
then the inverse. */
Print("Proj", getCurrentProjection(gl));
Print("Model", getCurrentModelView(gl));
Matrix.multiplyMM(
transformMatrix, 0,
getCurrentProjection(gl), 0,
getCurrentModelView(gl), 0);
Matrix.invertM(invertedMatrix, 0,
transformMatrix, 0);
/* Apply the inverse to the point
in clip space */
Matrix.multiplyMV(
outPoint, 0,
invertedMatrix, 0,
normalizedInPoint, 0);
if (outPoint[3] == 0.0)
{
// Avoid /0 error.
Log.e("World coords", "ERROR!");
return worldPos;
}
// Divide by the 3rd component to find
// out the real position.
worldPos.Set(
outPoint[0] / outPoint[3],
outPoint[1] / outPoint[3]);
return worldPos;
}
El algoritmo se explica con más detalle here.