Skip to content

Commit 3b7da48

Browse files
committed
working z-buffer
1 parent d9c4b14 commit 3b7da48

File tree

1 file changed

+66
-61
lines changed

1 file changed

+66
-61
lines changed

main.cpp

Lines changed: 66 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,86 +2,91 @@
22
#include <cmath>
33
#include <limits>
44
#include "tgaimage.h"
5+
#include "model.h"
56
#include "geometry.h"
67

7-
const TGAColor white = TGAColor(255, 255, 255, 255);
8-
const TGAColor red = TGAColor(255, 0, 0, 255);
9-
const TGAColor green = TGAColor(0, 255, 0, 255);
10-
const TGAColor blue = TGAColor(0, 0, 255, 255);
118
const int width = 800;
12-
const int height = 500;
9+
const int height = 800;
10+
const int depth = 255;
1311

14-
void line(Vec2i p0, Vec2i p1, TGAImage &image, TGAColor color) {
15-
bool steep = false;
16-
if (std::abs(p0.x-p1.x)<std::abs(p0.y-p1.y)) {
17-
std::swap(p0.x, p0.y);
18-
std::swap(p1.x, p1.y);
19-
steep = true;
20-
}
21-
if (p0.x>p1.x) {
22-
std::swap(p0, p1);
23-
}
24-
25-
for (int x=p0.x; x<=p1.x; x++) {
26-
float t = (x-p0.x)/(float)(p1.x-p0.x);
27-
int y = p0.y*(1.-t) + p1.y*t + .5;
28-
if (steep) {
29-
image.set(y, x, color);
30-
} else {
31-
image.set(x, y, color);
32-
}
33-
}
34-
}
12+
Model *model = NULL;
13+
int *zbuffer = NULL;
14+
Vec3f light_dir(0,0,-1);
3515

