GAMES101 HW2
这里回顾GAMES101 HW2,这次作业的内容是Triangles and Z-buffering。
课程主页:
课程作业:
课程视频:
参考资料:
- https://www.cnblogs.com/zzysmemory/p/14655679.html
- https://github.com/MARMOTatZJU/GAMES101-HW/blob/master/hw2/rasterizer.cpp
- https://github.com/kingiluob/Games101/blob/master/Assignment2/main.cpp
整体流程
算法的整体流程如下:
- for (each triangle T)
- for (each sample (x,y,z) in T)
- if (z < zbuffer[x,y]) // closest sample so far
- framebuffer[x,y] = rgb; // update color
- zbuffer[x,y] = z; // update depth
- else
;- // do nothing, this sample is occluded
- if (z < zbuffer[x,y]) // closest sample so far
- for (each sample (x,y,z) in T)
我们需要实现的函数为insideTriangle和rasterize_triangle。
insideTriangle
判断点$P$是否在三角形$ABC$内的方法如下($\times $表示叉积):
注意我们需要的是叉积的$z$分量,所以$A,B,C,P$的$z$分量可以取任意值,整体代码如下:
bool judge(Eigen::Vector3f &p, Eigen::Vector3f &a, Eigen::Vector3f &b) {
Eigen::Vector3f v = (b - a).cross(p - a);
return v.z() > 0;
}
static bool insideTriangle(float x, float y, const Triangle* t)
{
// TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
// 获得3个顶点
Eigen::Vector3f p(x, y, 0.0);
Eigen::Vector3f a = (t->v)[0];
Eigen::Vector3f b = (t->v)[1];
Eigen::Vector3f c = (t->v)[2];
if (judge(p, a, b) && judge(p, b, c) && judge(p, c, a)) {
return true;
}
return false;
}
rasterize_triangle
实现之前的伪代码即可,这里将ssaa合并,利用参数$n$控制super-sampling,$n=1$即为默认情形,于是伪代码如下:
算法的整体流程如下:
//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
// 转换为齐次坐标
auto v = t.toVector4();
// TODO : Find out the bounding box of current triangle.
// bounding box
float x_min = 1e10;
float x_max = -1e10;
float y_min = 1e10;
float y_max = -1e10;
for (int i = 0; i < 3; i++) {
x_min = std::min(x_min, t.v[i](0));
x_max = std::max(x_max, t.v[i](0));
y_min = std::min(y_min, t.v[i](1));
y_max = std::max(y_max, t.v[i](1));
}
int x_min_int = int(x_min);
int x_max_int = int(x_max) + 1;
int y_min_int = int(y_min);
int y_max_int = int(y_max) + 1;
std::cout << x_min_int << " " << x_max_int << " " << width << std::endl;
std::cout << y_min_int << " " << y_max_int << " " << height << std::endl;
// ssaa
float x, y;
// 间距
float d = 1.0 / n;
for (int i = x_min_int; i <= x_max_int; i++) {
for (int j = y_min_int; j <= y_max_int; j++) {
// 记录super-sample在三角形内的数量
int cnt = 0;
// 记录块内的最小深度
float z_interpolated_min = 1e10;
// 遍历每个super-sample
for (int p = 0; p < n; p++) {
for (int q = 0; q < n; q++) {
x = i + (p + 0.5) * d;
y = j + (q + 0.5) * d;
// 在三角形内则更新cnt
if (insideTriangle(x, y, &t)) {
cnt++;
// 计算插值深度值
auto[alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);
float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
z_interpolated *= w_reciprocal;
z_interpolated_min = std::min(z_interpolated_min, z_interpolated);
}
}
}
int index = get_index(i, j);
// 越小越近
if (z_interpolated_min < depth_buf[index]) {
// 设置颜色
Eigen::Vector3f point(i, j, 0);
set_pixel(point, t.getColor() * cnt / (n * n));
// 更新深度
depth_buf[index] = z_interpolated_min;
}
}
}
}
编译并运行,其中2, 3表示传入的$n$的值(不传入为1):
make -j4
./Rasterizer origin.png
./Rasterizer ssaa2.png 2
./Rasterizer ssaa3.png 3
结果展示:
origin.png:
ssaa2.png:
ssaa3.png:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere