我有一个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()调用正在创建一个非仿射矩阵。我想我需要的东西更像是Blender的相机对象矩阵,它可以对“眼球”的方向和位置进行编码,但无需进行透视调整。

给定我为透视和观察选择的值,我将如何构建仿射和可逆相机矩阵? (然后我将用它来计算焦点并从鼠标坐标映射到单击射线上的点)

将根据清晰度和长度来判断解决方案(如果您依赖于J3DIMath以外的某些外部库,那么它将添加到您的行数中)

How to get object in WebGL 3d space from a mouse click coordinate的答案由于其长度以及依赖于Jax的事实而几乎无法理解)

最佳答案

如果您通过these tutorials,我希望他们能清楚地表明透视矩阵仅适用于此。在到达剪贴空间之前,仍然会有除以w的情况。

因此,如果原始世界->剪辑空间为

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


然后往回走

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


从projectMatrix中我们知道,当tempPoint.w在视锥的近平面时为zNear,当zFar在远视平面时为zNear

因此,首先要从鼠标退回到3D,您必须将鼠标转换为剪贴空间(-1 + 1)。假设您有画布相对鼠标坐标

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)


所以

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


现在,您需要乘以zFarJ3DIVector3.prototype.multVecMatrix。我们本可以做到的
在第一步

tempNear = [clipX * zNear, clipY * zNear, -zNear, zNear];
tempFar  = [clipX * zFar , clipY * zFar ,  zFar ,  zFar];


或者我们可以使用一些功能。据我所知,J3DImath没有可以用来实现此功能的函数。

现在您返回到应用透视矩阵之后的值,因此最终可以乘以反透视或反viewPerspective(如果您有摄像机),就像您不是从0,0,0观看一样。

不幸的是,据我所知,J3DIMath doesn't have a function to do this。我看到的唯一函数是w,但是looking at the source该函数假定w将为1,但我们可以看到上面的不是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,
    ];
}


所以从上面的例子

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);

关于javascript - 如何使用J3DIMath.js库将WebGL Canvas 中的鼠标坐标转换为3D空间中的光线?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29684811/

10-16 21:58