Android OpenGL 3D комплектация
Я нахожусь на Android OpenGL-ES 2.0 и после всех ограничений, которые идут с этим, я не могу понять, как сделать касания 2D-экрана к имеющимся 3D точкам. Я не могу получить правильные результаты.
Я пытаюсь реализовать съемку луча в облаке точек, с помощью которого я могу сравнить расстояния между моими точками и найти ближайшую точку.
public class OpenGLRenderer extends Activity implements GLSurfaceView.Renderer {
public PointCloud ptCloud;
MatrixGrabber mg = new MatrixGrabber();
...
public void onDrawFrame(GL10 gl) {
gl.glDisable(GL10.GL_COLOR_MATERIAL);
gl.glDisable(GL10.GL_BLEND);
gl.glDisable(GL10.GL_LIGHTING);
//Background drawing
if(customBackground)
gl.glClearColor(backgroundRed, backgroundGreen, backgroundBlue, 1.0f);
else
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
if (PointCloud.doneParsing == true) {
if (envDone == false)
setupEnvironment();
// Clears the screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 55.0f, (float) screenWidth / (float) screenHeight, 10.0f ,10000.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, eyeX, eyeY, eyeZ,
centerX, centerY, centerZ,
upX, upY, upZ);
if(pickPointTrigger)
pickPoint(gl);
gl.glPushMatrix();
gl.glTranslatef(_xTranslate, _yTranslate, _zTranslate);
gl.glTranslatef(centerX, centerY, centerZ);
gl.glRotatef(_xAngle, 1f, 0f, 0f);
gl.glRotatef(_yAngle, 0f, 1f, 0f);
gl.glRotatef(_zAngle, 0f, 0f, 1f);
gl.glTranslatef(-centerX, -centerY, -centerZ);
ptCloud.draw(gl);
gl.glPopMatrix();
}
}
}
Вот моя функция выбора. Я установил местоположение на середину экрана только для целей отладки:
public void pickPoint(GL10 gl){
mg.getCurrentState(gl);
double mvmatrix[] = new double[16];
double projmatrix[] = new double[16];
int viewport[] = {0,0,screenWidth, screenHeight};
for(int i=0 ; i<16; i++){
mvmatrix[i] = mg.mModelView[i];
projmatrix[i] = mg.mProjection[i];
}
mg.getCurrentState(gl);
float realY = ((float) (screenHeight) - pickY);
float nearCoords[] = { 0.0f, 0.0f, 0.0f, 0.0f };
float farCoords[] = { 0.0f, 0.0f, 0.0f, 0.0f };
GLU.gluUnProject(screenWidth/2, screenHeight/2, 0.0f, mg.mModelView, 0, mg.mProjection, 0,
viewport, 0, nearCoords, 0);
GLU.gluUnProject(screenWidth/2, screenHeight/2, 1.0f, mg.mModelView, 0, mg.mProjection, 0,
viewport, 0, farCoords, 0);
System.out.println("Near: " + nearCoords[0] + "," + nearCoords[1] + "," + nearCoords[2]);
System.out.println("Far: " + farCoords[0] + "," + farCoords[1] + "," + farCoords[2]);
//Plot the points in the scene
nearMarker.set(nearCoords);
farMarker.set(farCoords);
markerOn = true;
double diffX = nearCoords[0] - farCoords[0];
double diffY = nearCoords[1] - farCoords[1];
double diffZ = nearCoords[2] - farCoords[2];
double rayLength = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2) + Math.pow(diffZ, 2));
System.out.println("rayLength: " + rayLength);
pickPointTrigger = false;
}
Изменение перцептивного zNear и Far не дает ожидаемых результатов, как может быть удаленная точка перспективы 1.0-1000.0 на расстоянии 11 единиц?
GLU.gluPerspective(gl, 55.0f, (float) screenWidth / (float) screenHeight, 1.0f ,100.0f);
.....
07-18 11:23:50.430: INFO/System.out(31795): Near: 57.574852,-88.60514,37.272636
07-18 11:23:50.430: INFO/System.out(31795): Far: 0.57574844,0.098602295,0.2700405
07-18 11:23:50.430: INFO/System.out(31795): rayLength: 111.74275719790872
GLU.gluPerspective(gl, 55.0f, (float) width / (float) height, 10.0f , 1000.0f);
...
07-18 11:25:12.420: INFO/System.out(31847): Near: 5.7575016,-7.965394,3.6339219
07-18 11:25:12.420: INFO/System.out(31847): Far: 0.057574987,0.90500546,-0.06634784
07-18 11:25:12.420: INFO/System.out(31847): rayLength: 11.174307289026638
Ищете любые предложения или, надеюсь, ошибки, которые вы видите в моем коде. Очень признателен. Я ловлю столько, сколько могу (это было проблемой некоторое время).
1 ответ
Я тоже над этим работаю - это очень раздражающая раздражающая проблема. У меня есть два потенциальных отведения: 1. Каким-то образом результирующий z зависит от того, где находится камера, а не от того, как вы ожидаете. Когда камера имеет значение 0, результирующее значение z равно -1, независимо от того, что такое winZ. До сих пор я в основном смотрел на результирующую z, поэтому у меня нет точных цифр по другим координатам, но я сейчас бездельничал со своим кодом и вашим кодом, и я обнаружил, что длина луча увеличивается по мере удаления от камеры (0,0,0). При (0,0,0) длина луча, как сообщается, равна 0. Примерно час назад я собрал несколько точек (cameraZ, winZ, resultZ) и подключил их к Mathematica. Результат, кажется, указывает на гиперболическую вещь; при фиксированной одной из переменных другая приводит к линейному изменению результирующего z, причем скорость изменения зависит от фиксированной переменной.
Мое второе руководство от http://www.gamedev.net/topic/420427-gluunproject-question/; рыба-меч цитирует формулу:
WinZ = (1.0f / fNear-1.0f / fDistance) / (1.0f / fNear-1.0f / fFar)
Теперь, похоже, это не совпадает с данными, которые я собрал, но, вероятно, стоит посмотреть. Я думаю, что я собираюсь посмотреть, смогу ли я понять, как работает математика этой вещи, и выяснить, что не так. Дайте мне знать, если вы что-нибудь выясните. О, также, вот формула, приспособленная к данным, которые я собрал:
-0,11072114015496763- 10.000231721597817
х - 0,0003149873867479971x^2 - 0.8633277851535017
y + 9.990256062051143x y + 8.767260632968973
* ^ - 9 лет ^2
АГА! Успех! Насколько я могу судить, gluUnProject просто сломан. Или никто не понимает, как его использовать вообще. В любом случае, я сделал функцию, которая должным образом отменяет функцию gluProject, которая, похоже, действительно используется для рисования на экране каким-то образом! Код выглядит следующим образом:
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));
}
В настоящее время он принимает следующие глобальные переменные: mg - MatrixGrabber с текущей областью просмотра матриц - float[4] с областью просмотра ({x, y, width, height})
Переменные, которые он принимает, эквивалентны тем, которые должен был принять gluUnProject. Например:
float[] xyz = {0, 0, 0};
xyz = unproject(mouseX, viewport[3] - mouseY, 1);
Это вернет точку под мышью, в дальней плоскости. Я также добавил функцию для преобразования между указанным расстоянием от камеры и ее 0-1... представление... вещь. Вот так:
unproject(mouseX, viewport[3] - mouseY, distanceToDepth(5));
Это вернет точку под мышкой в 5 единицах от камеры. Я проверил это с помощью метода, приведенного в вопросе - я проверил расстояние между ближней и дальней плоскостями. При fNear, равном 0,1, и fFar, равном 100, расстояние должно составлять 99,9. Насколько я могу судить, я постоянно получал около 99,8977, независимо от положения или ориентации камеры. Хаха, хорошо, что это выяснили. Дайте мне знать, если у вас есть / нет проблем с этим, или если вы хотите, чтобы я переписал его, чтобы принимать входные данные вместо использования глобальных переменных. Надеюсь, это поможет нескольким людям; Я размышлял об этом несколько дней, прежде чем всерьез попытаться это исправить.
Итак, выяснив, как это должно быть, я выяснил, чего им не хватало при реализации gluUnProject. Они забыли (не собирались и никому не сказали?) Делить на четвертый элемент результирующего вектора, который как бы нормализует вектор или что-то в этом роде. gluProject устанавливает его в 1 перед применением матриц, поэтому он должен быть равен 1, когда вы закончите отменять их. Короче говоря, вы можете использовать gluUnProject, но вам нужно передать ему значение с плавающей точкой [4], а затем разделить все полученные координаты на 4-е, например, так:
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 должен содержать соответствующие пространственные координаты. Кажется, это работает точно так же, как тот, который я собрал вместе. Это может быть немного быстрее; Я думаю, что они объединили один из шагов.