GAMES101 作业 02:Triangles and Z-buffering

作业 02 的实现代码:Assignment02

1. insideTriangle

static bool insideTriangle(float x, float y, const Vector3f* _v)
{   
    // TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
    Vector3f p(x, y, 1.0);
    Vector3f pa = _v[0] - p;
    Vector3f pb = _v[1] - p;
    Vector3f pc = _v[2] - p;
    Vector3f ab = _v[1] - _v[0];
    Vector3f bc = _v[2] - _v[1];
    Vector3f ca = _v[0] - _v[2];
    float paCab = pa.cross(ab)[2];
    float pbCbc = pb.cross(bc)[2];
    float pcCca = pc.cross(ca)[2];
    if (paCab > 0 && pbCbc > 0 && pcCca > 0) {
        return true;
    }
    if (paCab < 0 && pbCbc < 0 && pcCca < 0) {
        return true;
    }
    return false;
}

2. rasterize_triangle

//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();

    // TODO : Find out the bounding box of current triangle.
    auto [minX, maxX, minY, maxY] = calBoundingBox2D(v);
    // iterate through the pixel and find if the current pixel is inside the triangle
    for (int y = minY; y <= maxY; ++y) {
        for (int x = minX; x <= maxX; ++x) {
            int index = get_index(x, y);
            float minDepth = std::numeric_limits<float>::infinity();
            Vector3f pixelColor = {0.0, 0.0, 0.0};
            bool isInside = false;
            for (int di = 0; di < MSAA_N; ++di) {
                float tx = float(x) + DX[di];
                float ty = float(y) + DY[di];
                if (insideTriangle(tx, ty, t.v)) {
    // If so, use the following code to get the interpolated z value.
                    isInside = true;
                    auto[alpha, beta, gamma] = computeBarycentric2D(tx, ty, 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 (depth_sample_buf[index][di] > z_interpolated) {
                        depth_sample_buf[index][di] = z_interpolated;
                        frame_sample_buf[index][di] = t.getColor();
                    }
                }
                minDepth = std::min(minDepth, depth_sample_buf[index][di]);
                pixelColor += (frame_sample_buf[index][di] / float(MSAA_N));
            }
    // TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
            if (isInside) {
                set_pixel(Vector3f(float(x), float(y), minDepth), pixelColor);
            }
        }
    }
}

下面仔细讲解一下。

2.1. calBoundingBox2D

static std::tuple<int, int, int, int> calBoundingBox2D(const std::array<Vector4f, 3> &v) {
    int minX = int(floor(std::min(std::min(v[0][0], v[1][0]), v[2][0])));
    int maxX = int(ceil(std::max(std::max(v[0][0], v[1][0]), v[2][0])));
    int minY = int(floor(std::min(std::min(v[0][1], v[1][1]), v[2][1])));
    int maxY = int(ceil(std::max(std::max(v[0][1], v[1][1]), v[2][1])));
    return {minX, maxX, minY, maxY};
}

2.2. MSAA

2.2.1. MSAA 的一些常量

static const int MSAA_N = 2 * 2;
static const std::array<float, MSAA_N> DX, DY;

const std::array<float, rst::rasterizer::MSAA_N>
    rst::rasterizer::DX = {0.25, 0.75, 0.25, 0.75};

const std::array<float, rst::rasterizer::MSAA_N>
    rst::rasterizer::DY = {0.25, 0.25, 0.75, 0.75};

2.2.2. sampleList

对于每个像素的每个样本都需要管理颜色和深度,原来的 depth_buf 就没有用了。

std::vector<Eigen::Vector3f> frame_buf;
std::vector<std::array<Eigen::Vector3f, MSAA_N>> frame_sample_buf;

//std::vector<float> depth_buf;
std::vector<std::array<float, MSAA_N>> depth_sample_buf;

rst::rasterizer::rasterizer(int w, int h) : width(w), height(h)
{
    frame_buf.resize(w * h);
    frame_sample_buf.resize(w * h);
    //depth_buf.resize(w * h);
    depth_sample_buf.resize(w * h);
}

void rst::rasterizer::clear(rst::Buffers buff)
{
    if ((buff & rst::Buffers::Color) == rst::Buffers::Color)
    {
        std::fill(frame_buf.begin(), frame_buf.end(), Eigen::Vector3f{0, 0, 0});
        for (auto frameSampleList : frame_sample_buf) {
            std::fill(frameSampleList.begin(), frameSampleList.end(), Eigen::Vector3f{0, 0, 0});
        }
    }
    if ((buff & rst::Buffers::Depth) == rst::Buffers::Depth)
    {
        //std::fill(depth_buf.begin(), depth_buf.end(), std::numeric_limits<float>::infinity());
        for (auto depthSampleList : depth_sample_buf) {
            std::fill(depthSampleList.begin(), depthSampleList.end(), std::numeric_limits<float>::infinity());
        }
    }
}

2.2.3. MSAA 的实现

遍历每一个像素,然后遍历每个像素的每个样本;
假如样本在三角形之中,那么检查这个样本的 z 值;
假如 z 值比当前管理的 z 值小,即比原来的物品离视角更近,
那么保存样本的深度与颜色;
最后,取样本间最小的深度为此像素的深度,
样本颜色均值为此像素的颜色。

    for (int y = minY; y <= maxY; ++y) {
        for (int x = minX; x <= maxX; ++x) {
            int index = get_index(x, y);
            float minDepth = std::numeric_limits<float>::infinity();
            Vector3f pixelColor = {0.0, 0.0, 0.0};
            bool isInside = false;
            for (int di = 0; di < MSAA_N; ++di) {
                float tx = float(x) + DX[di];
                float ty = float(y) + DY[di];
                if (insideTriangle(tx, ty, t.v)) {
    // If so, use the following code to get the interpolated z value.
                    isInside = true;
                    auto[alpha, beta, gamma] = computeBarycentric2D(tx, ty, 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 (depth_sample_buf[index][di] > z_interpolated) {
                        depth_sample_buf[index][di] = z_interpolated;
                        frame_sample_buf[index][di] = t.getColor();
                    }
                }
                minDepth = std::min(minDepth, depth_sample_buf[index][di]);
                pixelColor += (frame_sample_buf[index][di] / float(MSAA_N));
            }
    // TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
            if (isInside) {
                set_pixel(Vector3f(float(x), float(y), minDepth), pixelColor);
            }

3. 运行结果

运行结果

posted @ 2020-11-27 19:32  virgilwjj  阅读(162)  评论(0编辑  收藏  举报