我正在制作一个带有平移和缩放功能的简单绘画程序。
您可以在这里找到问题的最小再现:https://codesandbox.io/s/mouse-coords-min-repro-4rfg1v?file=/src/index.ts
问题是当我尝试在
calcMouseWorldPos()
中的鼠标坐标和“世界”坐标之间进行转换时发生了什么。由于画布的宽度为 300 个单位,因此每个角在“世界空间”中应该恰好为 +/-160(320 的一半),这意味着如果我成功地将鼠标坐标转换为世界空间,悬停在每个角上应该打印{x: +/-160, y: +/-160}
到控制台。
当我放大/缩小时,它目前是这样工作的,但是当我开始平移时,它就坏了。我来自 ThreeJS/Unreal 背景并试图学习更多底层图形编程,而这个让我有点头晕。这不应该只是一个简单的逆矩阵问题吗?我在这里做错了什么?
编辑:这是有问题的重要部分
const vertexSource = `
uniform mat3 u_viewMatrix;
attribute vec2 a_position;
attribute vec2 a_uv;
varying vec2 vUv;
void main(){
vec3 aspPos = vec3(a_position, 1.0) * u_viewMatrix;
vUv = a_uv;
gl_Position = vec4(aspPos, 1.0);
}
function updateViewMatrix(): Mat3 {
const { x, y } = offset;
const dimensions = new Vector(canvas.clientWidth / 2, canvas.clientHeight / 2);
const zoomMat = new Mat3([zoom, 0, 0, 0, zoom, 0, 0, 0, 1]);
const transMat = new Mat3([1, 0, x, 0, 1, y, 0, 0, 1]);
const aspectMat = new Mat3([
1.0 / dimensions.x, 0, 0,
0, 1.0 / dimensions.y, 0,
0, 0, 1.0
]);
viewMatrix.copy(zoomMat.multiply(aspectMat).multiply(transMat));
viewMatrixUniform.set(false, viewMatrix.data);
return viewMatrix;
}
`;
function calcMouseWorldPos(event: MouseEvent): void {
const mousePos = new Vector(event.offsetX, event.offsetY).multiplyScalar(devicePixelRatio);
const windowDimensions = new Vector(canvas.width, canvas.height);
//convert from pixels to clip space
mousePos.divide(windowDimensions).subtractScalar(0.5).multiplyScalar(2);
mousePos.y *= -1;
//convert from clip space to world space
mousePos.multiplyMat3(updateViewMatrix().clone().inverse());
console.log(mousePos.toObject());
}
计算鼠标的原始数学-> world-pos
clipSpace = ((mousePos / windowDimensions) - 0.5) * 2;
clipSpace.y *= -1;
worldSpace = mousePos * viewMatrix.inverse()
通过换出最后一行
worldSpace = mousePos * viewMatrix.inverse().transpose()
一切正常。我的矩阵库中甚至还没有原生的转置方法,但我决定尝试一下,作为最后的努力,结果证明这就是所需要的。不知道为什么需要它,因为我以前从未见过它,而且我的矩阵库的
inverse()
方法的输出与所有在线计算器的输出相匹配,但我想这里出于某种原因需要它。
现在我知道了,当有疑问时,转置!
此外,任何阅读本文的人比我更了解矩阵,我仍然很想知道为什么需要它以便我以后可以更好地直觉这样的情况,快速解释会很棒。