gluUnProject always returns zero - android

I need gluUnProject to convert screen coordinates to world coordinates and right now I just about have it working. When my app runs it accurately tells me the coordinates on screen which I know are stored in my renderer thread and then pumps out screen coordinates. Unfortunately the screen coordinates seem to have no effect of world coordinates and the world coordinates remain at zero.
Here is my gluUnProject method
public void vector3 (GL11 gl){
int[] viewport = new int[4];
float[] modelview = new float[16];
float[] projection = new float[16];
float winx, winy, winz;
float[] newcoords = new float[4];
gl.glGetIntegerv(GL11.GL_VIEWPORT, viewport, 0);
((GL11) gl).glGetFloatv(GL11.GL_MODELVIEW_MATRIX, modelview, 0);
((GL11) gl).glGetFloatv(GL11.GL_PROJECTION_MATRIX, projection, 0);
winx = (float)setx;
winy = (float)viewport[3] - sety;
winz = 0;
GLU.gluUnProject(setx, (float)viewport[3] - sety, 0, modelview, 0, projection, 0, viewport, 0, newcoords, 0);
posx = (int)newcoords[0];
posy = (int)newcoords[1];
posz = (int)newcoords[2];
Log.d(TAG, "x= " + String.valueOf(posx));
Log.d(TAG, "y= " + String.valueOf(posy));
Log.d(TAG, "z= " + String.valueOf(posz));
}
Now I've searched and found this forum post and they came to the conclusion that it was to do with using getFloatv instead of getDoublev, but getDoublev does not seem to be supported by GL11
The method glGetDoublev(int, float[], int) is undefined for the type GL11
and also
The method glGetDoublev(int, double[], int) is undefined for the type GL11
should the double and float thing matter and if so how do I go about using doubles
Thank you
EDIT:
I was told that gluUnproject fails when too close to the near far clipping plane so I set winz to -5 when near is 0 and far is -10. This had no effect on the output.
I also logged each part of the newcoords[] array and they all return something that is NaN (not a number) could this be the problem or something higher up in the algorithm

I'm guessing you're working on the emulator? Its OpenGL implementation is rather buggy, and after testing I found that it returns all zeroes for the following calls:
gl11.glGetIntegerv(GL11.GL_VIEWPORT, viewport, 0);
gl11.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, modelview, 0);
gl11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, projection, 0);
The gluUnProject() function needs to calculate the inverse of the combined modelview-projection matrix, and since these are all zeroes, the inverse does not exist and will consist of NaNs. The resulting newcoords vector is therefor also all Nans.
Try it on a device with a proper OpenGL implementation, it should work. Keep in mind to still divide by newcoords[3] though ;-)

Related

Android 3D Surface Plot

My requirement is to create a 3d surface plot(should also display the x y z axis) from a list of data points (x y z) values.The 3d visualization should be done on ANDROID.
My Inputs : Currently planning on using open gl 1.0 and java. I m also considering Adore3d , min3d and rgl package which uses open gl 1.0. Good at java ,but a novice at 3d programming.
Time Frame : 2 months
I would like to know the best way to go about it? Is opengl 1.0 good for 3d surface plotting?Any other packages/libraries that can be used with Android?
Well, you can plot the surface using OpenGL 1.0 or OpenGL 2.0. All you need to do is to draw the axes as lines and draw the surface as triangles. If you have your heightfield data, you would do:
float[][] surface;
int width, height; // 2D surface data and it's dimensions
GL.glBegin(GL.GL_LINES);
GL.glVertex3f(0, 0, 0); // line starting at 0, 0, 0
GL.glVertex3f(width, 0, 0); // line ending at width, 0, 0
GL.glVertex3f(0, 0, 0); // line starting at 0, 0, 0
GL.glVertex3f(0, 0, height); // line ending at 0, 0, height
GL.glVertex3f(0, 0, 0); // line starting at 0, 0, 0
GL.glVertex3f(0, 50, 0); // line ending at 0, 50, 0 (50 is maximal value in surface[])
GL.glEnd();
// display the axes
GL.glBegin(GL.GL_TRIANGLES);
for(int x = 1; x < width; ++ x) {
for(int y = 1; y < height; ++ y) {
float a = surface[x - 1][y - 1];
float b = surface[x][y - 1];
float c = surface[x][y];
float d = surface[x - 1][y];
// get four points on the surface (they form a quad)
GL.glVertex3f(x - 1, a, y - 1);
GL.glVertex3f(x, b, y - 1);
GL.glVertex3f(x, c, y);
// draw triangle abc
GL.glVertex3f(x - 1, a, y - 1);
GL.glVertex3f(x, c, y);
GL.glVertex3f(x - 1, d, y);
// draw triangle acd
}
}
GL.glEnd();
// display the data
This draws simple axes and heightfield, all in white color. It should be pretty straight forward to extend it from here.
Re the second part of your question:
Any other packages/libraries that can be used with Android?
Yes, it's now possible to draw an Android 3D Surface Plot with SciChart.
Link to Android Chart features page
Link to Android 3D Surface Plot example
Lots of configurations are possible including drawing wireframe, gradient colour maps, contours and real-time updates.
Disclosure, I'm the tech lead on the scichart team

