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");