О. Я на самом деле решил проблему, вроде.
Сначала я изменяю исходный код glUnproject, чтобы иметь следующее:
public static Vec3 unProject(
float winx, float winy, float winz,
Matrix44 resultantMatrix,
int width, int height){
float[] m = new float[16],
in = new float[4],
out = new float[4];
m = Matrix44.invert(resultantMatrix.get());
in[0] = (winx / (float)width) * 2 - 1;
in[1] = (winy / (float)height) * 2 - 1;
in[2] = 2 * winz - 1;
in[3] = 1;
Matrix.multiplyMV(out, 0, m, 0, in, 0);
if (out[3]==0)
return null;
out[3] = 1/out[3];
return new Vec3(out[0] * out[3], out[1] * out[3], out[2] * out[3]);
}
Вводом к вышеприведенному будет точка в координатах усеченного проецируемого вида (т.е. экранный ввод). Например:
unProject(30, 50, 0, mvpMatrix, 800, 480)
переведет ввод с экрана (щелчок) в точке (30,50) в мировую координату, в которой находится объект. Третий параметр, winz
, фактически указывает, на какую проецируемую плоскость произошел щелчок, здесь 0 означает ближнюю Z плоскости проекции.
Я делаю функции выбора, проецируя две точки, используя вышеописанную функцию, на дальнюю и ближнюю плоскости отсечения, так:
Vec3 near = unProject(30, 50, 0, mvpMatrix, 800, 480);
Vec3 far = unProject(30, 50, 1, mvpMatrix, 800, 480); // 1 for winz means projected on the far plane
Vec3 pickingRay = Subtract(far, near); // Vector subtraction
Как только мы получим луч выбора, я просто проверяю расстояние между лучом захвата и «центром» этих «выбираемых» объектов. (конечно, у вас может быть более сложный алгоритм тестирования).