虚拟机代码:
计算重心坐标的函数
static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector3f* v)
static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector3f* v)
{
float c1 = (x*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*y + v[1].x()*v[2].y() - v[2].x()*v[1].y()) / (v[0].x()*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*v[0].y() + v[1].x()*v[2].y() - v[2].x()*v[1].y());
float c2 = (x*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*y + v[2].x()*v[0].y() - v[0].x()*v[2].y()) / (v[1].x()*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*v[1].y() + v[2].x()*v[0].y() - v[0].x()*v[2].y());
float c3 = (x*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*y + v[0].x()*v[1].y() - v[1].x()*v[0].y()) / (v[2].x()*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*v[2].y() + v[0].x()*v[1].y() - v[1].x()*v[0].y());
return {c1,c2,c3};
}
某个像素点是否在三角形内 注意将框架中的int 变成float,否则看不到效果
static bool insideTriangle(float x, float y, const Vector3f* _v)
static bool insideTriangle(float x, float y, const Vector3f* _v)
{
// 1, get a vector
Eigen::Vector2f P;
P<< x, y;
Eigen::Vector2f AB,BC,CA,AP,BP,CP;
AB = _v[1].head(2) - _v[0].head(2);
BC = _v[2].head(2) - _v[1].head(2);
CA = _v[0].head(2) - _v[2].head(2);
AP = P - _v[0].head(2);
BP = P - _v[1].head(2);
CP = P - _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)
||
( (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);
// TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
}
光栅化三角形MASS4为提高部分
void rst::rasterizer::rasterize_triangle(const Triangle& t)
里面w_reciprocal 为推导公式的一部分,详见下面的理论参考链接,框架直接给出了公式,但自己推导发现费劲!!!
//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();
// get bounding box range
// get min and max coordinate
float minx = std::min({v[0][0], v[1][0], v[2][0]});
float maxx = std::max({v[0][0], v[1][0], v[2][0]});
float miny = std::min({v[0][1], v[1][1], v[2][1]});
float maxy = std::max({v[0][1], v[1][1], v[2][1]});
// get Integer
minx = (int)std::floor(minx);
miny = (int)std::floor(miny);
maxx = (int)std::ceil(maxx);
maxy = (int)std::ceil(maxy);
// using MASS ?
bool MSAA = true;
// traverse entail bounding box
if(MSAA){
std::vector<Eigen::Vector2f> mass4 =
{
{0.25,0.25},
{0.75,0.25},
{0.75,0.25},
{0.75,0.75}
};
for(int i = minx;i<=maxx;i++){
for(int j = miny;j<=maxy;j++){
float minDeeph = FLT_MAX;
float count = 0;
for(int k = 0;k<4;k++){
if(insideTriangle((float)i + mass4[k][0], (float)j + mass4[k][1], t.v)){
// get alpha beta gamma
count++;
float alpha,beta,gamma;
auto tup = computeBarycentric2D(i, j, t.v);
std::tie(alpha,beta,gamma) = tup;
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;
minDeeph = std::min(minDeeph, z_interpolated);
}
}
// compare z_interpolated and z_buffer
if(minDeeph < depth_buf[get_index(i,j)]){
// replace
depth_buf[get_index(i,j)] = minDeeph;
Eigen::Vector3f newColor = t.getColor() * count / 4.0;
Eigen::Vector3f newPos;
newPos<< (float)i, (float)j, minDeeph;
set_pixel(newPos, newColor);
}
}
}
}else{
for(int i = minx;i<=maxx;i++){
for(int j = miny;j<=maxy;j++){
if(insideTriangle((float)i + 0.5, (float)j + 0.5, t.v)){
// get alpha beta gamma
float alpha,beta,gamma;
auto tup = computeBarycentric2D(i, j, t.v);
std::tie(alpha,beta,gamma) = tup;
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;
// compare z_interpolated and z_buffer
if(z_interpolated < depth_buf[get_index(i,j)]){
// replace
depth_buf[get_index(i,j)] = z_interpolated;
Eigen::Vector3f newColor = t.getColor();
Eigen::Vector3f newPos;
newPos<< (float)i, (float)j, z_interpolated;
set_pixel(newPos, newColor);
}
}
}
}
}
// If so, use the following code to get the interpolated z value.
//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;
// TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
}
结果:
没有用MSAA4
使用MSAA4
理论参考链接
代码参考链接
C++/C++11中std::transform的使用
std::floor和std:ceil简述
std::tie详解