我一直在尝试实现这个博客中概述的优化栅格:https://fgiesen.wordpress.com/2013/02/10/optimizing-the-basic-rasterizer/。
在他之前的博客文章https://fgiesen.wordpress.com/2013/02/08/triangle-rasterization-in-practice/中,这种天真的方法计算了每个像素的决定因素(以重心为中心的权重)。但是他的优化版本利用了这样一个事实:对于三个点a,b,c,行列式函数。
(b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) 可以重写为
A * c.x + B * c.y + C 为
A = (a.y - b.y), B = (b.x - a.x), C = a.x * b.y - a.y * b.x. 因为在遍历过程中,点a,b是三角形上的两个点,c是唯一值变化的点。
对于任何边函数E输出相应的三角形划分的权值和点c,我们可以用离散的步骤表示x差分和y差。
E(c.x, c.y) = A * c.x + B * c.y + C所以
E(c.x + 1, c.y) - E(c.x, c.y) = A, and E(c.x, c.y + 1) - E(c.x, c.y) = B因此,在每次迭代时,我们不需要重新计算行列式,我们只需为第一个c找到三个行列式,然后将它们增量为A或B,它们对应于它们的边。
我目前正试图在我自己的栅格化器中实现这一点,但是我很快注意到了公式中的一个问题。我的三角形被输入屏幕空间中的绘图函数,所以低y值意味着高上,而在向量空间则表示低下。我想通过把公式中的每一个y值乘以-1来解释这个问题。
这给出了a,b,c行列式的下列公式:
(b.x - a.x) * (a.y - c.y) - (a.y - b.y) * (c.x - a.x)由此我得出下列A、B、C的结论:
A = b.y - a.y, B = a.x - b.x, C = b.x * a.y - a.x * b.y在我的测试中,使用这个新的行列式公式(在每个像素上计算)工作得很好。对于遍历的第一点c,它等价于
A * c.x + B * c.y + C但是,当它继续沿着三角形的边框遍历时,步长递增的行列式值与原始计算的行列式值不同步。这意味着步长A和B是错误的--这对我来说是毫无意义的。
我认为造成这个问题的唯一两个原因要么是我计算的A、B和C不正确,要么是我没有从向量空间映射到屏幕空间,以保留区域或方向。
但以防万一,这里是我所有的光栅程序代码:
帮手
typedef float* point_t;
typedef float* triangle_t;
typedef struct edge {
point_t tail, tip;
float step_x, step_y;
int is_top_left;
} edge_t;
/* ... */
/* tail is the begining of the edge (i.e a), tip is the end of the edge (b) and c is variable */
static float init_edge(edge_t* edge, point_t tail, point_t tip, point_t origin) {
edge->tail = tail;
edge->tip = tip;
edge->is_top_left = is_top_left(tail, tip);
float A = tip[1] - tail[1];
float B = tail[0] - tip[0];
float C = tip[0] * tail[1] - tail[0] * tip[1];
/* step sizes */
edge->step_x = A;
edge->step_y = B;
/* edge function output at origin */
return A * origin[0] + B * origin[1] + C;
}
static float det(point_t a, point_t b, point_t c) {
return (b[0] - a[0]) * (a[1] - c[1]) - (a[1] - b[1]) * (c[0] - a[0]);
}draw_triangle
void draw_triangle(sr_pipeline_t* pipeline, triangle_t triangle) {
/* orient triangle ccw */
point_t v0 = (point_t)malloc(sizeof(float) * pipeline->num_attr);
point_t v1 = (point_t)malloc(sizeof(float) * pipeline->num_attr);
point_t v2 = (point_t)malloc(sizeof(float) * pipeline->num_attr);
memcpy(v0, triangle, sizeof(float) * pipeline->num_attr);
memcpy(v1, triangle + pipeline->num_attr, sizeof(float) * pipeline->num_attr);
memcpy(v2, triangle + (2 * pipeline->num_attr), sizeof(float) * pipeline->num_attr);
orient_ccw(&v0, &v1, &v2);
/* find bounding box */
float min_x = /* ... */;
float min_y = /* ... */;
float max_x = /* ... */;
float max_y = /* ... */;
/* store current point */
point_t p = (point_t)calloc(pipeline->num_attr, sizeof(float));
p[0] = min_x;
p[1] = min_y;
/* grab edge information */
edge_t e01, e12, e20;
float w0 = init_edge(&e12, v1, v2, p);
float w1 = init_edge(&e20, v2, v0, p);
float w2 = init_edge(&e01, v0, v1, p);
/* rasterize */
for (p[1] = min_y; p[1] <= max_y; p[1]++) {
for (p[0] = min_x; p[0] <= max_x; p[0]++) {
/* determinant calculated at every step (I suspect these are correct) */
float s0 = det(v1, v2, p);
float s1 = det(v2, v0, p);
float s2 = det(v0, v1, p);
if ( (s0 >= 0) && (s1 >= 0) && (s2 >= 0) ) {
draw_point(pipeline, p);
}
w0 += e12.step_x;
w1 += e20.step_x;
w2 += e01.step_x;
}
w0 += e12.step_y;
w1 += e20.step_y;
w2 += e01.step_y;
}
free(v0);
free(v1);
free(v2);
free(p);
}我省略的代码和函数已经正确地验证了工作。
重申一下,我的问题是为什么w0、w1、w2的值与s0、s1、s2的值不一样?
任何帮助都是感激的,谢谢!
发布于 2022-06-13 17:16:31
与其将公式中的每个y值乘以-1,不如用(top - y)替换它们。
https://stackoverflow.com/questions/72606451
复制相似问题