我有一个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];
现在,您需要乘以
zFar
或J3DIVector3.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/