從零開始寫光柵化渲染器3:三角形光柵化
阿新 • • 發佈:2018-12-30
1.平底三角形光柵化
我們已經知道如何繪製一條2D直線,接下來我們開始繪製實心三角形。其實原理比較簡單,如下圖是一個平底三角形,V2.y==V3.y,所以我們只要沿著三角形的兩條邊不斷畫直線,就可以將三角形填滿。首先我們必須確定每條直線的左右兩個點,即
所以
當得到
2.一般三角形的繪製
一般三角形如下圖所示,我們可以將其劃分為一個平底三角形(
程式碼如下:
struct Scanline
{
Scanline(const Vertex &v_,const Vertex &Step_,int x_,int y_,float width_):v(v_),step(Step_),x(x_),y(y_),width(width_){}
Vertex v;
Vertex step;
int x;
int y;
float width;
};
void sort_vertex(Vertex &v1,Vertex &v2,Vertex &v3)
{
if (v1.position.y>v2.position.y || (v1.position.y==v2.position.y&&v1.position.x>v2.position.x) )
{
swap(v1,v2);
}
if (v2.position.y>v3.position.y || (v2.position.y==v3.position.y&&v2.position .x>v3.position.x) )
{
swap(v2,v3);
}
if (v1.position.y>v2.position.y || (v1.position.y==v2.position.y&&v1.position.x>v2.position.x) )
{
swap(v1,v2);
}
}
Scanline generate_scanline(Vertex vl,Vertex vr)
{
float width = vr.position.x - vl.position.x;
int startX = vl.position.x+0.5;
Vertex step((vr.position-vl.position)/width,(vr.normal-vl.normal)/width,(vr.color-vl.color)/width,(vr.u-vl.u)/width,(vr.v-vl.v)/width);
return Scanline(vl,step,startX,vl.position.y+0.5,width);
}
void draw_scanline(Vertex vl,Vertex vr)
{
Scanline scanline = generate_scanline(vl,vr);
int lenght = scanline.width+0.5;
for (int i=0;i<=lenght;++i)
{
DirectX::instance().drawPixel(scanline.x+i,scanline.y,scanline.v.color);
scanline.v.add(scanline.step);
}
}
void draw_top_flat_triangle(Vertex v1,Vertex v2,Vertex v3)
{
int startY = v1.position.y + 0.5;
int endY = v3.position.y + 0.5;
for (int y=startY;y<=endY;++y)
{
float factor = static_cast<float>(y-startY)/(endY-startY);
Vertex vl = v1.interp(v3,factor);
Vertex vr = v2.interp(v3,factor);
draw_scanline(vl,vr);
}
}
void draw_button_flat_triangle(Vertex v1,Vertex v2,Vertex v3)
{
int startY = v1.position.y + 0.5;
int endY = v3.position.y + 0.5;
for (int y=startY;y<=endY;++y)
{
float factor = static_cast<float>(y-startY)/(endY-startY);
Vertex vl = v1.interp(v2,factor);
Vertex vr = v1.interp(v3,factor);
draw_scanline(vl,vr);
}
}
void draw_triangle(Vertex v1,Vertex v2,Vertex v3)
{
sort_vertex(v1,v2,v3);
if (v1.position.y==v2.position.y)
{
draw_top_flat_triangle(v1,v2,v3);
}
else if (v2.position.y==v3.position.y)
{
draw_button_flat_triangle(v1,v2,v3);
}
else
{
float factor = (v2.position.y-v1.position.y)/(v3.position.y-v1.position.y);
Vertex v4 = v1.interp(v3,factor);
if (v4.position.x<v2.position.x)
{
swap(v4,v2);
}
draw_button_flat_triangle(v1,v2,v4);
draw_top_flat_triangle(v2,v4,v3);
}
}
效果圖:
專案完整地址: