Я не уверен на 100%, что я понимаю вашу диаграмму, но в остальном ваш код выглядит нормально.
В большинстве математических выражений WebGL усеченная точка проходит на расстоянии -Z. Конечно, вы можете повернуть это на основе представления. Но в любом случае, если вы пропустите пространство клипа [x, y, -1] через обратную матрицу (проекция * вид), то вы получите некоторую точку дальней плоскости плоскости усечения вида. Поскольку вид вращается, эта точка перемещается вместе с усечением.
Если мы сделаем так, чтобы камера смотрела на эту стену, но с некоторым углом, то для каждого щелчка мы получим разные значения для оси Y, которые она должна быть постоянной, потому что каждая точка на этой стене находится в одной и той же позиции Y.
Нет: если вы поворачиваете камеру, вся стена будет вращаться, так что точки на ней будут вращаться.
Вот диаграмма, смотрящая сверху на усеченный вид в мировом пространстве. Вид вращается. Если clipX и clipY равны 0, то вычисляемая точка находится в центре дальней плоскости усеченного конуса (Z = 1 в пространстве клипа). Вы можете видеть, что эта точка вращается, даже если она остается на плоскости. Его положение в пространстве вида не изменится, но его положение в мировом пространстве изменится, потому что весь угол обзора эффективно поворачивается.
Конечно, вы получите другое значение для Y, если повернуть камеру.
const v3 = twgl.v3;
const m4 = twgl.m4;
const ctx = document.querySelector('canvas').getContext('2d');
const boxTop = [
[-1, 1, -1],
[-1, 1, 1],
[ 1, 1, 1],
[ 1, 1, -1],
];
function render(time) {
time *= 0.001;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
const fov = 60 * Math.PI / 180;
const ratio = ctx.canvas.clientWidth / ctx.canvas.clientHeight;
const near = 10;
const far = 40;
const projectionMatrix = m4.perspective(fov , ratio, near, far);
const viewMatrix = m4.rotationY(time);
// convert to clip space
const xClipSpace = 0;
const yClipSpace = 0;
const zClipSpace = 1;
// convert back from clip space to world space
const xyzVec3 = v3.create(xClipSpace ,yClipSpace ,zClipSpace);
const transform = m4.multiply(projectionMatrix, viewMatrix);
const inverse = m4.inverse(transform);
const result = m4.transformPoint(inverse, xyzVec3);
// -------------
ctx.setTransform(1, 0, 0, 1, 150.5, 75.5);
// draw origin
ctx.beginPath();
for (let i = -200; i <= 200; i += 20) {
ctx.moveTo(-400, i);
ctx.lineTo( 400, i);
ctx.moveTo(i, -400);
ctx.lineTo(i, 400);
}
ctx.strokeStyle = '#DDD';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(-400, 0);
ctx.lineTo( 400, 0);
ctx.moveTo(0, -400);
ctx.lineTo(0, 400);
ctx.strokeStyle = '#444';
ctx.stroke();
ctx.fillStyle = '#888';
ctx.fillText('x', 140, 10);
ctx.fillText('z', 5, -65);
// draw frustum
ctx.beginPath();
for (let i = 0; i < 4; ++i) {
const v0 = m4.transformPoint(inverse, boxTop[i]);
const v1 = m4.transformPoint(inverse, boxTop[(i + 1) % 4]);
drawLine(ctx, v0, v1);
}
ctx.strokeStyle = 'black';
ctx.stroke();
{
ctx.beginPath();
ctx.arc(result[0], result[2], 3, 0, Math.PI * 2);
ctx.fillStyle = 'red';
ctx.fill();
ctx.fillText(`${result[0].toFixed(2)}, ${result[2].toFixed(2)}`, result[0] + 5, result[2] + 3);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function drawLine(ctx, v0, v1) {
ctx.moveTo(v0[0], v0[2]);
ctx.lineTo(v1[0], v1[2]);
}
render();
canvas { border: 1px solid black; }
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.js"></script>