36-
void rasterize(Vec2i p0, Vec2i p1, TGAImage &image, TGAColor color, int ybuffer[]) {
37-
if (p0.x>p1.x) {
38-
std::swap(p0, p1);
39-
}
40-
for (int x=p0.x; x<=p1.x; x++) {
41-
float t = (x-p0.x)/(float)(p1.x-p0.x);
42-
int y = p0.y*(1.-t) + p1.y*t + .5;
43-
if (ybuffer[x]<y) {
44-
ybuffer[x] = y;
45-
image.set(x, 0, color);
16+
void triangle(Vec3i t0, Vec3i t1, Vec3i t2, TGAImage &image, TGAColor color, int *zbuffer) {
17+
if (t0.y==t1.y && t0.y==t2.y) return; // i dont care about degenerate triangles
18+
if (t0.y>t1.y) std::swap(t0, t1);
19+
if (t0.y>t2.y) std::swap(t0, t2);
20+
if (t1.y>t2.y) std::swap(t1, t2);
21+
int total_height = t2.y-t0.y;
22+
for (int i=0; i<total_height; i++) {
23+
bool second_half = i>t1.y-t0.y || t1.y==t0.y;
24+
int segment_height = second_half ? t2.y-t1.y : t1.y-t0.y;
25+
float alpha = (float)i/total_height;
26+
float beta = (float)(i-(second_half ? t1.y-t0.y : 0))/segment_height; // be careful: with above conditions no division by zero here
27+
Vec3i A = t0 + (t2-t0)*alpha;
28+
Vec3i B = second_half ? t1 + (t2-t1)*beta : t0 + (t1-t0)*beta;
29+
if (A.x>B.x) std::swap(A, B);
30+
for (int j=A.x; j<=B.x; j++) {
31+
float phi = B.x==A.x ? 1. : (float)(j-A.x)/(float)(B.x-A.x);
32+
Vec3i P = A + (B-A)*phi;
33+
P.x = j; P.y = t0.y+i; // a hack to fill holes (due to int cast precision problems)
34+
int idx = j+(t0.y+i)*width;
35+
if (zbuffer[idx]<P.z) {
36+
zbuffer[idx] = P.z;
37+
image.set(P.x, P.y, color); // attention, due to int casts t0.y+i != A.y
38+
}
4639
}
4740
}
4841
}
4942

5043
int main(int argc, char** argv) {
51-
{ // just dumping the 2d scene (yay we have enough dimensions!)
52-
TGAImage scene(width, height, TGAImage::RGB);
53-
54-
// scene "2d mesh"
55-
line(Vec2i(20, 34), Vec2i(744, 400), scene, red);
56-
line(Vec2i(120, 434), Vec2i(444, 400), scene, green);
57-
line(Vec2i(330, 463), Vec2i(594, 200), scene, blue);
58-
59-
// screen line
60-
line(Vec2i(10, 10), Vec2i(790, 10), scene, white);
44+
if (2==argc) {
45+
model = new Model(argv[1]);
46+
} else {
47+
model = new Model("obj/african_head.obj");
48+
}
6149

62-
scene.flip_vertically(); // i want to have the origin at the left bottom corner of the image
63-
scene.write_tga_file("scene.tga");
50+
zbuffer = new int[width*height];
51+
for (int i=0; i<width*height; i++) {
52+
zbuffer[i] = std::numeric_limits<int>::min();
6453
}
6554

66-
{
67-
TGAImage render(width, 16, TGAImage::RGB);
68-
int ybuffer[width];
69-
for (int i=0; i<width; i++) {
70-
ybuffer[i] = std::numeric_limits<int>::min();
55+
{ // draw the model
56+
TGAImage image(width, height, TGAImage::RGB);
57+
for (int i=0; i<model->nfaces(); i++) {
58+
std::vector<int> face = model->face(i);
59+
Vec3i screen_coords[3];
60+
Vec3f world_coords[3];
61+
for (int j=0; j<3; j++) {
62+
Vec3f v = model->vert(face[j]);
63+
screen_coords[j] = Vec3i((v.x+1.)*width/2., (v.y+1.)*height/2., (v.z+1.)*depth/2.);
64+
world_coords[j] = v;
65+
}
66+
Vec3f n = (world_coords[2]-world_coords[0])^(world_coords[1]-world_coords[0]);
67+
n.normalize();
68+
float intensity = n*light_dir;
69+
if (intensity>0) {
70+
triangle(screen_coords[0], screen_coords[1], screen_coords[2], image, TGAColor(intensity*255, intensity*255, intensity*255, 255), zbuffer);
71+
}
7172
}
72-
rasterize(Vec2i(20, 34), Vec2i(744, 400), render, red, ybuffer);
73-
rasterize(Vec2i(120, 434), Vec2i(444, 400), render, green, ybuffer);
74-
rasterize(Vec2i(330, 463), Vec2i(594, 200), render, blue, ybuffer);
7573

76-
// 1-pixel wide image is bad for eyes, lets widen it
74+
image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
75+
image.write_tga_file("output.tga");
76+
}
77+
78+
{ // dump z-buffer (debugging purposes only)
79+
TGAImage zbimage(width, height, TGAImage::GRAYSCALE);
7780
for (int i=0; i<width; i++) {
78-
for (int j=1; j<16; j++) {
79-
render.set(i, j, render.get(i, 0));
81+
for (int j=0; j<height; j++) {
82+
zbimage.set(i, j, TGAColor(zbuffer[i+j*width], 1));
8083
}
8184
}
82-
render.flip_vertically(); // i want to have the origin at the left bottom corner of the image
83-
render.write_tga_file("render.tga");
85+
zbimage.flip_vertically(); // i want to have the origin at the left bottom corner of the image
86+
zbimage.write_tga_file("zbuffer.tga");
8487
}
88+
delete model;
89+
delete [] zbuffer;
8590
return 0;
8691
}
8792

0 commit comments

Comments
 (0)