通过相机位置和角度将 3D 投影到 2D 屏幕上

问题描述 投票:0回答:1

我正在研究如何将 3D 投影到 2D 屏幕,或者换句话说,采用具有 3 个坐标 (x, y, z) 的 3D 点,并获取相应的 2D 点在屏幕上绘制 (x ,y)。

我找到了这个答案,我喜欢它,并且我在代码中实现了它,但我希望能够更改相机角度。我还找到了这个答案,我理解得很部分。

我目前只能更改 3D 空间中的相机位置,但不能更改角度。至于我的代码是什么,就是这样,它是用 Python 编写的,我在 Casio Graph 90+E 计算器上进行编码,所以我只能访问几个函数(我还制作了一个小型 2D 图形模块)用于绘制基元形状的简单函数,但不关心它,因为我只是在寻找简单的 3D 点):

  • set_pixel(x, y, RGB color),将屏幕上的特定像素设置为指定的RGB颜色
  • get_pixel(x, y),返回屏幕像素的颜色(我认为它在这里不会有用)
  • show_screen(),更新屏幕
  • 和clear_screen(),它将屏幕清除为白色
    from casioplot import * #this is the calculator's graphics library
    
    
    points = [
        (-5, -5, 5),
        (5, -5, 5),
        (5, 5, 5),
        (-5, 5, 5),
        (-5, -5, 15),
        (5, -5, 15),
        (5, 5, 15),
        (-5, 5, 15)
    ] #simple square corners coordinates
    
    
    def threeDToTwoD(point, cam):
        f = point[2] - cam[2]
        x = (point[0] - cam[0]) * (f / point[2]) + cam[0]
        y = (point[1] - cam[1]) * (f / point[2]) + cam[1]
        return (round(x), round(y)) #the rounding is because I need integer coordinates for setting the pixel
    
    
    cam = [0, 0, 0]
    while True:
        clear_screen()
        for point in points:
            x, y = threeDToTwoD(point, cam)
            set_pixel(191 + x, 96 - y, (0, 0, 0))
        show_screen()
        cam[2] -= 1 #to move towards the points
python math 3d projection
1个回答
0
投票

我用 JavaScript 制作了这个小提琴,但这只是为了演示数学,所以它可以进行调整。 https://jsfiddle.net/ue0am6fs/

它演示了如何使用 3D 变换矩阵来旋转立方体(相机的角度将定义您使用的矩阵)。在小提琴中实现的唯一变换是围绕 X 和 Y 轴的旋转,例如:

function createXRotationMatrix(angle) {
  return [
  [1, 0, 0, 0],
  [0, Math.cos(angle), Math.sin(angle), 0],
  [0, -Math.sin(angle), Math.cos(angle), 0],
  [0, 0, 0, 1]
]

但是您可以实现其他形式的 3D 变换并将它们与矩阵乘法结合起来:

function multiplyMatrix(a, b) {
  const c = [[],[],[],[]];
  for (let x = 0; x < 4; x++) {
    for (let y = 0; y < 4; y++) {
      let acc = 0;
      for (let n = 0; n < 4; n++) {
        acc += a[n][x] * b[y][n];
      }
      c[y][x] = acc;
    }
  }
  return c;
}

然后可以通过将点乘以矩阵来变换点。

function multiplyPointByMatrix(matrix, point) {
  return [
  (point[0] * matrix[0][0]) + (point[1] * matrix[0][1]) + (point[2] * matrix[0][2]) + (1 * matrix[0][3]),
  (point[0] * matrix[1][0]) + (point[1] * matrix[1][1]) + (point[2] * matrix[1][2]) + (1 * matrix[1][3]),
  (point[0] * matrix[2][0]) + (point[1] * matrix[2][1]) + (point[2] * matrix[2][2]) + (1 * matrix[2][3])
  ]
}

点变换后,您可以使用 set_pixel 命令通过计算长度并沿线插值来绘制它们。

function drawTransformedLine(a, b) {
  var ta = multiplyPointByMatrix(transform, a);
  var tb = multiplyPointByMatrix(transform, b);
  var dx = ta[0] - tb[0];
  var dy = ta[1] - tb[1];
  var d = Math.sqrt(dx * dx + dy * dy);
  for (let i = 0; i <= d; i++) {
    var interpolated = lerp(ta, tb, i / d);
    set_pixel(interpolated[0], interpolated[1], [255, 0, 0]);
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.