I am also working on this, it is a very annoying annoying problem. I have two potential conclusions: 1. Somehow, the resulting z depends on where the camera is, and not on how you expect. When camera z is at 0, the result of z is -1, regardless of what winZ is. Until now, I mainly looked at the resulting z, so I donβt have exact numbers for other coordinates, but now I messed up my code and your code, and I found that the messages being sent the beam length increases, the further the camera receives (0,0, 0). At (0,0,0) the beam length is reportedly equal to 0. An hour or so ago, I collected a bunch of points (cameraZ, winZ, resultZ) and connected them to Mathematica. The result seems to indicate a hyperbolic appearance of things; with one of the fixed variables, the other leads to the fact that the resulting z varies linearly, and the rate of change depends on the fixed variable.
My second result is http://www.gamedev.net/topic/420427-gluunproject-question/ ; swordfish quotes the formula:
WinZ = (1.0f / fNear-1.0f / fDistance) / (1.0f / fNear-1.0f / fFar)
Now this is not like the data I collected, but it is probably worth a look. I think I'll see if I can understand how math works and find out what happened. Let me know if you come up with anything. Oh, also, here is a formula tied to the collected data:
-0.11072114015496763 - 10.000231721597817 x - 0.0003149873867479971 x^2 - 0.8633277851535017 y + 9.990256062051143 xy + 8.767260632968973 * ^ - 9 y ^ 2
Wolfram Alpha does it like this: http://www.wolframalpha.com/input/?i=Plot3D [-0.11072114015496763% 60 + - + 10.000231721597817% 60 + x + - ++++ 0.0003149873867479971% 60 + x ^ 2 + - + 0.8633277851535017% 60 + y +% 2B ++++ 9.990256062051143% 60 + x + y +% 2B + 8.767260632968973% 60 * ^ - 9 + y ^ 2 +% 2C + {x% 2C + -15% 2C +++ +15}% 2C + {for% 2C + 0% 2C + 1}]
Aha! Success! As far as I can tell, gluUnProject is just broken. Or no one understands how to use it at all. Anyway, I created a function that properly overrides the gluProject function, which seems to be what they use to draw on the screen in some way! The code is as follows:
public float[] unproject(float rx, float ry, float rz) {//TODO Factor in projection matrix float[] modelInv = new float[16]; if (!android.opengl.Matrix.invertM(modelInv, 0, mg.mModelView, 0)) throw new IllegalArgumentException("ModelView is not invertible."); float[] projInv = new float[16]; if (!android.opengl.Matrix.invertM(projInv, 0, mg.mProjection, 0)) throw new IllegalArgumentException("Projection is not invertible."); float[] combo = new float[16]; android.opengl.Matrix.multiplyMM(combo, 0, modelInv, 0, projInv, 0); float[] result = new float[4]; float vx = viewport[0]; float vy = viewport[1]; float vw = viewport[2]; float vh = viewport[3]; float[] rhsVec = {((2*(rx-vx))/vw)-1,((2*(ry-vy))/vh)-1,2*rz-1,1}; android.opengl.Matrix.multiplyMV(result, 0, combo, 0, rhsVec, 0); float d = 1 / result[3]; float[] endResult = {result[0] * d, result[1] * d, result[2] * d}; return endResult; } public float distanceToDepth(float distance) { return ((1/fNear) - (1/distance))/((1/fNear) - (1/fFar)); }
Currently, it accepts the following global variables: mg - matrix grabber with current viewport matrices - float [4] with a viewport ({x, y, width, height})
The variables that it takes are equivalent to the ones gluUnProject should have done. For instance:
float[] xyz = {0, 0, 0}; xyz = unproject(mouseX, viewport[3] - mouseY, 1);
This will return the point under the mouse in the background. I also added a function to convert between the specified distance from the camera and its 0-1 ... representation ... thing. For instance:
unproject(mouseX, viewport[3] - mouseY, distanceToDepth(5));
This will return the point under the mouse 5 units from the camera. I checked this using the method asked in the question - I checked the distance between the near plane and the long-range plan. With fNear 0.1 and fFar 100, the distance should be 99.9. As far as I can tell, I constantly got about 99.8977, regardless of the position or orientation of the camera. Haha, good thing that turned out. Let me know if you / don't have any problems with this, or if you want me to rewrite it to input resources instead of using global variables. Hope this helps a few people; I was curious about this for several days before seriously trying to fix it.
Hey, therefore, figuring out how it should be, I realized that they missed the implementation of gluUnProject. They forgot (not intended for anyone and didnβt tell anyone?), To divide into the fourth element of the resulting vector, which, as it were, normalizes the vector or something like that. gluProject sets it to 1 before applying matrices, so to complete them you need 1 when you cancel them. In short, you can use gluUnProject, but you need to pass it a float [4], and then divide all the resulting coordinates into a fourth, for example:
float[] xyzw = {0, 0, 0, 0}; android.opengl.GLU.gluUnProject(rx, ry, rz, mg.mModelView, 0, mg.mProjection, 0, this.viewport, 0, xyzw, 0); xyzw[0] /= xyzw[3]; xyzw[1] /= xyzw[3]; xyzw[2] /= xyzw[3]; //xyzw[3] /= xyzw[3]; xyzw[3] = 1; return xyzw;
xyzw should now contain the corresponding spatial coordinates. This seems to work just like the one I combined. It may be a little faster; I think they combined one of the steps.