Problems using gluUnProject

Basically i have an application for Android 1.5 with a GLSurfaceView class that shows a simple square polygon on the screen. I want to learn to add a new functionality, the functionality of moving the square touching it with the finger. I mean that when the user touches the square and moves the finger, the square should be moved with the finger, until the finger releases the screen.
I'm trying to use gluUnProject to obtain the OpenGL coordinates that matches the exact position of the finger, then, i will make a translatef to the polygon, and i will get the polygon moved to that position (i hope it)
The problem is that something is going wrong with gluUnProject, it is giving me this exception: java.lang.IllegalArgumentException: length - offset < n on the call to gluUnProject.
First of all, i'm passing 0 as Z win coordinate because i dont know what i have to pass as z win coordinate, because win doesn't have Z coordinates, only X and Y. I tested passing 1 on Z coordinate, and i'm getting the same exception.
float [] outputCoords=getOpenGLCoords(event.getX(), event.getY(), 0);
x=outputCoords[0];
y=outputCoords[1];
z=outputCoords[2];
.
.
.
public float[] getOpenGLCoords(float xWin,float yWin,float zWin)
{
int screenW=SectionManager.instance.getDisplayWidth();
int screenH=SectionManager.instance.getDisplayHeight();
//CODE FOR TRANSLATING FROM SCREEN COORDINATES TO OPENGL COORDINATES
mg.getCurrentProjection(MyGl);
mg.getCurrentModelView(MyGl);
float [] modelMatrix = new float[16];
float [] projMatrix = new float[16];
modelMatrix=mg.mModelView;
projMatrix=mg.mProjection;
int [] mView = new int[4];
mView[0] = 0;
mView[1] = 0;
mView[2] = screenW; //width
mView[3] = screenH; //height
float [] outputCoords = new float[3];
GLU.gluUnProject(xWin, yWin, zWin, modelMatrix, 0, projMatrix, 0, mView, 0, outputCoords, 0);
return outputCoords;
}
I answered the same question here; basically the gluUnproject function expects your outputCoords array to have size 4 instead of 3. Note that these are homogeneous coordinates, so you still have to divide the first 3 by the 4th one if you're doing perspective projection.

Android OpenGL - Help with C++ Conversion

