我有一个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的事实)
答案 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
位于平截头体的近平面时zNear
为zFar
,而当它位于远处的平面时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
现在您需要乘以zFar
或tempNear = [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}}