如何使用J3DIMath.js库将WebGL画布中的鼠标坐标转换为3D空间中的光线?

时间:2015-04-16 19:58:49

标签: javascript matrix 3d webgl

我有一个WebGL应用程序,我使用J3DIMatrix4类来计算模型视图透视矩阵(因为这是每个教程所做的)。

现在我想弄清楚鼠标在哪个对象上,我需要将鼠标位置转换为世界空间中的光线。我使用J3dIMath.js library和以下代码来计算我的透视矩阵

this.perspectiveMatrix = new J3DIMatrix4();
this.perspectiveMatrix.perspective(30, canvas.clientWidth / canvas.clientHeight, 1, 10000);
this.perspectiveMatrix.lookat(0,0,7, 0,0,0, 0,1,0)

当实际绘制一个物体时,我将它与物体的矩阵混合:

this.mvpMatrix.load(this.perspectiveMatrix);
this.mvpMatrix.multiply(this.mvMatrix);
this.mvpMatrix.setUniform(gl, this.u_modelViewProjMatrixLoc, false);

顶点着色器是沼泽标准

uniform mat4 u_modelViewProjMatrix;
attribute vec2 vTexCoord;
attribute vec4 vPosition;
varying vec2 v_texCoord;
void main()
{
    gl_Position = u_modelViewProjMatrix * vPosition;
    v_texCoord = vTexCoord;
}

我尝试反转透视矩阵并使用

var mat = new J3DIMatrix4()
mat.load(this.perspectiveMatrix)
mat.multiply(this.mvMatrix)
mat.invert()
var coord = new J3DIVector3(0.7, 0.5, 1)
coord.multVecMatrix(mat)
debug_log(coord)
//I picked [0.7,0.5,1] because I figured it likely represented an on-screen point in camera space.

不幸的是,这给了我一些非常奇怪的结果,如[8121,362,-8120]。我期待[4,4,6]

附近的结果更多

我认为这是因为.perspective()调用正在创建一个非仿射矩阵。我想我需要的东西更像是搅拌机的相机对象矩阵,它可以对眼球的方向和位置进行编码,但没有透视调整。

鉴于我为自己的视角和外观选择的值,我将如何构建仿射和可逆相机矩阵? (然后我将用它来计算焦点并从鼠标坐标到点击射线上的点进行映射)

将根据清晰度和长度判断解决方案(如果您依赖于除J3DIMath之外的某些外部库,则会将其添加到您的行数中)

How to get object in WebGL 3d space from a mouse click coordinate的回答大部分都是难以理解的,因为它的长度和依赖于Jax的事实)

1 个答案:

答案 0 :(得分:3)

如果你经历these tutorials,我希望他们能说清楚透视矩阵到目前为止。在你到达剪辑空间之前,还有一个除以w的区别。

所以,如果原始世界 - >剪辑空间是

tempPoint = projectionMatrix * viewMatrix * worldSpacePoint
clipSpacePoint = tempPoint / tempPoint.w

然后向后退去

tempPoint = clipSpacePoint * tempPoint.w
worldSpacePoint = inverse(projectMatrix * viewMatrix) * tempPoint

我们从projectMatrix知道,当tempPoint.w位于平截头体的近平面时zNearzFar,而当它位于远处的平面时clipX = mouseX / gl.canvas.clientWidth * 2 - 1; clipY = mouseY / gl.canvas.clientHeight * -2 + 1; // because GL is 0 at bottom clipZ = -1 (for close) +1 for (far) 。{/ p>

所以首先从鼠标向后退到3D,你必须将鼠标转换为剪辑空间(-1 + 1)。假设你有画布相对鼠标坐标

clipNear = [clipX, clipY, -1, 1];
clipFar  = [clipX, clipY,  1, 1];

所以

zNear

现在您需要乘以zFartempNear = [clipX * zNear, clipY * zNear, -zNear, zNear]; tempFar = [clipX * zFar , clipY * zFar , zFar , zFar]; 。我们本可以做到的 在第一步

J3DIVector3.prototype.multVecMatrix

或者我们可以使用一些功能。据我所知,J3DImath没有我们可以用来做的功能。

现在你回到了应用透视矩阵之后的值,所以如果你有一个摄像头,你最终可以乘以逆透视或逆视图,如果你没有从0,0查看, 0

不幸的是,据我所知,J3DIMath doesn't have a function to do this。我看到的唯一功能是w,但looking at the source该函数假设w为1,但我们可以看到上面function multVec4J3DIMatrix function(vec4, matrix) { var x = vec4[0]; var y = vec4[1]; var z = vec4[2]; var w = vec4[3]; var m = matrix.$matrix; return [ x * m.m11 + y * m.m21 + z * m.m31 + w * m.m41, x * m.m12 + y * m.m22 + z * m.m32 + w * m.m42, x * m.m13 + y * m.m23 + z * m.m33 + w * m.m43, x * m.m14 + y * m.m24 + z * m.m34 + w * m.m44, ]; } 不是1。

所以,我建议使用另一个数学库

与此同时,这段代码应该有效。

var mat = new J3DIMatrix4()
mat.load(this.perspectiveMatrix)
mat.multiply(this.mvMatrix)
mat.invert()

// from this line we see zNear and zFar
// this.perspectiveMatrix.perspective(30, canvas.clientWidth / canvas.clientHeight, 1, 10000);
zNear = 1;
zFar  = 10000;

// var coord = new J3DIVector3(0.7, 0.5, 1)
// I'm going to assume since you put 1 for z you wanted zFar
coord = [0.7 * zNear, 0.7 * zNear, zFar, zFar];
world = multVec4J3DIMatrix(coord, mat);

所以从上面的例子

{{1}}