|
1 | 1 | #include <vector> |
| 2 | +#include <cstdlib> |
2 | 3 | #include <limits> |
3 | 4 | #include <iostream> |
4 | 5 | #include "tgaimage.h" |
|
7 | 8 | #include "our_gl.h" |
8 | 9 |
|
9 | 10 | Model *model = NULL; |
10 | | -float *shadowbuffer = NULL; |
11 | 11 |
|
12 | 12 | const int width = 800; |
13 | 13 | const int height = 800; |
14 | 14 |
|
15 | | -Vec3f light_dir(1,1,0); |
16 | | -Vec3f eye(1,1,4); |
| 15 | +Vec3f eye(1.2,-.8,3); |
17 | 16 | Vec3f center(0,0,0); |
18 | 17 | Vec3f up(0,1,0); |
19 | 18 |
|
20 | | -struct Shader : public IShader { |
21 | | - mat<4,4,float> uniform_M; // Projection*ModelView |
22 | | - mat<4,4,float> uniform_MIT; // (Projection*ModelView).invert_transpose() |
23 | | - mat<4,4,float> uniform_Mshadow; // transform framebuffer screen coordinates to shadowbuffer screen coordinates |
24 | | - mat<2,3,float> varying_uv; // triangle uv coordinates, written by the vertex shader, read by the fragment shader |
25 | | - mat<3,3,float> varying_tri; // triangle coordinates before Viewport transform, written by VS, read by FS |
26 | | - |
27 | | - Shader(Matrix M, Matrix MIT, Matrix MS) : uniform_M(M), uniform_MIT(MIT), uniform_Mshadow(MS), varying_uv(), varying_tri() {} |
| 19 | +struct ZShader : public IShader { |
| 20 | + mat<4,3,float> varying_tri; |
28 | 21 |
|
29 | 22 | virtual Vec4f vertex(int iface, int nthvert) { |
30 | | - varying_uv.set_col(nthvert, model->uv(iface, nthvert)); |
31 | | - Vec4f gl_Vertex = Viewport*Projection*ModelView*embed<4>(model->vert(iface, nthvert)); |
32 | | - varying_tri.set_col(nthvert, proj<3>(gl_Vertex/gl_Vertex[3])); |
| 23 | + Vec4f gl_Vertex = Projection*ModelView*embed<4>(model->vert(iface, nthvert)); |
| 24 | + varying_tri.set_col(nthvert, gl_Vertex); |
33 | 25 | return gl_Vertex; |
34 | 26 | } |
35 | 27 |
|
36 | | - virtual bool fragment(Vec3f bar, TGAColor &color) { |
37 | | - Vec4f sb_p = uniform_Mshadow*embed<4>(varying_tri*bar); // corresponding point in the shadow buffer |
38 | | - sb_p = sb_p/sb_p[3]; |
39 | | - int idx = int(sb_p[0]) + int(sb_p[1])*width; // index in the shadowbuffer array |
40 | | - float shadow = .3+.7*(shadowbuffer[idx]<sb_p[2]); // magic coeff to avoid z-fighting |
41 | | - Vec2f uv = varying_uv*bar; // interpolate uv for the current pixel |
42 | | - Vec3f n = proj<3>(uniform_MIT*embed<4>(model->normal(uv))).normalize(); // normal |
43 | | - Vec3f l = proj<3>(uniform_M *embed<4>(light_dir )).normalize(); // light vector |
44 | | - Vec3f r = (n*(n*l*2.f) - l).normalize(); // reflected light |
45 | | - float spec = pow(std::max(r.z, 0.0f), model->specular(uv)); |
46 | | - float diff = std::max(0.f, n*l); |
47 | | - TGAColor c = model->diffuse(uv); |
48 | | - for (int i=0; i<3; i++) color[i] = std::min<float>(20 + c[i]*shadow*(1.2*diff + .6*spec), 255); |
| 28 | + virtual bool fragment(Vec3f gl_FragCoord, Vec3f bar, TGAColor &color) { |
| 29 | + color = TGAColor(0, 0, 0); |
49 | 30 | return false; |
50 | 31 | } |
51 | 32 | }; |
52 | 33 |
|
53 | | -struct DepthShader : public IShader { |
54 | | - mat<3,3,float> varying_tri; |
55 | | - |
56 | | - DepthShader() : varying_tri() {} |
| 34 | +float max_elevation_angle(float *zbuffer, Vec2f p, Vec2f dir) { |
| 35 | + float maxangle = 0; |
| 36 | + for (float t=0.; t<1000.; t+=1.) { |
| 37 | + Vec2f cur = p + dir*t; |
| 38 | + if (cur.x>=width || cur.y>=height || cur.x<0 || cur.y<0) return maxangle; |
57 | 39 |
|
58 | | - virtual Vec4f vertex(int iface, int nthvert) { |
59 | | - Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); // read the vertex from .obj file |
60 | | - gl_Vertex = Viewport*Projection*ModelView*gl_Vertex; // transform it to screen coordinates |
61 | | - varying_tri.set_col(nthvert, proj<3>(gl_Vertex/gl_Vertex[3])); |
62 | | - return gl_Vertex; |
| 40 | + float distance = (p-cur).norm(); |
| 41 | + if (distance < 1.f) continue; |
| 42 | + float elevation = zbuffer[int(cur.x)+int(cur.y)*width]-zbuffer[int(p.x)+int(p.y)*width]; |
| 43 | + maxangle = std::max(maxangle, atanf(elevation/distance)); |
63 | 44 | } |
64 | | - |
65 | | - virtual bool fragment(Vec3f bar, TGAColor &color) { |
66 | | - Vec3f p = varying_tri*bar; |
67 | | - color = TGAColor(255, 255, 255)*(p.z/depth); |
68 | | - return false; |
69 | | - } |
70 | | -}; |
| 45 | + return maxangle; |
| 46 | +} |
71 | 47 |
|
72 | 48 | int main(int argc, char** argv) { |
73 | 49 | if (2>argc) { |
74 | 50 | std::cerr << "Usage: " << argv[0] << "obj/model.obj" << std::endl; |
75 | 51 | return 1; |
76 | 52 | } |
77 | | - |
78 | 53 | float *zbuffer = new float[width*height]; |
79 | | - shadowbuffer = new float[width*height]; |
80 | | - for (int i=width*height; --i; ) { |
81 | | - zbuffer[i] = shadowbuffer[i] = -std::numeric_limits<float>::max(); |
82 | | - } |
83 | | - |
| 54 | + for (int i=width*height; i--; zbuffer[i] = -std::numeric_limits<float>::max()); |
84 | 55 | model = new Model(argv[1]); |
85 | | - light_dir.normalize(); |
86 | 56 |
|
87 | | - { // rendering the shadow buffer |
88 | | - TGAImage depth(width, height, TGAImage::RGB); |
89 | | - lookat(light_dir, center, up); |
90 | | - viewport(width/8, height/8, width*3/4, height*3/4); |
91 | | - projection(0); |
| 57 | + TGAImage frame(width, height, TGAImage::RGB); |
| 58 | + lookat(eye, center, up); |
| 59 | + viewport(width/8, height/8, width*3/4, height*3/4); |
| 60 | + projection(-1.f/(eye-center).norm()); |
92 | 61 |
|
93 | | - DepthShader depthshader; |
94 | | - Vec4f screen_coords[3]; |
95 | | - for (int i=0; i<model->nfaces(); i++) { |
96 | | - for (int j=0; j<3; j++) { |
97 | | - screen_coords[j] = depthshader.vertex(i, j); |
98 | | - } |
99 | | - triangle(screen_coords, depthshader, depth, shadowbuffer); |
| 62 | + ZShader zshader; |
| 63 | + for (int i=0; i<model->nfaces(); i++) { |
| 64 | + for (int j=0; j<3; j++) { |
| 65 | + zshader.vertex(i, j); |
100 | 66 | } |
101 | | - depth.flip_vertically(); // to place the origin in the bottom left corner of the image |
102 | | - depth.write_tga_file("depth.tga"); |
| 67 | + triangle(zshader.varying_tri, zshader, frame, zbuffer); |
103 | 68 | } |
104 | 69 |
|
105 | | - Matrix M = Viewport*Projection*ModelView; |
106 | | - |
107 | | - { // rendering the frame buffer |
108 | | - TGAImage frame(width, height, TGAImage::RGB); |
109 | | - lookat(eye, center, up); |
110 | | - viewport(width/8, height/8, width*3/4, height*3/4); |
111 | | - projection(-1.f/(eye-center).norm()); |
112 | | - |
113 | | - Shader shader(ModelView, (Projection*ModelView).invert_transpose(), M*(Viewport*Projection*ModelView).invert()); |
114 | | - Vec4f screen_coords[3]; |
115 | | - for (int i=0; i<model->nfaces(); i++) { |
116 | | - for (int j=0; j<3; j++) { |
117 | | - screen_coords[j] = shader.vertex(i, j); |
| 70 | + for (int x=0; x<width; x++) { |
| 71 | + for (int y=0; y<height; y++) { |
| 72 | + if (zbuffer[x+y*width] < -1e5) continue; |
| 73 | + float total = 0; |
| 74 | + for (float a=0; a<M_PI*2-1e-4; a += M_PI/4) { |
| 75 | + total += M_PI/2 - max_elevation_angle(zbuffer, Vec2f(x, y), Vec2f(cos(a), sin(a))); |
118 | 76 | } |
119 | | - triangle(screen_coords, shader, frame, zbuffer); |
| 77 | + total /= (M_PI/2)*8; |
| 78 | + total = pow(total, 100.f); |
| 79 | + frame.set(x, y, TGAColor(total*255, total*255, total*255)); |
120 | 80 | } |
121 | | - frame.flip_vertically(); // to place the origin in the bottom left corner of the image |
122 | | - frame.write_tga_file("framebuffer.tga"); |
123 | 81 | } |
124 | 82 |
|
125 | | - delete model; |
| 83 | + frame.flip_vertically(); |
| 84 | + frame.write_tga_file("framebuffer.tga"); |
126 | 85 | delete [] zbuffer; |
127 | | - delete [] shadowbuffer; |
| 86 | + delete model; |
128 | 87 | return 0; |
129 | 88 | } |
130 | 89 |
|
0 commit comments