如何在JavaScript 2D Canvas中实现3D顶点到2D顶点的投影?
3D点透视投影实现问题
我有一个Camera类,用于将3D点投影到2D平面,但不知道如何正确计算3D点的透视投影。我尝试过将x和y除以z,但我认为这不是正确的透视投影公式。我使用的是左手坐标系(示意图如下):

(X轴代表左右,Y轴代表上下,Z轴代表前后)
以下是完整代码:
JavaScript代码
function degreesToRadians(degrees) { return degrees * Math.PI / 180; } function random(min, max) { return Math.random() * (max - min) + min; } function clamp(min, max, value) { if (value < min) { value = min; } else if (value > max) { value = max; } return value; } class Camera { constructor(x = 0, y = 0, z = 0, fov = 60, rotation = { x: 0, y: 0, z: 0 }, zNear = 0.1, zFar = 1000) { this.x = x; this.y = y; this.z = z; this.fov = fov; this.rotation = rotation; this.zNear = zNear; this.zFar = zFar; } project3dPointTo2d(point) { // Fix these calculations return { x: point.x / point.z, y: point.y / point.z } } } /** * @type { HTMLCanvasElement } */ var scene = document.getElementById("scene"); var ctx = scene.getContext("2d"); var vWidth = window.innerWidth; var vHeight = window.innerHeight; var fps = 60; var updateLoop; var keysDown = []; function resizeCanvas() { vWidth = window.innerWidth; vHeight = window.innerHeight; scene.width = vWidth; scene.height = vHeight; } resizeCanvas(); var testcamera = new Camera(0, 0, -10, 60, { x: 0, y: 0, z: 0 }, 0.1, 1000); var testpoint = { x: 0, y: 0, z: 100 } function main() { // Logic if (keysDown["w"]) { testcamera.z++; } if (keysDown["s"]) { testcamera.z--; } if (keysDown["a"]) { testcamera.x--; } if (keysDown["d"]) { testcamera.x++; } var proj2dPoint = testcamera.project3dPointTo2d(testpoint); // Drawing ctx.clearRect(0, 0, vWidth, vHeight); ctx.save(); ctx.fillStyle = "#000000"; ctx.beginPath(); ctx.arc(proj2dPoint.x, proj2dPoint.y, 5, 0, Math.PI * 2); ctx.fill(); ctx.closePath(); ctx.restore(); } window.onload = function() { updateLoop = setInterval(main, 1000 / fps); } window.addEventListener("keydown", (e) => { e.preventDefault(); keysDown[e.key] = true; }); window.addEventListener("keyup", (e) => { e.preventDefault(); keysDown[e.key] = false; }); window.addEventListener("resize", (e) => { resizeCanvas(); });
CSS代码
*, *:before, *:after { font-family: roboto, Arial, Helvetica, sans-serif, system-ui; padding: 0px 0px; margin: 0px 0px; } canvas { display: block; }
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <canvas id="scene"></canvas> </body> </html>
(可以看到点出现在屏幕左上角而非中心)
内容的提问来源于stack exchange,提问作者Pete21
相关产品推荐
相关产品推荐

