js 实现简单的3D立方体

const canvas = document.querySelector('#canvas');
      const ctx = canvas.getContext('2d');
      // canvas.width = window.innerWidth;
      // canvas.height = window.innerHeight;
      const vertices = [
        [-1, -1, -1],
        [1, -1, -1],
        [1, 1, -1],
        [-1, 1, -1],
        [-1, -1, 1],
        [1, -1, 1],
        [1, 1, 1],
        [-1, 1, 1]
      ];

      const faces = [
        [0, 1, 2, 3], // back
        [4, 5, 6, 7], // front
        [0, 1, 5, 4], // bottom
        [2, 3, 7, 6], // top
        [0, 3, 7, 4], // left
        [1, 2, 6, 5]  // right
      ];
      function multiplyMatrix (b, a) {
        // 检查矩阵 a 和 b 的维度是否匹配
        if (a[0].length !== b.length) {
          throw new Error("矩阵 a 的列数必须等于矩阵 b 的行数");
        }

        // 初始化结果矩阵
        const result = new Array(a.length); // 结果矩阵的行数等于 a 的行数
        for (let i = 0; i < result.length; i++) {
          result[i] = new Array(b[0].length).fill(0); // 结果矩阵的列数等于 b 的列数
        }

        // 矩阵乘法
        for (let i = 0; i < a.length; i++) { // 遍历 a 的每一行
          for (let j = 0; j < b[0].length; j++) { // 遍历 b 的每一列
            let sum = 0;
            for (let k = 0; k < a[0].length; k++) { // 遍历 a 的列和 b 的行
              sum += a[i][k] * b[k][j];
            }
            result[i][j] = sum;
          }
        }

        return result;
      }

      function rotateX (matrix, angle) {
        const cos = Math.cos(angle);
        const sin = Math.sin(angle);
        const rotationX = [
          [1, 0, 0],
          [0, cos, -sin],
          [0, sin, cos]
        ];
        return multiplyMatrix(rotationX, matrix);
      }

      function rotateY (matrix, angle) {
        const cos = Math.cos(angle);
        const sin = Math.sin(angle);
        const rotationY = [
          [cos, 0, sin],
          [0, 1, 0],
          [-sin, 0, cos]
        ];
        return multiplyMatrix(rotationY, matrix);
      }

      function rotateZ (matrix, angle) {
        const cos = Math.cos(angle);
        const sin = Math.sin(angle);
        const rotationZ = [
          [cos, -sin, 0],
          [sin, cos, 0],
          [0, 0, 1]
        ];
        return multiplyMatrix(rotationZ, matrix);
      }

      function translate (matrix, x, y, z) {
        const translation = [
          [1, 0, 0, x],
          [0, 1, 0, y],
          [0, 0, 1, z],
          [0, 0, 0, 1]
        ];
        return multiplyMatrix(translation, matrix);
      }

      function perspectiveProjection (matrix, fov, aspect, near, far) {
        const f = 1.0 / Math.tan(fov / 2);
        const rangeInv = 1.0 / (near - far);
        const projection = [
          [f / aspect, 0, 0, 0],
          [0, f, 0, 0],
          [0, 0, (near + far) * rangeInv, 2 * near * far * rangeInv],
          [0, 0, -1, 0],
          [0, 0, 0, -1]
        ];
        return multiplyMatrix(projection, matrix);
      }

      function project (vertex) {
        const fov = Math.PI / 4; // Field of view
        const aspect = canvas.width / canvas.height;
        const near = 0.1;
        const far = 200;

        let point = [...vertex, 1];
        point = perspectiveProjection([point], fov, aspect, near, far)[0];

        // Normalize
        const w = point[3];
        const x = (point[0] / w + 1) * canvas.width / 16 + canvas.width / 2;
        const y = (-point[1] / w + 1) * canvas.height / 16 + canvas.height / 2;

        return [x, y];
      }

      function draw () {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Apply transformations
        let transformedVertices = vertices.map(v => [...v]);
        transformedVertices = transformedVertices.map(v => rotateX([v], angleX)[0]);
        transformedVertices = transformedVertices.map(v => rotateY([v], angleY)[0]);
        transformedVertices = transformedVertices.map(v => rotateZ([v], angleZ)[0]);
        transformedVertices = transformedVertices.map(v => translate([[...v, 0]], 0, 0, 5)[0]);

        // Project vertices to 2D
        const projectedVertices = transformedVertices.map(v => project(v));

        // Draw faces
        faces.forEach(face => {
          ctx.beginPath();
          face.forEach((vertexIndex, i) => {
            const [x, y] = projectedVertices[vertexIndex];
            ctx.fillText(vertexIndex + '', x, y)
            if (i === 0) {
              ctx.moveTo(x, y);
            } else {
              ctx.lineTo(x, y);
            }
          });
          ctx.closePath();
          ctx.stroke();
        });

        requestAnimationFrame(draw);
      }

      let angleX = 0;
      let angleY = 0;
      let angleZ = 0;

      document.addEventListener('mousemove', (e) => {
        angleX = (e.clientY / canvas.height - 0.5) * Math.PI;
        angleY = (e.clientX / canvas.width - 0.5) * Math.PI;
      });

      draw();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值