JS 3D 实现:三维投影

代码: https://github.com/hanai/js-d3

坐标系

3d cube

渲染

投影

将三维空间中的坐标 <x, y, z> 投影到平面上,得到投影的坐标 <x', y'>

渲染函数

遍历每一个要渲染的对象,遍历对象的各个平面,对平面各个顶点由函数 project() 计算出投影在平面上的二维坐标,依次连接平面各顶点。

function render(objects, ctx, dx, dy) {
  // Clear the previous frame
  ctx.clearRect(0, 0, 2 * dx, 2 * dy);

  // for each object
  objects.forEach(object => {
    // for each face
    object.faces.forEach(face => {
      face.forEach((vertex, vertexIdx) => {
        var P = project(vertex);

        if (vertexIdx === 0) {
          // draw the first vertex
          ctx.beginPath();
          ctx.moveTo(P.x + dx, -P.y + dy);
        } else {
          // draw the other vertices
          ctx.lineTo(P.x + dx, -P.y + dy);
        }
      });

      // close the path and draw the face
      ctx.closePath();
      ctx.stroke();
      ctx.fill();
    });
  });
}

正视图

function project(M) {
    return new Vertex2D(M.x, M.z);
}

透视图

cube project

point project

由三维空间中的顶点 M(x, y, z),我们希望的到平面上的投影 M' 的坐标 (x', z')

point in plane

如图,由截线定理可得 x' = d / y * x,故:

function project(M) {
    // Distance between the camera and the plane
    var d = 200;
    var r = d / M.y;

    return new Vertex2D(r * M.x, r * M.z);
}

其它

旋转鼠标旋转立方体

rotate cube

绑定事件 mousedownmousemove,由 event.clientXevent.clientY 可得 Δx, Δy,换算得水平旋转角度 theta 与竖直旋转角度 phi


参考