//ModelView变换 voidlookat(Vec3f eye, Vec3f center, Vec3f up){ Vec3f z = (eye-center).normalize(); Vec3f x = cross(up,z).normalize(); Vec3f y = cross(z,x).normalize(); ModelView = Matrix::identity(); for (int i=0; i<3; i++) { ModelView[0][i] = x[i]; ModelView[1][i] = y[i]; ModelView[2][i] = z[i]; ModelView[i][3] = -center[i]; } }
//和我们编写的一致,不用修改 Vec3f barycentric(Vec2f A, Vec2f B, Vec2f C, Vec2f P){ Vec3f s[2]; for (int i=2; i--; ) { s[i][0] = C[i]-A[i]; s[i][1] = B[i]-A[i]; s[i][2] = A[i]-P[i]; } Vec3f u = cross(s[0], s[1]); if (std::abs(u[2])>1e-2) // dont forget that u[2] is integer. If it is zero then triangle ABC is degenerate returnVec3f(1.f-(u.x+u.y)/u.z, u.y/u.z, u.x/u.z); returnVec3f(-1,1,1); // in this case generate negative coordinates, it will be thrown away by the rasterizator }
//本次使用的简单着色器,GouraudShading方式在下面会说 structGouraudShader : public IShader { Vec3f varying_intensity; // written by vertex shader, read by fragment shader
virtual Vec4f vertex(int iface, int nthvert){ //embed扩展数据到4维 Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); // read the vertex from .obj file gl_Vertex = Viewport*Projection*ModelView*gl_Vertex; // transform it to screen coordinates varying_intensity[nthvert] = std::max(0.f, model->normal(iface, nthvert)*light_dir); // get diffuse lighting intensity return gl_Vertex; }
virtualboolfragment(Vec3f bar, TGAColor &color){ float intensity = varying_intensity*bar; // interpolate intensity for the current pixel color = TGAColor(255, 255, 255)*intensity; // well duh returnfalse; // no, we do not discard this pixel } };
intmain(int argc, char** argv){ if (2==argc) { model = newModel(argv[1]); } else { model = newModel("obj/african_head.obj"); }
//准备变换矩阵 lookat(eye, center, up); viewport(width/8, height/8, width*3/4, height*3/4); projection(-1.f/(eye-center).norm()); light_dir.normalize();
image. flip_vertically(); // to place the origin in the bottom left corner of the image zbuffer.flip_vertically(); image. write_tga_file("output.tga"); zbuffer.write_tga_file("zbuffer.tga");
structShader : public IShader { Vec3f varying_intensity; // written by vertex shader, read by fragment shader mat<2,3,float> varying_uv; // same as above
virtual Vec4f vertex(int iface, int nthvert){ //uv找到顶点纹理坐标,按列赋值给矩阵 varying_uv.set_col(nthvert, model->uv(iface, nthvert)); //计算顶点的切线,找到顶点对应的光强 varying_intensity[nthvert] = std::max(0.f, model->normal(iface, nthvert)*light_dir); // get diffuse lighting intensity Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); // read the vertex from .obj file return Viewport*Projection*ModelView*gl_Vertex; // transform it to screen coordinates } virtualboolfragment(Vec3f bar, TGAColor &color){ float intensity = varying_intensity*bar; // interpolate intensity for the current pixel Vec2f uv = varying_uv*bar; // interpolate uv for the current pixel color = model->diffuse(uv)*intensity; // well duh returnfalse; // no, we do not discard this pixel } };
structShader : public IShader { mat<2,3,float> varying_uv; // same as above mat<4,4,float> uniform_M; // Projection*ModelView mat<4,4,float> uniform_MIT; // (Projection*ModelView).invert_transpose()
virtual Vec4f vertex(int iface, int nthvert){ //找到纹理坐标 varying_uv.set_col(nthvert, model->uv(iface, nthvert)); Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); // read the vertex from .obj file return Viewport*Projection*ModelView*gl_Vertex; // transform it to screen coordinates }
virtualboolfragment(Vec3f bar, TGAColor &color){ //插值纹理坐标 Vec2f uv = varying_uv*bar; // interpolate uv for the current pixel //使用世界坐标的法线,变换法线到裁剪空间 Vec3f n = proj<3>(uniform_MIT*embed<4>(model->normal(uv))).normalize(); //变换光照到裁剪空间 Vec3f l = proj<3>(uniform_M *embed<4>(light_dir )).normalize(); float intensity = std::max(0.f, n*l); color = model->diffuse(uv)*intensity; // well duh returnfalse; // no, we do not discard this pixel } };