I'm trying to convert this C++ code to Android's Java. However, I'm using GL10 and glGetDoublev apparently isn't supported on OpenGL-ES. How else can I perform this function?
// Get point by reading z buffer and unprojecting to object coords
void Pick(int x, int y)
{
GLint viewport[4];
GLdouble mvmatrix[16], projmatrix[16];
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
int winx = x;
int winy = winHeight - y;
GLfloat winz = 0.0;
GLdouble objx = 0.0;
GLdouble objy = 0.0;
GLdouble objz = 0.0;
// Get winz for given winx and winy
glReadPixels(winx, winy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winz);
// Make sure there was something at the point
if (winz >= 1.0)
{
qDebug("Nothing picked");
}
else
{
// Get object coords from win coords
gluUnProject((GLdouble)winx, (GLdouble)winy, (GLdouble)winz,
mvmatrix, projmatrix, viewport,
&objx, &objy, &objz);
qDebug("Pick: win=%d,%d,%.3f obj=%.3f,%.3f,%.3f",
winx, winy, winz, objx, objy, objz);
// Place a marker at that position
Marker marker;
marker.point.x = objx;
marker.point.y = objy;
marker.point.z = objz;
markerList << marker;
// limit to two markers
if (markerList.count() > 2)
markerList.pop_front();
Rebuild();
}
}
I ran into this problem in my own Android OpenGL ES 1.0 forays. Since OpenGL ES 1.0 does not allow you to get the matrices directly (as far as I know glGetFloatv was not implemented in 1.0), as you wanted to do, you need to make a wrapper that tracks matrices.
If you use OpenGL ES 1.1, you can use glGetFloatv since it has been implemented.
Here is the website where I originally found the solution:
http://www.41post.com/1540/programming/android-opengl-get-the-modelview-matrix-on-15-cupcake
All implementation details are there.

Android draw bitmap on polygons

I am trying to draw a bitmap on a polygon has sides more than 4. ı am dealing with opengl to do this but i realised in 2d there is a method called drawBitmapMesh in Canvas for this. It worked for 4 side polygon but not working for 5.
This works
float verts[] = {0,0, 0,10, 0,20 ,0,30, 10,0, 10,10, 10,20, 10,30, 20,0, 20,10, 20,20, 20,30, 30,0, 30,10, 30,20, 30,30};
canvas.drawBitmapMesh(bitmap, 3, 3, verts, 0, null, 0, null);
This does not work gives runtime error.
float verts[] = {0,0, 0,10, 0,20 ,0,30, 0,40, 10,0, 10,10, 10,20, 10,30,10,40, 20,0, 20,10, 20,20, 20,30,20,40, 30,0, 30,10, 30,20, 30,30,30,40};
canvas.drawBitmapMesh(bitmap, 4, 4, verts, 0, null, 0, null);
From the SDK documentation:
verts Array of x,y pairs, specifying where the mesh should be drawn. There must be at least (meshWidth+1) * (meshHeight+1) * 2 + meshOffset values in the array
You have 38 values in your array, whereas the above calculation with the parameters gives: (4+1)*(4+1)*2 + 0 = 50 values ...

Do OpenGL Point Sprites work in Android?

