将一个三角形绘制到像素数组中

4
我需要将三角形添加到像素数组中。以下是我的代码:
  • 表示像素的数组:[r,g,b,a,r,g,b,a,...]
  • 像素密度
  • 图像的宽度和高度
  • 我的三角形:{p0: {x: 5, y: 20}, p1: {x: 65, y: 220}, p2: {x: 10, y: 143}}
  • 三角形的颜色为{r: 100, g: 214, b: 45, a:200}
我能够使用以下代码填充我的图像:
for (let i = 0; i < pixels.length; i+=4) {
  pixels[i] = color.r;
  pixels[i+1] = color.g;
  pixels[i+2] = color.b;
  pixels[i+3] = color.a;
}

如何计算出需要填充颜色的像素?

谢谢!

编辑:也许我应该稍微解释一下。我已经成功画出了三角形的点,但是不知道如何填充区域。我还想考虑性能,并避免查看每个像素。下面是我如何绘制点的代码:

static getIndex(x, y, width) {
  return 4 * (width * y + x);
}

static drawTriangle(triangle, img) {
  for (let i = 0; i < triangle.points.length; i++) {
    let point = triangle.points[i];
    for (let a = -5; a < 6; a++) {
      let idx = this.getIndex(point.x + a, point.y, img.width);
      img.pixels[idx] = triangle.color.r;
      img.pixels[idx + 1] = triangle.color.g;
      img.pixels[idx + 2] = triangle.color.b;
      img.pixels[idx + 3] = triangle.color.a;

      idx = this.getIndex(point.x, point.y + a, img.width);
      img.pixels[idx] = triangle.color.r;
      img.pixels[idx + 1] = triangle.color.g;
      img.pixels[idx + 2] = triangle.color.b;
      img.pixels[idx + 3] = triangle.color.a;
    }
  };
}

甚至只是几何学。 - Nick stands with Ukraine
你知道吗?你可以使用画布元素通过三个lineTo调用来绘制一个三角形,然后使用getImageData从中获取图像位图。 - trincot
3
你需要创建一个填充水平线段(y,x1,x2)的例程,然后使用任何三角形光栅化算法。 - MBo
1
可能是填充三角形的算法的重复问题。 - Spektre
你的 pixels[] 组织方式并不合理,通常 2D 光栅图像是存储为 2D 像素数组而不是列表... 如果你的像素只是编码为 1D 数组,那么像素 x,y 可以通过 pixel[x+y*xs]pixel[y+x*ys] 访问,其中 xs,ys 是光栅分辨率,你需要指定它是多少... MBo 是正确的,看一下我链接的重复项以及其中的子链接... 你应该能够找到实现这个 三角形光栅化 所需的所有内容。 - Spektre
1个回答

5

我终于成功地得到了我想要的东西。我不知道三角形光栅化,感谢提供链接。

这是我的代码:

一个getIndex方法,用于在像素数组中查找x、y坐标的索引。

static getIndex(x, y, width) {
  return 4 * (width * y + x);
}

然后是一个绘图函数,用于填充x、y坐标之间的颜色。我还添加了alpha混合。

static plot(x, y, color, img) {
  let idx = this.getIndex(x, y, img.width);

  let added = [color.r, color.g, color.b, map(color.a, 0, 255, 0, 1)];
  let base = [img.pixels[idx], img.pixels[idx + 1], img.pixels[idx + 2], map(img.pixels[idx + 3], 0, 255, 0, 1)];
  let a01 = 1 - (1 - added[3]) * (1 - base[3]);

  img.pixels[idx + 0] = Math.round((added[0] * added[3] / a01) + (base[0] * base[3] * (1 - added[3]) / a01)); // red
  img.pixels[idx + 1] = Math.round((added[1] * added[3] / a01) + (base[1] * base[3] * (1 - added[3]) / a01)); // green
  img.pixels[idx + 2] = Math.round((added[2] * added[3] / a01) + (base[2] * base[3] * (1 - added[3]) / a01)); // blue
  img.pixels[idx + 3] = Math.round(map(a01, 0, 1, 0, 255));
 }

我需要能够画线:
static line(x0, y0, x1, y1, img, color) {
  x0 = Math.round(x0);
  y0 = Math.round(y0);
  x1 = Math.round(x1);
  y1 = Math.round(y1);
  var dx = Math.abs(x1 - x0);
  var dy = Math.abs(y1 - y0);
  var sx = x0 < x1 ? 1 : -1;
  var sy = y0 < y1 ? 1 : -1;
  var err = dx - dy;

  let itt = 0;
  while (true) {
    this.plot(x0, y0, color, img);
    itt ++;
    if (x0 == x1 && y0 == y1) break;
    var e2 = 2 * err;
    if (e2 > -dy) {
      err -= dy;
      x0 += sx;
    }
    if (e2 < dx) {
      err += dx;
      y0 += sy;
    }
  }
}

接下来是光栅化,我使用了以下链接:http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html

static fillTriangle(triangle, img) {
  let vertices = Array.from(triangle.points);
  vertices.sort((a, b) => a.y > b.y);
  if (vertices[1].y == vertices[2].y) {
    this.fillBottomFlatTriangle(vertices[0], vertices[1], vertices[2], img, triangle.color);
  } else if (vertices[0].y == vertices[1].y) {
    this.fillTopFlatTriangle(g, vertices[0], vertices[1], vertices[2], img, triangle.color);
  } else {
    let v4 = {
      x: vertices[0].x + float(vertices[1].y - vertices[0].y) / float(vertices[2].y - vertices[0].y) * (vertices[2].x - vertices[0].x),
      y: vertices[1].y
    };
    this.fillBottomFlatTriangle(vertices[0], vertices[1], v4, img, triangle.color);
    this.fillTopFlatTriangle(vertices[1], v4, vertices[2], img, triangle.color);
  }
}

static fillBottomFlatTriangle(v1, v2, v3, img, color) {
  let invslope1 = (v2.x - v1.x) / (v2.y - v1.y);
  let invslope2 = (v3.x - v1.x) / (v3.y - v1.y);

  let curx1 = v1.x;
  let curx2 = v1.x;

  for (let scanlineY = v1.y; scanlineY <= v2.y; scanlineY++) {
    this.line(curx1, scanlineY, curx2, scanlineY, img, color);
    curx1 += invslope1;
    curx2 += invslope2;
  }
}

static fillTopFlatTriangle(v1, v2, v3, img, color) {
  let invslope1 = (v3.x - v1.x) / (v3.y - v1.y);
  let invslope2 = (v3.x - v2.x) / (v3.y - v2.y);

  let curx1 = v3.x;
  let curx2 = v3.x;

  for (let scanlineY = v3.y; scanlineY > v1.y; scanlineY--) {
    this.line(curx1, scanlineY, curx2, scanlineY, img, color);
    curx1 -= invslope1;
    curx2 -= invslope2;
  }
}

看啊,我可以画我的三角形了。这可能不是火箭科学,但我不认为有人会认为它是“基础”的...

感谢你的帮助!


你也可以使用三角形光栅化算法来计算三角形中的平均颜色! - slaviboy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接