哦。我实际上解决了这个问题,有点。
我首先从 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表示投影平面的nearZ。
我制作拾取函数的方式是使用上述函数在远近裁剪平面上取消投影两个点,因此:
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
一旦我们有了拾取射线,我所做的只是测试拾取射线与那些“可拾取”对象的“中心”之间的距离。(当然,你可以有一些更复杂的测试算法)。