-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Expand file tree
/
Copy pathmain.cpp
More file actions
80 lines (69 loc) · 4.07 KB
/
main.cpp
File metadata and controls
80 lines (69 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include "our_gl.h"
#include "model.h"
extern mat<4,4> ModelView, Perspective; // "OpenGL" state matrices and
extern std::vector<double> zbuffer; // the depth buffer
struct PhongShader : IShader {
const Model &model;
vec4 l; // light direction in eye coordinates
vec2 varying_uv[3]; // triangle uv coordinates, written by the vertex shader, read by the fragment shader
vec4 varying_nrm[3]; // normal per vertex to be interpolated by the fragment shader
vec4 tri[3]; // triangle in view coordinates
PhongShader(const vec3 light, const Model &m) : model(m) {
l = normalized((ModelView*vec4{light.x, light.y, light.z, 0.})); // transform the light vector to view coordinates
}
virtual vec4 vertex(const int face, const int vert) {
varying_uv[vert] = model.uv(face, vert);
varying_nrm[vert] = ModelView.invert_transpose() * model.normal(face, vert);
vec4 gl_Position = ModelView * model.vert(face, vert);
tri[vert] = gl_Position;
return Perspective * gl_Position; // in clip coordinates
}
virtual std::pair<bool,TGAColor> fragment(const vec3 bar) const {
mat<2,4> E = { tri[1]-tri[0], tri[2]-tri[0] };
mat<2,2> U = { varying_uv[1]-varying_uv[0], varying_uv[2]-varying_uv[0] };
mat<2,4> T = U.invert() * E;
mat<4,4> D = {normalized(T[0]), // tangent vector
normalized(T[1]), // bitangent vector
normalized(varying_nrm[0]*bar[0] + varying_nrm[1]*bar[1] + varying_nrm[2]*bar[2]), // interpolated normal
{0,0,0,1}}; // Darboux frame
vec2 uv = varying_uv[0] * bar[0] + varying_uv[1] * bar[1] + varying_uv[2] * bar[2];
vec4 n = normalized(D.transpose() * model.normal(uv));
vec4 r = normalized(n * (n * l)*2 - l); // reflected light direction
double ambient = .4; // ambient light intensity
double diffuse = 1.*std::max(0., n * l); // diffuse light intensity
double specular = (.5+2.*sample2D(model.specular(), uv)[0]/255.) * std::pow(std::max(r.z, 0.), 35); // specular intensity, note that the camera lies on the z-axis (in eye coordinates), therefore simple r.z, since (0,0,1)*(r.x, r.y, r.z) = r.z
TGAColor gl_FragColor = sample2D(model.diffuse(), uv);
for (int channel : {0,1,2})
gl_FragColor[channel] = std::min<int>(255, gl_FragColor[channel]*(ambient + diffuse + specular));
return {false, gl_FragColor}; // do not discard the pixel
}
};
int main(int argc, char** argv) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " obj/model.obj" << std::endl;
return 1;
}
constexpr int width = 800; // output image size
constexpr int height = 800;
constexpr vec3 light{ 1, 1, 1}; // light source
constexpr vec3 eye{-1, 0, 2}; // camera position
constexpr vec3 center{ 0, 0, 0}; // camera direction
constexpr vec3 up{ 0, 1, 0}; // camera up vector
lookat(eye, center, up); // build the ModelView matrix
init_perspective(norm(eye-center)); // build the Perspective matrix
init_viewport(width/16, height/16, width*7/8, height*7/8); // build the Viewport matrix
init_zbuffer(width, height);
TGAImage framebuffer(width, height, TGAImage::RGB, {177, 195, 209, 255});
for (int m=1; m<argc; m++) { // iterate through all input objects
Model model(argv[m]); // load the data
PhongShader shader(light, model);
for (int f=0; f<model.nfaces(); f++) { // iterate through all facets
Triangle clip = { shader.vertex(f, 0), // assemble the primitive
shader.vertex(f, 1),
shader.vertex(f, 2) };
rasterize(clip, shader, framebuffer); // rasterize the primitive
}
}
framebuffer.write_tga_file("framebuffer.tga");
return 0;
}