GAMES101作業解答-作業02-Triangles and Z-buffering
1. 題目要求
- 在屏幕上畫出一個實心三角形, 換言之,柵格化一個三角形。上一次作業中,在視口變化之后,我們調用了函數 rasterize_wireframe(const Triangle& t)。但這一次,你需要自己填寫並調用 函數 rasterize_triangle(const Triangle& t)。
- 該函數的內部工作流程如下:
-
- 創建三角形的 2 維 bounding box。
-
- 遍歷此 bounding box 內的所有像素(使用其整數索引)。然后,使用像素中 心的屏幕空間坐標來檢查中心點是否在三角形內。
-
- 如果在內部,則將其位置處的插值深度值 (interpolated depth value) 與深度 緩沖區 (depth buffer) 中的相應值進行比較。
-
- 如果當前點更靠近相機,請設置像素顏色並更新深度緩沖區 (depth buffer)。
我們需要修改的函數如下:
• rasterize_triangle(): 執行三角形柵格化算法
• static bool insideTriangle(): 測試點是否在三角形內。你可以修改此函 數的定義,這意味着,你可以按照自己的方式更新返回類型或函數參數。
因為我們只知道三角形三個頂點處的深度值,所以對於三角形內部的像素, 我們需要用插值的方法得到其深度值。我們已經為你處理好了這一部分,因為有 關這方面的內容尚未在課程中涉及。插值的深度值被儲存在變量 z_interpolated 中。
- 如果當前點更靠近相機,請設置像素顏色並更新深度緩沖區 (depth buffer)。
2. 作業解答
- 所需的實驗環境前面已經介紹了,這些題目都是基於前面的基礎或者框架,為了進一步實現各種復雜功能,我們需要理解作業意圖以及看閆老師的pdf文件和視頻,同時要完成作業需要去查閱一些網上資料。
- 本次作業主要目的是實現三角形的光柵化以及實現Z-buffer算法對三角形的遮擋。
- 關鍵部分的代碼如下所示:
// Screen space rasterization 屏幕空間光柵化
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();
// 畫出三角形所在邊界
// x_l = x_min ; x_r = x_max ; y_b = y_min ; y_t = y_max
int x_l = std::floor(std::min(v[0][0], std::min(v[1][0], v[2][0]))); //floor向下取整
int x_r = std::ceil(std::max(v[0][0], std::max(v[1][0], v[2][0]))); //ceil向上取整
int y_b = std::floor(std::min(v[0][1], std::min(v[1][1], v[2][1])));
int y_t = std::ceil(std::max(v[0][1], std::max(v[1][1], v[2][1])));
for (int x = x_l; x <= x_r; x++)
for (int y = y_b; y <= y_t; y++) {
if (insideTriangle(x + 0.5, y + 0.5, t.v)) {
auto[alpha, beta, gamma] = computeBarycentric2D((float) x + 0.5f, (float) y + 0.5f, t.v); //重心坐標插值
float w_reciprocal = 1.0f / (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;
if (depth_buf[get_index(x, y)] > z_interpolated) {
Vector3f color = t.getColor();
Vector3f point(3);
point << (float) x, (float) y, z_interpolated;
depth_buf[get_index(x, y)] = z_interpolated;
set_pixel(point, color);
}
}
}
}
]// 利用叉乘以及右手定則判斷是否在三角形內部方法
static bool insideTriangle(int x, int y, const Vector3f* _v)
{
Vector2f point(x, y);
Vector2f AB = _v[1].head(2) - _v[0].head(2);
Vector2f BC = _v[2].head(2) - _v[1].head(2);
Vector2f CA = _v[0].head(2) - _v[2].head(2);
Vector2f AP = point - _v[0].head(2);
Vector2f BP = point - _v[1].head(2);
Vector2f CP = point - _v[2].head(2);
return AB[0] * AP[1] - AB[1] * AP[0] > 0
&& BC[0] * BP[1] - BC[1] * BP[0] > 0
&& CA[0] * CP[1] - CA[1] * CP[0] > 0;
}
- 實驗結果
與實驗文檔中的圖是反的,這個坐標系的選取問題,不影響結果。