From 1cb0834ab17faa8c48e9964592ca9f52e2304cc8 Mon Sep 17 00:00:00 2001 From: ssloy Date: Mon, 26 Jan 2015 22:55:56 +0100 Subject: [PATCH] first shaders --- geometry.cpp | 5 ++-- geometry.h | 34 +++++++++++++++--------- main.cpp | 48 +++++++++++++++++----------------- model.cpp | 8 ++++-- model.h | 2 ++ our_gl.cpp | 21 ++++----------- our_gl.h | 3 +++ shaders.txt | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 138 insertions(+), 57 deletions(-) create mode 100644 shaders.txt diff --git a/geometry.cpp b/geometry.cpp index 5c9dcda8..801f58f6 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -1,7 +1,6 @@ #include "geometry.h" -template <> template <> vec<3,int> ::vec(const vec<3,float> &v) : x(int(v.x+.5)),y(int(v.y+.5)),z(int(v.z+.5)) {} +template <> template <> vec<3,int> ::vec(const vec<3,float> &v) : x(int(v.x+.5f)),y(int(v.y+.5f)),z(int(v.z+.5f)) {} template <> template <> vec<3,float>::vec(const vec<3,int> &v) : x(v.x),y(v.y),z(v.z) {} -template <> template <> vec<2,int> ::vec(const vec<2,float> &v) : x(int(v.x+.5)),y(int(v.y+.5)) {} +template <> template <> vec<2,int> ::vec(const vec<2,float> &v) : x(int(v.x+.5f)),y(int(v.y+.5f)) {} template <> template <> vec<2,float>::vec(const vec<2,int> &v) : x(v.x),y(v.y) {} - diff --git a/geometry.h b/geometry.h index d084cb03..f0ef6f3f 100644 --- a/geometry.h +++ b/geometry.h @@ -9,7 +9,7 @@ template class mat; template struct vec { - vec() { for (size_t i=DIM; i--; data_[i] = T(0)); } + vec() { for (size_t i=DIM; i--; data_[i] = T()); } T& operator[](const size_t i) { assert(i struct vec { ///////////////////////////////////////////////////////////////////////////////// template struct vec<2,T> { - vec() : x(0), y(0) {} + vec() : x(T()), y(T()) {} vec(T X, T Y) : x(X), y(Y) {} template vec<2,T>(const vec<2,U> &v); T& operator[](const size_t i) { assert(i<2); return i<=0 ? x : y; } @@ -31,7 +31,7 @@ template struct vec<2,T> { ///////////////////////////////////////////////////////////////////////////////// template struct vec<3,T> { - vec() : x(0), y(0), z(0) {} + vec() : x(T()), y(T()), z(T()) {} vec(T X, T Y, T Z) : x(X), y(Y), z(Z) {} template vec<3,T>(const vec<3,U> &v); T& operator[](const size_t i) { assert(i<3); return i<=0 ? x : (1==i ? y : z); } @@ -67,7 +67,7 @@ template vec operator*(vec lhs, } template vec operator/(vec lhs, const U& rhs) { - for (size_t i=DIM; i--; lhs[i]*=rhs); + for (size_t i=DIM; i--; lhs[i]/=rhs); return lhs; } @@ -99,7 +99,7 @@ template std::ostream& operator<<(std::ostream& out, ve template struct dt { static T det(const mat& src) { T ret=0; - for (size_t i=DIM; i--; ret += src[0][i]*src.algAdd(0,i)); + for (size_t i=DIM; i--; ret += src[0][i]*src.cofactor(0,i)); return ret; } }; @@ -127,13 +127,18 @@ template class mat { return rows[idx]; } - vec col(const size_t idx) { + vec col(const size_t idx) const { assert(idx ret; for (size_t i=DimRows; i--; ret[i]=rows[i][idx]); return ret; } + void set_col(size_t idx, vec v) { + assert(idx identity() { mat ret; for (size_t i=DimRows; i--; ) @@ -145,21 +150,21 @@ template class mat { return dt::det(*this); } - mat minor(size_t row, size_t col) const { + mat get_minor(size_t row, size_t col) const { mat ret; for (size_t i=DimRows-1; i--; ) for (size_t j=DimCols-1;j--; ret[i][j]=rows[i adjugate() const { mat ret; for (size_t i=DimRows; i--; ) - for (size_t j=DimCols; j--; ret[i][j]=algAdd(i,j)); + for (size_t j=DimCols; j--; ret[i][j]=cofactor(i,j)); return ret; } @@ -178,13 +183,18 @@ template vec operator*(cons return ret; } +templatemat operator*(const mat& lhs, const mat& rhs) { + mat result; + for (size_t i=R1; i--; ) + for (size_t j=C2; j--; result[i][j]=lhs[i]*rhs.col(j)); + return result; +} templatemat operator/(mat lhs, const T& rhs) { for (size_t i=DimRows; i--; lhs[i]=lhs[i]/rhs); return lhs; } - template std::ostream& operator<<(std::ostream& out, mat& m) { for (size_t i=0; i Vec2f; typedef vec<2, int> Vec2i; typedef vec<3, float> Vec3f; typedef vec<3, int> Vec3i; +typedef vec<4, float> Vec4f; typedef mat<4,4,float> Matrix; #endif //__GEOMETRY_H__ - diff --git a/main.cpp b/main.cpp index 290d5574..a4bef29e 100644 --- a/main.cpp +++ b/main.cpp @@ -10,41 +10,39 @@ Model *model = NULL; const int width = 800; const int height = 800; - Vec3f light_dir(1,1,1); Vec3f eye(1,1,3); Vec3f center(0,0,0); Vec3f up(0,1,0); struct Shader : public IShader { + mat<3,3,float> varying_tri; + mat<2,3,float> varying_uv; + virtual ~Shader() {} - Vec2i varying_uv[3]; - float varying_inty[3]; virtual Vec3i vertex(int iface, int nthvert) { - varying_inty[nthvert] = model->normal(iface, nthvert)*Vec3f(light_dir); - varying_uv[nthvert] = model->uv(iface, nthvert); - Vec3f gl_Vertex = model->vert(iface, nthvert); - vec<4,float> p = (Viewport*(Projection*(ModelView*embed<4>(gl_Vertex)))); - Vec3f gl_Position = proj<3>(p*(1.f/p[3])); - return Vec3i(gl_Position); + Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); + gl_Vertex = Projection*ModelView*gl_Vertex; + varying_tri.set_col(nthvert, proj<3>(gl_Vertex/gl_Vertex[3])); + + varying_uv.set_col(nthvert, model->uv(iface, nthvert)); + + gl_Vertex = Viewport*gl_Vertex; + return proj<3>(gl_Vertex/gl_Vertex[3]); } virtual bool fragment(Vec3f bar, TGAColor &color) { - Vec2i uv; - for (size_t i=3;i--;) { - uv = uv + (varying_uv[i])*bar[i]; - } - -// float inty = varying_inty[0]*bar.x + varying_inty[1]*bar.y + varying_inty[2]*bar.z; - // inty = std::max(0.f, std::min(1.f, inty)); -// color = model->diffuse(uv)*inty; + Vec2i uv = varying_uv*bar; + Vec3f n = model->normal(uv); + Vec3f reflected_light = n*(n*light_dir*2.f) - light_dir; + float diffuse_ity = std::max(n*light_dir, 0.f); + float ambient_ity = .1f; + float specular_ity = pow(std::max(reflected_light.z/reflected_light.norm(), 0.0f), model->specular(uv)); - Matrix itm = Matrix::identity();//ModelView.invert_transpose(); - vec<4,float> n = itm*embed<4>(model->normal(uv), 0.f); - Vec3f n2 = proj<3>(n).normalize(); - float inty = n2*light_dir; - color = model->diffuse(uv)*inty; + float ity = CLAMP(.1f+n*light_dir, 0.f, 1.f); + TGAColor diff = model->diffuse(uv)*ity; + for (int c=0; c<3; c++) color[c] = std::min(5 + diff[c]*(diffuse_ity + .6f*specular_ity), 255.f); return false; } @@ -56,6 +54,7 @@ int main(int argc, char** argv) { } else { model = new Model("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()); @@ -63,6 +62,7 @@ int main(int argc, char** argv) { TGAImage image (width, height, TGAImage::RGB); TGAImage zbuffer(width, height, TGAImage::GRAYSCALE); + Shader shader; for (int i=0; infaces(); i++) { Vec3i screen_coords[3]; @@ -71,10 +71,10 @@ int main(int argc, char** argv) { } triangle(screen_coords, shader, image, zbuffer); } - image.flip_vertically(); - image.write_tga_file("output.tga"); + 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"); delete model; diff --git a/model.cpp b/model.cpp index f16dc7bf..f83cf2bc 100644 --- a/model.cpp +++ b/model.cpp @@ -3,7 +3,7 @@ #include #include "model.h" -Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffusemap_(), normalmap_() { +Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffusemap_(), normalmap_(), specularmap_() { std::ifstream in; in.open (filename, std::ifstream::in); if (in.fail()) return; @@ -41,6 +41,7 @@ Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffus std::cerr << "# v# " << verts_.size() << " f# " << faces_.size() << " vt# " << uv_.size() << " vn# " << norms_.size() << std::endl; load_texture(filename, "_diffuse.tga", diffusemap_); load_texture(filename, "_nm.tga", normalmap_); + load_texture(filename, "_spec.tga", specularmap_); } Model::~Model() {} @@ -94,8 +95,11 @@ Vec2i Model::uv(int iface, int nthvert) { return Vec2i(uv_[idx][0]*diffusemap_.get_width(), uv_[idx][1]*diffusemap_.get_height()); } +float Model::specular(Vec2i uv) { + return specularmap_.get(uv.x, uv.y)[0]/1.f; +} + Vec3f Model::normal(int iface, int nthvert) { int idx = faces_[iface][nthvert][2]; return norms_[idx].normalize(); } - diff --git a/model.h b/model.h index e89647ea..4bca0d0b 100644 --- a/model.h +++ b/model.h @@ -14,6 +14,7 @@ class Model { std::vector uv_; TGAImage diffusemap_; TGAImage normalmap_; + TGAImage specularmap_; void load_texture(std::string filename, const char *suffix, TGAImage &img); public: Model(const char *filename); @@ -26,6 +27,7 @@ class Model { Vec3f vert(int iface, int nthvert); Vec2i uv(int iface, int nthvert); TGAColor diffuse(Vec2i uv); + float specular(Vec2i uv); std::vector face(int idx); }; diff --git a/our_gl.cpp b/our_gl.cpp index 8cc44385..90179234 100644 --- a/our_gl.cpp +++ b/our_gl.cpp @@ -34,14 +34,6 @@ void lookat(Vec3f eye, Vec3f center, Vec3f up) { } } - -Vec3f barycentric(Vec3i A, Vec3i B, Vec3i C, Vec3i P) { - Vec3f u = cross(Vec3f(C[0]-A[0], B[0]-A[0], A[0]-P[0]),Vec3f(C[1]-A[1], B[1]-A[1], A[1]-P[1])); - return std::abs(u[2])>.5 ? Vec3f(1.f-(u[0]+u[1])/u[2], u[1]/u[2], u[0]/u[2]) : Vec3f(-1,1,1); // dont forget that u[2] is an integer. If it is zero then triangle ABC is degenerate -} - -/* - Vec3f barycentric(Vec3i A, Vec3i B, Vec3i C, Vec3i P) { Vec3i s[2]; for (int i=2; i--; ) { @@ -50,13 +42,10 @@ Vec3f barycentric(Vec3i A, Vec3i B, Vec3i C, Vec3i P) { s[i][2] = A[i]-P[i]; } Vec3f u = cross(s[0], s[1]); - if (std::abs(u[2])>1e-2) { - u = u*(1./u.z); - return u; - } - return Vec3f(-1,1,1); + if (std::abs(u[2])>1e-2) // dont forget that u[2] is integer. If it is zero then triangle ABC is degenerate + return Vec3f(1.f-(u.x+u.y)/u.z, u.y/u.z, u.x/u.z); + return Vec3f(-1,1,1); // in this case generate negative coordinates, it will be thrown away by the rasterizator } -*/ void triangle(Vec3i *pts, IShader &shader, TGAImage &image, TGAImage &zbuffer) { Vec2i bboxmin( std::numeric_limits::max(), std::numeric_limits::max()); @@ -68,12 +57,12 @@ void triangle(Vec3i *pts, IShader &shader, TGAImage &image, TGAImage &zbuffer) { } } Vec3i P; + TGAColor color; for (P[0]=bboxmin[0]; P[0]<=bboxmax[0]; P[0]++) { for (P[1]=bboxmin[1]; P[1]<=bboxmax[1]; P[1]++) { Vec3f c = barycentric(pts[0], pts[1], pts[2], P); - P[2] = std::max(0, std::min(255, int(pts[0][2]*c[0] + pts[1][2]*c[1] + pts[2][2]*c[2] + .5))); // clamping to 0-255 since it is stored in unsigned char + P[2] = std::max(0, std::min(255, int(pts[0].z*c[0] + pts[1].z*c[1] + pts[2].z*c[2] + .5))); // clamping to 0-255 since it is stored in unsigned char if (c[0]<0 || c[1]<0 || c[2]<0 || zbuffer.get(P[0], P[1])[0]>P[2]) continue; - TGAColor color; bool discard = shader.fragment(c, color); if (!discard) { zbuffer.set(P[0], P[1], TGAColor(P[2])); diff --git a/our_gl.h b/our_gl.h index 3db8c1f1..c591e4b9 100644 --- a/our_gl.h +++ b/our_gl.h @@ -19,5 +19,8 @@ struct IShader { }; void triangle(Vec3i *pts, IShader &shader, TGAImage &image, TGAImage &zbuffer); +template T CLAMP(const T& value, const T& low, const T& high) { + return value < low ? low : (value > high ? high : value); +} #endif //__OUR_GL_H__ diff --git a/shaders.txt b/shaders.txt new file mode 100644 index 00000000..e8393185 --- /dev/null +++ b/shaders.txt @@ -0,0 +1,74 @@ +struct FlatShader : public IShader { + mat<3,3,float> varying_tri; + + virtual ~FlatShader() {} + + virtual Vec3i vertex(int iface, int nthvert) { + Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); + gl_Vertex = Projection*ModelView*gl_Vertex; + varying_tri.set_col(nthvert, proj<3>(gl_Vertex/gl_Vertex[3])); + gl_Vertex = Viewport*gl_Vertex; + return proj<3>(gl_Vertex/gl_Vertex[3]); + } + + virtual bool fragment(Vec3f bar, TGAColor &color) { + Vec3f n = cross(varying_tri.col(1)-varying_tri.col(0),varying_tri.col(2)-varying_tri.col(0)).normalize(); + float intensity = CLAMP(n*light_dir, 0.f, 1.f); + color = TGAColor(255, 255, 255)*intensity; + return false; + } +}; + +struct GouraudShader : public IShader { + mat<3,3,float> varying_tri; + Vec3f varying_ity; + + virtual ~GouraudShader() {} + + virtual Vec3i vertex(int iface, int nthvert) { + Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); + gl_Vertex = Projection*ModelView*gl_Vertex; + varying_tri.set_col(nthvert, proj<3>(gl_Vertex/gl_Vertex[3])); + + varying_ity[nthvert] = CLAMP(model->normal(iface, nthvert)*light_dir, 0.f, 1.f); + + gl_Vertex = Viewport*gl_Vertex; + return proj<3>(gl_Vertex/gl_Vertex[3]); + } + + virtual bool fragment(Vec3f bar, TGAColor &color) { + float intensity = varying_ity*bar; + color = TGAColor(255, 255, 255)*intensity; + return false; + } +}; + + +struct ToonShader : public IShader { + mat<3,3,float> varying_tri; + Vec3f varying_ity; + + virtual ~ToonShader() {} + + virtual Vec3i vertex(int iface, int nthvert) { + Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); + gl_Vertex = Projection*ModelView*gl_Vertex; + varying_tri.set_col(nthvert, proj<3>(gl_Vertex/gl_Vertex[3])); + + varying_ity[nthvert] = CLAMP(model->normal(iface, nthvert)*light_dir, 0.f, 1.f); + + gl_Vertex = Viewport*gl_Vertex; + return proj<3>(gl_Vertex/gl_Vertex[3]); + } + + virtual bool fragment(Vec3f bar, TGAColor &color) { + float intensity = varying_ity*bar; + if (intensity>.85) intensity = 1; + else if (intensity>.60) intensity = .80; + else if (intensity>.45) intensity = .60; + else if (intensity>.30) intensity = .45; + else if (intensity>.15) intensity = .30; + color = TGAColor(255, 155, 0)*intensity; + return false; + } +};