光栅化三角形
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();
std::vector<float> bb(4,INT_MAX);
bb[0]=bb[1]=INT_MIN;
for(int i=0;i<3;i++){
bb[0]=std::max(float(v[i][0]),float(bb[0]));
bb[1]=std::max(float(v[i][1]),float(bb[1]));
bb[2]=std::min(float(v[i][0]),float(bb[2]));
bb[3]=std::min(float(v[i][1]),float(bb[3]));
}
bb[0]=std::ceil(bb[0]); //max x,means right;
bb[1]=std::ceil(bb[1]); //max y,means top;
bb[2]=std::floor(bb[2]); //min x,means left;
bb[3]=std::floor(bb[3]); //min y,means bottom;
for(float x=bb[2];x<bb[0];x++){
for(float y=bb[3];y<bb[1];y++){
if(insideTriangle(x+0.5,y+0.5,t.v)){
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;
if(z_interpolated<depth_buf[get_index(x,y)]){
depth_buf[get_index(x,y)]=z_interpolated;
set_pixel(Vector3f(x,y,1),t.getColor());
}
}
}
}
}
SSAA版
//SSAA
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();
std::vector<float> bb(4,INT_MAX);
bb[0]=bb[1]=INT_MIN;
for(int i=0;i<3;i++){
bb[0]=std::max(float(v[i][0]),float(bb[0]));
bb[1]=std::max(float(v[i][1]),float(bb[1]));
bb[2]=std::min(float(v[i][0]),float(bb[2]));
bb[3]=std::min(float(v[i][1]),float(bb[3]));
}
bb[0]=std::ceil(bb[0]); //max x,means right;
bb[1]=std::ceil(bb[1]); //max y,means top;
bb[2]=std::floor(bb[2]); //min x,means left;
bb[3]=std::floor(bb[3]); //min y,means bottom;
for(float x=bb[2];x<bb[0];x++){
for(float y=bb[3];y<bb[1];y++){
float cnt=0;
for(float i=x+0.25;i<x+1;i+=0.5){
for(float j=y+0.25;j<y+1;j+=0.5){
if(insideTriangle(i,j,t.v)){
cnt++;
}
}
}
if(cnt>0){
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;
if(z_interpolated<depth_buf[get_index(x,y)]){
depth_buf[get_index(x,y)]=z_interpolated;
set_pixel(Vector3f(x,y,1),t.getColor()*cnt/4);
}
}
}
}
}
首先计算Triangle的boundingbox,这步原理其实很简单,我在boudingbox应该是三维的还是二维的这个问题上纠结了一会,后来发现两个三角形都是在同一个z平面上的,就不用考虑z轴方向了。此处的最大值要向上取整celi,最小值向下取整floor,以求得正确的空间范围。
求完boundingbox后,就要遍历区间内的每一个点,计算是否在三角形内,注意此时要取每个像素的中点判断该像素的位置,
4XSSAA:将每个点分为四个点,分别计算其是否在三角形内,若有n个在,则最后将实际的颜色值设为原来值的n/4,这里会出现黑边,不知是不是插值的方法不正确,求大佬指正。
对每个点调用insideTriangle函数判断其位置是否在三角形内,代码如下
static bool insideTriangle(float x, float y,const Vector3f* _v)
{
Eigen::Vector3f p(x,y,1);
Vector3f edge[3]={_v[1]-_v[0],_v[2]-_v[1],_v[0]-_v[2]};
int last=0;
for(int i=0;i<3;i++){
auto pi=p-_v[i];
float temp=edge[i][0]*pi[1]-pi[0]*edge[i][1];
if(last==1&&temp<0){
return false;
}else if(last==-1&&temp>0){
return false;
}else{
last= temp>0? 1:-1;
}
}
注意,这里将参数中的x,y改为了float,否则无法实现点的细分。
用x,y生成一个点,计算该点与三角形三条边的向量分别叉乘后得到的向量在z轴上是否一致。一致在三角形内,否则在三角形外。
無SSAA
4XSSAA