Assignment 2: Rasterization & Z-buffering
19322093吴景图
作业概述
光栅化是将向量图形格式表示的图像转换成位图以用于显示器或者打印机输出的过程。目前我们的电子计算机采用栅格点阵的方式来显示图像、图形等数据,对于输入的连续信号(例如三角形),计算机会对该信号进行离散地采样。对应到三角形的光栅化过程,就是确定哪些栅格点(亦或者说像素点)被三角形覆盖了,我们会对被三角形覆盖了的像素点进行着色,从而最终在屏幕上显示出输入的三角形的形状和颜色。
构建好项目后,会有如下输出(见0.gif)
Task 1、实现Bresenham直线光栅化算法
实现TRShaderPipeline::rasterize_wire_aux
函数。
该函数在 rasterize_wire 中被调用,对三角形的每一条边都进行直线光栅化:
void TRShaderPipeline::rasterize_wire(
const VertexData &v0,
const VertexData &v1,
const VertexData &v2,
const unsigned int &screen_width,
const unsigned int &screene_height,
std::vector<VertexData> &rasterized_points)
{
//Draw each line step by step
rasterize_wire_aux(v0, v1, screen_width, screene_height, rasterized_points);
rasterize_wire_aux(v1, v2, screen_width, screene_height, rasterized_points);
rasterize_wire_aux(v0, v2, screen_width, screene_height, rasterized_points);
}
先研究VertexData
类
class VertexData
{
public:
glm::vec4 pos; //World space position
glm::vec3 col; //World space color
glm::vec3 nor; //World space normal
glm::vec2 tex; //World space texture coordinate
glm::vec4 cpos; //Clip space position
glm::ivec2 spos;//Screen space position
它定义了几个坐标,及颜色等信息,要用的应该是屏幕坐标,即spos。
再看VertexData TRShaderPipeline::VertexData::lerp
它的作用是线性插值,在两点之间,按照权值插值,得到一个新点。在这里的应用中,只需要对颜色插值,而位置计算出来的。
Bresenham 算法流程如下
考虑了dx,dy的正负,dx,dy的绝对值大小,写出了以下不太优美的代码
void TRShaderPipeline::rasterize_wire_aux(
const VertexData &from,
const VertexData &to,
const unsigned int &screen_width,
const unsigned int &screen_height,
std::vector<VertexData> &rasterized_points)
{
int x0 = from.spos.x;
int y0 = from.spos.y;
int x1 = to.spos.x;
int y1 = to.spos.y;
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
if ( abs( dx) > abs( dy) )
{
if (x0 > x1)
swap(x0, x1), swap(y0, y1);
int yy = y0;
int p = dy * 2 - dx;
auto tmp = VertexData::lerp(from, to, fabs(float(x0 - from.spos.x) / dx));
tmp.spos.x = x0;
tmp.spos.y = yy;
if (tmp.spos.x >= 0 && tmp.spos.x < screen_width && tmp.spos.y >= 0 && tmp.spos.y < screen_height)
rasterized_points.push_back(tmp);
for (int i = x0; i < x1; i++)
{
tmp = VertexData::lerp(from, to, fabs( float(i + 1 - from.spos.x ) / dx) );
tmp.spos.x = i + 1;
if (p <= 0)
p += abs( dy + dy) ;
else
{
yy += ((y1>y0 ) ? 1 : -1);
p += dy + dy - ( dx + dx);
}
tmp.spos.y = yy;
if (tmp.spos.x >= 0 && tmp.spos.x < screen_width && tmp.spos.y >= 0 && tmp.spos.y < screen_height)
rasterized_points.push_back(tmp);
}
}
else
{
if(y0 > y1)
swap(x0, x1), swap(y0, y1) ;
int xx = x0;
int p = dx + dx - dy;
auto tmp = VertexData::lerp(from, to, fabs(float(y0 - from.spos.y) / dy));
tmp.spos.x = xx;
tmp.spos.y = y0;
if (tmp.spos.x >= 0 && tmp.spos.x < screen_width && tmp.spos.y >= 0 && tmp.spos.y < screen_height)
rasterized_points.push_back(tmp);
for (int i = y0; i < y1; i++)
{
tmp = VertexData::lerp(from, to, fabs(float(i + 1 - from.spos.y) / dy));
tmp.spos.y = i + 1;
if (p <= 0)
p += abs(dx + dx);
else
{
xx += ((x1> x0) ? 1 : -1);
p += dx + dx - dy - dy;
}
tmp.spos.x = xx;
if (tmp.spos.x >= 0 && tmp.spos.x < screen_width && tmp.spos.y >= 0 && tmp.spos