3.0 Lession 3 z-buffer

[TOC]

参考

简单的-二维ybuffer

下面的图是二维图片,上面的是二维在一维的切面,为了看的更清晰,把1px扩展到16px。实际创建了一个数组进行buffer缓冲


void rasterize(Vec2i p0, Vec2i p1, TGAColor color, TGAImage &image, int ybuffer[]) {
    if (p0.x > p1.x) {
        std::swap(p0, p1);
    }

    for (int x = p0.x; x <= p1.x; x++) {
        float t = (x-p0.x)/(float)(p1.x-p0.x);
        //注意 + .5 进行四舍五入
        int y = p0.y*(1.-t) + p1.y*t + .5;
        if (ybuffer[x] < y) {
            ybuffer[x] = y;
            image.set(x, 0, color);
        }
    }
}


TGAImage image(800, 16, TGAImage::RGB);
int ybuffer[800];
for (int i = 0; i < 800; i++) {
    ybuffer[i] = std::numeric_limits<int>::min();
}
rasterize(Vec2i(20, 34),   Vec2i(744, 400), Red, image, ybuffer);
rasterize(Vec2i(120, 434), Vec2i(444, 400), Green, image, ybuffer);
rasterize(Vec2i(330, 463), Vec2i(594, 200), Blue, image,ybuffer);

for (int x = 0; x < 800; x++) {
    TGAColor color = image.get(x, 0);
    for (int j = 1; j < 16; j++) {
        image.set(x, j, color);
    }
}
image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
image.write_tga_file("l3_ybuffer.tga");

zbuffer


void triangle_line_sweeping_3d(Vec3i p0, Vec3i p1, Vec3i p2, TGAColor color, TGAImage &image, int* zbuffer) {
    //冒泡
    if (p0.y > p1.y) std::swap(p0, p1);
    if (p0.y > p2.y) std::swap(p0, p2);
    if (p1.y > p2.y) std::swap(p1, p2);

    std::cout << "after swap\n" << p0 << p1 << p2;

    //总高度
    int totalHeight = p2.y - p0.y + 1;
    //第一段三角形高度
    int segmentHeight_1 = p1.y - p0.y + 1;
    //第二段三角形高度
    int segmentHeight_2 = p2.y - p1.y + 1;

    std::cout << "totalHeight=" << totalHeight << " segmentHeight=" << segmentHeight_1 << "\n";
    for (int y = p0.y; y <= p2.y; y++) {
        bool isPart1 = y > p1.y - 1 ? false : true;
        float alpha = isPart1 ? ((float) (y - p0.y + 1) / segmentHeight_1) : ((float) (y - p1.y + 1) / segmentHeight_2);
        Vec3i A = isPart1 ? p0 + (p1 - p0) * alpha : p1 + (p2 - p1) * alpha;

        //注意这里beta计算变换高度是 y - p0.y + 1,最后的+1很重要
        float beta = ((float) (y - p0.y + 1) / totalHeight);
        Vec3i B = p0 + (p2 - p0) * beta;
        std::cout << "A = " << A << "B= " << B;
        if (A.x > B.x) {
            std::swap(A, B);
        }

        for (int x = A.x; x <= B.x; x++) {
            float t = (x - A.x)/(float)(B.x - A.x);
            int z = A.z * (1-t) + B.z * t + .5f;
            int bufferIdx = x + image.get_width() * y;
            if (zbuffer[bufferIdx] < z) {
                zbuffer[bufferIdx] = z;
                image.set(x, y, color);
            }
        }
    }
}


    int width = 1000;
    int height = 1000;
    int depth = 255;
    TGAImage image(width, height, TGAImage::RGB);
    Model model("../obj/african_head.obj");
    Vec3f lightDir(0,0,-1);
    int zbuffer[width * height];
    for (int i=0; i<width*height; i++) {
        zbuffer[i] = std::numeric_limits<int>::min();
    }
    for (int face=0; face < model.nfaces(); face++) {
        std::vector<int> vertIdxes = model.face(face);
        Vec3i screenCordinate[3];
        Vec3f worldCordinate[3];
        for (int vId = 0; vId < 3; vId++) {
            Vec3f v = model.vert(face, vId);
            // z映射到0-255
            screenCordinate[vId] = Vec3i ((v.x + 1.) /2. * image.get_width(), (v.y + 1.) /2. * image.get_height(), (v.z+1.)*depth/2.);
            worldCordinate[vId] = v;
        }

        Vec3f norm = (worldCordinate[2] - worldCordinate[0]) ^ (worldCordinate[1] - worldCordinate[0]);
        norm.normalize();
        float intensity = norm.dotProduct(lightDir);
        if (intensity > 0) {
            triangle_line_sweeping_3d(screenCordinate[0], screenCordinate[1], screenCordinate[2], TGAColor(intensity*255, intensity*255, intensity*255, 255), image, zbuffer);
        }
    }
    image.flip_vertically();
    image.write_tga_file("l3_zbuffer.tga");