I'm developing on a Droid, version 2.1-update1. My supported GL extensions include GL_OES_point_sprite and GL_OES_point_size_array.
I am unable to get point sprites to render. The code below throws UnsupportedOperationException from GLWrapperBase at the glTexEnvi call. If I disable textures and comment out the glTexEnvi all, it throws the same exception further down, at glPointSizePointerOES().
Are point sprites properly supported in Android? Has anyone gotten them working? Or is there an issue with my code below?
// Note that gl is cast to GL11
gl.glEnable(GL11.GL_TEXTURE_2D);
gl.glEnable(GL11.GL_BLEND);
gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
gl.glDepthMask(false);
gl.glEnable(GL11.GL_POINT_SPRITE_OES);
gl.glTexEnvi( GL11.GL_POINT_SPRITE_OES, GL11.GL_COORD_REPLACE_OES, GL11.GL_TRUE );
gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL11.GL_SHORT, 0, .vertBuffer);
gl.glEnableClientState(GL11.GL_POINT_SIZE_ARRAY_OES);
gl.glPointSizePointerOES(GL11.GL_FLOAT, 0, pointSizeBuffer);
Thanks
I got this working, here is my draw function
Initialize everything
gl.glEnable(GL10.GL_TEXTURE);
TextureManager.activateTexture(gl, R.drawable.water1); //Don't look for this, it's not public api, just looks upd texture id for android resource if loaded, and then activates it. it's the gl.glBindTexture() call replacement
gl.glEnable(GL11.GL_POINT_SPRITE_OES);
gl.glEnableClientState(GL11.GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES);
gl.glEnableClientState(GL11.GL_POINT_SIZE_ARRAY_OES);
gl.glEnableClientState(GL11.GL_POINT_SPRITE_OES);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
Set the texture environment up to use point sprites
gl.glTexEnvf(GL11.GL_POINT_SPRITE_OES, GL11.GL_COORD_REPLACE_OES, GL11.GL_TRUE);
Set up pointers to the data (First array is 2d laid out [x,y,x2,y2,...] second is 1d [s1,s2,..])
gl.glVertexPointer(2,GL11.GL_FLOAT,0,PosData);
((GL11)(gl)).glPointSizePointerOES(GL10.GL_FLOAT, 0, SizeData);
Draw
gl.glDrawArrays(GL10.GL_POINTS,0,MAX);
Disable stuff
gl.glDisableClientState(GL11.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL11.GL_POINT_SIZE_ARRAY_OES);
gl.glDisableClientState(GL11.GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES);
gl.glDisableClientState(GL11.GL_POINT_SIZE_ARRAY_OES);
gl.glDisable(GL10.GL_TEXTURE);
In my initializer I only have my projection setup and GL_BLEND enabled for blending. I think you would need GL_COLOR_MATERIAL if you wanted to color your sprite.
I got the point sprites working with ES 1.1 & 2 on a nexus one. I use a fixed point size so I didn´t have to use a size buffer but you can use my code to first get it working and then add the size buffer.
In my draw method:
gl.glEnable(GL11.GL_POINT_SPRITE_OES);
gl.glTexEnvf(GL11.GL_POINT_SPRITE_OES, GL11.GL_COORD_REPLACE_OES, GL11.GL_TRUE);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 2 dimensional array, (x1,y1, x2, y2, ...).
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mVerticesBuffer);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
gl.glPointSize(32); // Fixed point size for all points
// This only worked with GLES11 & GLES20.
GLES11.glDrawArrays(GLES11.GL_POINTS, 0, vertices.length);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_TEXTURE_2D);
gl.glDisable(GL11.GL_POINT_SPRITE_OES);
if like me you're using MatrixTrackingGL you need to use glTexEnvf rather than glTexEnvi (f not i at the end) and you need to go into MatrixTrackingGL and change glPointSizePointerOES:
public void glPointSizePointerOES(int type, int stride, Buffer pointer) {
mgl11.glPointSizePointerOES(type, stride, pointer);
//throw new UnsupportedOperationException();
}
I'm sure there is a good reason why it is unsupported in the first place but I don't know it and it works for me on a ZTE Blade running android 2.1
For anyone wondering, MatrixTrackerGL comes from C:\Program Files\android-sdk-windows\samples\android-7\ApiDemos\src\com\example\android\apis\graphics\spritetext
It is used when setting up your GLSurface View:
// GraphicsRenderer is my implementation of Renderer
Graphics Renderer graphicsRenderer = new GraphicsRenderer(this);
GLSurfaceView mGLView = (GLSurfaceView) findViewById(R.id.graphics_glsurfaceview1);
mGLView.setGLWrapper(new GLSurfaceView.GLWrapper() {
public GL wrap(GL gl) {
return new MatrixTrackingGL(gl);
}});
mGLView.setEGLConfigChooser(true);
mGLView.setRenderer(graphicsRenderer);
and means you can use GLU.gluUnProject to do picking!:
MatrixGrabber matrixGrabber = new MatrixGrabber();
matrixGrabber.getCurrentModelView(gl);
matrixGrabber.getCurrentProjection(gl);
float[] vector = new float[4];
GLU.gluUnProject(x, y, 0f, matrixGrabber.mModelView, 0, matrixGrabber.mProjection, 0, new int[]{mGLView .getTop(),mGLView .getLeft(),mGLView .getWidth(),mGLView .getHeight()}, 0, vector, 0);

Categories

Resources