JavaScript
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
const fov = 90;
const fovRad = 1 / Math.tan((fov * 0.5) * Math.PI / 180);
const cameraPos = { x: 0, y: 0, z: 0 };
function project(point) {
// point.z should be > 0 (after translation) to be in front of the camera.
return {
x: (point.x * fovRad / point.z) * width + width / 2,
y: (-point.y * fovRad / point.z) * height + height / 2
};
}
const cubeVertices = [
{ x: -1, y: -1, z: -1 },
{ x: 1, y: -1, z: -1 },
{ x: 1, y: 1, z: -1 },
{ x: -1, y: 1, z: -1 },
{ x: -1, y: -1, z: 1 },
{ x: 1, y: -1, z: 1 },
{ x: 1, y: 1, z: 1 },
{ x: -1, y: 1, z: 1 }
];
const cubeFaces = [
[0, 1, 2, 3], // back
[4, 5, 6, 7], // front
[0, 1, 5, 4], // bottom
[2, 3, 7, 6], // top
[1, 2, 6, 5], // right
[0, 3, 7, 4] // left
];
function rotateX(point, angle) {
const cos = Math.cos(angle);
const sin = Math.sin(angle);
return {
x: point.x,
y: point.y * cos - point.z * sin,
z: point.y * sin + point.z * cos
};
}
function rotateY(point, angle) {
const cos = Math.cos(angle);
const sin = Math.sin(angle);
return {
x: point.x * cos + point.z * sin,
y: point.y,
z: -point.x * sin + point.z * cos
};
}
function vectorSubtract(a, b) {
return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
}
function vectorAdd(a, b) {
return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
}
function vectorScale(v, s) {
return { x: v.x * s, y: v.y * s, z: v.z * s };
}
function crossProduct(a, b) {
return {
x: a.y * b.z - a.z * b.y,
y: a.z * b.x - a.x * b.z,
z: a.x * b.y - a.y * b.x
};
}
function dotProduct(a, b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
function normalize(v) {
const length = Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
return { x: v.x/length, y: v.y/length, z: v.z/length };
}
let angle = 0;
const lightDir = normalize({ x: 1, y: 1, z: -1 });
function draw() {
ctx.clearRect(0, 0, width,...