From 87c7dc94072db01d238af8c199ea86d83590d9d6 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Sokolov" Date: Tue, 25 Aug 2020 15:42:18 +0200 Subject: [PATCH] c++14 facelift --- CMakeLists.txt | 2 +- geometry.cpp | 7 +- geometry.h | 289 ++++++++++++++++++++++++++----------------------- main.cpp | 96 ++++++++-------- model.cpp | 84 +++++++------- model.h | 35 +++--- our_gl.cpp | 76 ++++++------- our_gl.h | 17 ++- tgaimage.h | 4 +- 9 files changed, 310 insertions(+), 300 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5bd06de..e96134b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ endfunction() enable_cxx_compiler_flag_if_supported("-Wall") enable_cxx_compiler_flag_if_supported("-Wextra") enable_cxx_compiler_flag_if_supported("-pedantic") -enable_cxx_compiler_flag_if_supported("-std=c++11") +enable_cxx_compiler_flag_if_supported("-std=c++14") enable_cxx_compiler_flag_if_supported("-O3") enable_cxx_compiler_flag_if_supported("-fopenmp") diff --git a/geometry.cpp b/geometry.cpp index 3b6b2f25..5ac61462 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+.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+.5f)),y(int(v.y+.5f)) {} -template <> template <> vec<2,float>::vec(const vec<2,int> &v) : x(v.x),y(v.y) {} +vec3 cross(const vec3 &v1, const vec3 &v2) { + return vec<3>{v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x}; +} diff --git a/geometry.h b/geometry.h index 46ee7b35..55aaaa1a 100644 --- a/geometry.h +++ b/geometry.h @@ -1,221 +1,238 @@ #ifndef __GEOMETRY_H__ #define __GEOMETRY_H__ + #include -#include #include #include -template class mat; - -template struct vec { - vec() { for (size_t i=DIM; i--; data_[i] = T()); } - T& operator[](const size_t i) { assert(i struct vec<2,T> { - 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; } - const T& operator[](const size_t i) const { assert(i<2); return i<=0 ? x : y; } - - T x,y; +template struct vec { + vec() = default; + double & operator[](const int i) { assert(i>=0 && i=0 && i struct vec<3,T> { - 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); } - const T& operator[](const size_t i) const { assert(i<3); return i<=0 ? x : (1==i ? y : z); } - float norm() { return std::sqrt(x*x+y*y+z*z); } - vec<3,T> & normalize(T l=1) { *this = (*this)*(l/norm()); return *this; } - - T x,y,z; -}; - -///////////////////////////////////////////////////////////////////////////////// - -template T operator*(const vec& lhs, const vec& rhs) { - T ret = T(); - for (size_t i=DIM; i--; ret+=lhs[i]*rhs[i]); +template double operator*(const vec& lhs, const vec& rhs) { + double ret = 0; + for (int i=n; i--; ret+=lhs[i]*rhs[i]); return ret; } - -templatevec operator+(vec lhs, const vec& rhs) { - for (size_t i=DIM; i--; lhs[i]+=rhs[i]); - return lhs; +template vec operator+(const vec& lhs, const vec& rhs) { + vec ret = lhs; + for (int i=n; i--; ret[i]+=rhs[i]); + return ret; } -templatevec operator-(vec lhs, const vec& rhs) { - for (size_t i=DIM; i--; lhs[i]-=rhs[i]); - return lhs; +template vec operator-(const vec& lhs, const vec& rhs) { + vec ret = lhs; + for (int i=n; i--; ret[i]-=rhs[i]); + return ret; } -template vec operator*(vec lhs, const U& rhs) { - for (size_t i=DIM; i--; lhs[i]*=rhs); - return lhs; +template vec operator*(const double& rhs, const vec &lhs) { + vec ret = lhs; + for (int i=n; i--; ret[i]*=rhs); + return ret; } -template vec operator/(vec lhs, const U& rhs) { - for (size_t i=DIM; i--; lhs[i]/=rhs); - return lhs; +template vec operator*(const vec& lhs, const double& rhs) { + vec ret = lhs; + for (int i=n; i--; ret[i]*=rhs); + return ret; } -template vec embed(const vec &v, T fill=1) { - vec ret; - for (size_t i=LEN; i--; ret[i]=(i vec operator/(const vec& lhs, const double& rhs) { + vec ret = lhs; + for (int i=n; i--; ret[i]/=rhs); return ret; } -template vec proj(const vec &v) { - vec ret; - for (size_t i=LEN; i--; ret[i]=v[i]); +template vec embed(const vec &v, double fill=1) { + vec ret; + for (int i=n1; i--; ret[i]=(i vec<3,T> cross(vec<3,T> v1, vec<3,T> v2) { - return vec<3,T>(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x); +template vec proj(const vec &v) { + vec ret; + for (int i=n1; i--; ret[i]=v[i]); + return ret; } -template std::ostream& operator<<(std::ostream& out, vec& v) { - for(unsigned int i=0; i std::ostream& operator<<(std::ostream& out, const vec& v) { + for (int i=0; i struct dt { - static T det(const mat& src) { - T ret=0; - for (size_t i=DIM; i--; ret += src[0][i]*src.cofactor(0,i)); - return ret; - } +template<> struct vec<2> { + vec() = default; + vec(double X, double Y) : x(X), y(Y) {} + double& operator[](const int i) { assert(i>=0 && i<2); return i==0 ? x : y; } + double operator[](const int i) const { assert(i>=0 && i<2); return i==0 ? x : y; } + double norm2() const { return (*this)*(*this) ; } + double norm() const { return std::sqrt(norm2()); } + vec & normalize() { *this = (*this)/norm(); return *this; } + + double x{}, y{}; }; -template struct dt<1,T> { - static T det(const mat<1,1,T>& src) { - return src[0][0]; - } +///////////////////////////////////////////////////////////////////////////////// + +template<> struct vec<3> { + vec() = default; + vec(double X, double Y, double Z) : x(X), y(Y), z(Z) {} + double& operator[](const int i) { assert(i>=0 && i<3); return i==0 ? x : (1==i ? y : z); } + double operator[](const int i) const { assert(i>=0 && i<3); return i==0 ? x : (1==i ? y : z); } + double norm2() const { return (*this)*(*this) ; } + double norm() const { return std::sqrt(norm2()); } + vec & normalize() { *this = (*this)/norm(); return *this; } + + double x{}, y{}, z{}; }; ///////////////////////////////////////////////////////////////////////////////// -template class mat { - vec rows[DimRows]; -public: - mat() {} +template struct dt; - vec& operator[] (const size_t idx) { - assert(idx struct mat { + vec rows[nrows] = {{}}; - const vec& operator[] (const size_t idx) const { - assert(idx& operator[] (const int idx) { assert(idx>=0 && idx& operator[] (const int idx) const { assert(idx>=0 && idx col(const size_t idx) const { - assert(idx ret; - for (size_t i=DimRows; i--; ret[i]=rows[i][idx]); + vec col(const int idx) const { + assert(idx>=0 && idx ret; + for (int i=nrows; i--; ret[i]=rows[i][idx]); return ret; } - void set_col(size_t idx, vec v) { - assert(idx &v) { + assert(idx>=0 && idx identity() { - mat ret; - for (size_t i=DimRows; i--; ) - for (size_t j=DimCols;j--; ret[i][j]=(i==j)); + static mat identity() { + mat ret; + for (int i=nrows; i--; ) + for (int j=ncols;j--; ret[i][j]=(i==j)); return ret; } - T det() const { - return dt::det(*this); + double det() const { + return dt::det(*this); } - 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 get_minor(const int row, const int col) const { + mat ret; + for (int i=nrows-1; i--; ) + for (int j=ncols-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]=cofactor(i,j)); + mat adjugate() const { + mat ret; + for (int i=nrows; i--; ) + for (int j=ncols; j--; ret[i][j]=cofactor(i,j)); return ret; } - mat invert_transpose() { - mat ret = adjugate(); - T tmp = ret[0]*rows[0]; - return ret/tmp; + mat invert_transpose() const { + mat ret = adjugate(); + return ret/(ret[0]*rows[0]); } - mat invert() { + mat invert() const { return invert_transpose().transpose(); } - mat transpose() { - mat ret; - for (size_t i=DimCols; i--; ret[i]=this->col(i)); + mat transpose() const { + mat ret; + for (int i=ncols; i--; ret[i]=this->col(i)); return ret; } }; ///////////////////////////////////////////////////////////////////////////////// -template vec operator*(const mat& lhs, const vec& rhs) { - vec ret; - for (size_t i=DimRows; i--; ret[i]=lhs[i]*rhs); +template vec operator*(const mat& lhs, const vec& rhs) { + vec ret; + for (int i=nrows; i--; ret[i]=lhs[i]*rhs); 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)); +templatemat operator*(const mat& lhs, const mat& rhs) { + mat result; + for (int i=R1; i--; ) + for (int j=C2; j--; result[i][j]=lhs[i]*rhs.col(j)); + return result; +} + +templatemat operator*(const mat& lhs, const double& val) { + mat result; + for (int i=nrows; i--; result[i] = lhs[i]*val); return result; } -templatemat operator/(mat lhs, const T& rhs) { - for (size_t i=DimRows; i--; lhs[i]=lhs[i]/rhs); - return lhs; +templatemat operator/(const mat& lhs, const double& val) { + mat result; + for (int i=nrows; i--; result[i] = lhs[i]/val); + return result; } -template std::ostream& operator<<(std::ostream& out, mat& m) { - for (size_t i=0; imat operator+(const mat& lhs, const mat& rhs) { + mat result; + for (int i=nrows; i--; ) + for (int j=ncols; j--; result[i][j]=lhs[i][j]+rhs[i][j]); + return result; +} + +templatemat operator-(const mat& lhs, const mat& rhs) { + mat result; + for (int i=nrows; i--; ) + for (int j=ncols; j--; result[i][j]=lhs[i][j]-rhs[i][j]); + return result; +} + +template std::ostream& operator<<(std::ostream& out, const mat& m) { + for (int 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; +template struct dt { + static double det(const mat& src) { + double ret = 0; + for (int i=n; i--; ret += src[0][i]*src.cofactor(0,i)); + return ret; + } +}; + +template<> struct dt<1> { + static double det(const mat<1,1>& src) { + return src[0][0]; + } +}; + +///////////////////////////////////////////////////////////////////////////////// + +typedef vec<2> vec2; +typedef vec<3> vec3; +typedef vec<4> vec4; +typedef mat<4,4> mat44; +vec3 cross(const vec3 &v1, const vec3 &v2); + #endif //__GEOMETRY_H__ diff --git a/main.cpp b/main.cpp index 9b349e66..65c5a3f0 100644 --- a/main.cpp +++ b/main.cpp @@ -1,61 +1,64 @@ #include #include #include +#include #include "tgaimage.h" #include "model.h" #include "geometry.h" #include "our_gl.h" -const int width = 800; -const int height = 800; +constexpr int width = 800; // output image size +constexpr int height = 800; -Vec3f light_dir(1,1,1); -Vec3f eye(1,1,3); -Vec3f center(0,0,0); -Vec3f up(0,1,0); +const vec3 light_dir(1,1,1); // light source +const vec3 eye(1,1,3); // camera position +const vec3 center(0,0,0); // camera direction +const vec3 up(0,1,0); // camera up vector struct Shader : public IShader { const Model &model; - Shader(const Model &m) : model(m) {} - mat<2,3,float> varying_uv; // triangle uv coordinates, written by the vertex shader, read by the fragment shader - mat<4,3,float> varying_tri; // triangle coordinates (clip coordinates), written by VS, read by FS - mat<3,3,float> varying_nrm; // normal per vertex to be interpolated by FS - mat<3,3,float> ndc_tri; // triangle in normalized device coordinates + vec3 l; // light direction in normalized device coordinates + mat<2,3> varying_uv; // triangle uv coordinates, written by the vertex shader, read by the fragment shader + mat<4,3> varying_tri; // triangle coordinates (clip coordinates), written by VS, read by FS + mat<3,3> varying_nrm; // normal per vertex to be interpolated by FS + mat<3,3> ndc_tri; // triangle in normalized device coordinates + + Shader(const Model &m) : model(m) { + l = proj<3>((Projection*ModelView*embed<4>(light_dir, 0.))).normalize(); // transform the light vector to the normalized device coordinates + } - virtual Vec4f vertex(int iface, int nthvert) { + virtual vec4 vertex(const int iface, const int nthvert) { varying_uv.set_col(nthvert, model.uv(iface, nthvert)); - varying_nrm.set_col(nthvert, proj<3>((Projection*ModelView).invert_transpose()*embed<4>(model.normal(iface, nthvert), 0.f))); - Vec4f gl_Vertex = Projection*ModelView*embed<4>(model.vert(iface, nthvert)); + varying_nrm.set_col(nthvert, proj<3>((Projection*ModelView).invert_transpose()*embed<4>(model.normal(iface, nthvert), 0.))); + vec4 gl_Vertex = Projection*ModelView*embed<4>(model.vert(iface, nthvert)); varying_tri.set_col(nthvert, gl_Vertex); ndc_tri.set_col(nthvert, proj<3>(gl_Vertex/gl_Vertex[3])); return gl_Vertex; } - virtual bool fragment(Vec3f bar, TGAColor &color) { - Vec3f bn = (varying_nrm*bar).normalize(); - Vec2f uv = varying_uv*bar; - - mat<3,3,float> A; - A[0] = ndc_tri.col(1) - ndc_tri.col(0); - A[1] = ndc_tri.col(2) - ndc_tri.col(0); - A[2] = bn; + virtual bool fragment(const vec3 bar, TGAColor &color) { + vec3 bn = (varying_nrm*bar).normalize(); // per-vertex normal interpolation + vec2 uv = varying_uv*bar; // tex coord interpolation - mat<3,3,float> AI = A.invert(); + // for the math refer to the tangent space normal mapping lecture + // https://github.com/ssloy/tinyrenderer/wiki/Lesson-6bis-tangent-space-normal-mapping - Vec3f i = AI * Vec3f(varying_uv[0][1] - varying_uv[0][0], varying_uv[0][2] - varying_uv[0][0], 0); - Vec3f j = AI * Vec3f(varying_uv[1][1] - varying_uv[1][0], varying_uv[1][2] - varying_uv[1][0], 0); + mat<3,3> AI = mat<3,3>{ {ndc_tri.col(1) - ndc_tri.col(0), ndc_tri.col(2) - ndc_tri.col(0), bn} }.invert(); + vec3 i = AI * vec3(varying_uv[0][1] - varying_uv[0][0], varying_uv[0][2] - varying_uv[0][0], 0); + vec3 j = AI * vec3(varying_uv[1][1] - varying_uv[1][0], varying_uv[1][2] - varying_uv[1][0], 0); + mat<3,3> B = mat<3,3>{ {i.normalize(), j.normalize(), bn} }.transpose(); - mat<3,3,float> B; - B.set_col(0, i.normalize()); - B.set_col(1, j.normalize()); - B.set_col(2, bn); + vec3 n = (B * model.normal(uv)).normalize(); // transform the normal from the texture to the tangent space - Vec3f n = (B*model.normal(uv)).normalize(); + double diff = std::max(0., n*l); // diffuse light intensity + vec3 r = (n*(n*l)*2 - l).normalize(); // reflected light direction + double spec = std::pow(std::max(r.z, 0.), 5+model.specular(uv)); // specular intensity - float diff = std::max(0.f, n*light_dir); - color = model.diffuse(uv)*diff; + TGAColor c = model.diffuse(uv); + for (int i=0; i<3; i++) + color[i] = std::min(10 + c[i]*(diff + spec), 255); // (a bit of ambient light, diff + spec), clamp the result - return false; + return false; // the pixel is not discarded } }; @@ -65,28 +68,23 @@ int main(int argc, char** argv) { return 1; } - float *zbuffer = new float[width*height]; - for (int i=width*height; i--; zbuffer[i] = -std::numeric_limits::max()); + std::vector zbuffer(width*height, -std::numeric_limits::max()); - TGAImage frame(width, height, TGAImage::RGB); - lookat(eye, center, up); - viewport(width/8, height/8, width*3/4, height*3/4); - projection(-1.f/(eye-center).norm()); - light_dir = proj<3>((Projection*ModelView*embed<4>(light_dir, 0.f))).normalize(); + TGAImage framebuffer(width, height, TGAImage::RGB); // the output image + lookat(eye, center, up); // build the ModelView matrix + viewport(width/8, height/8, width*3/4, height*3/4); // build the Viewport matrix + projection(-1.f/(eye-center).norm()); // build the Projection matrix - for (int m=1; m #include "model.h" -Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffusemap_(), normalmap_(), specularmap_() { +Model::Model(const std::string filename) : verts_(), uv_(), norms_(), facet_vrt_(), facet_tex_(), facet_nrm_(), diffusemap_(), normalmap_(), specularmap_() { std::ifstream in; in.open (filename, std::ifstream::in); if (in.fail()) return; @@ -14,34 +14,41 @@ Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffus char trash; if (!line.compare(0, 2, "v ")) { iss >> trash; - Vec3f v; + vec3 v; for (int i=0;i<3;i++) iss >> v[i]; verts_.push_back(v); } else if (!line.compare(0, 3, "vn ")) { iss >> trash >> trash; - Vec3f n; + vec3 n; for (int i=0;i<3;i++) iss >> n[i]; norms_.push_back(n.normalize()); } else if (!line.compare(0, 3, "vt ")) { iss >> trash >> trash; - Vec2f uv; + vec2 uv; for (int i=0;i<2;i++) iss >> uv[i]; uv_.push_back(uv); } else if (!line.compare(0, 2, "f ")) { - std::vector f; - Vec3i tmp; + int f,t,n; iss >> trash; - while (iss >> tmp[0] >> trash >> tmp[1] >> trash >> tmp[2]) { - for (int i=0; i<3; i++) tmp[i]--; // in wavefront obj all indices start at 1, not zero - f.push_back(tmp); + int cnt = 0; + while (iss >> f >> trash >> t >> trash >> n) { + facet_vrt_.push_back(--f); + facet_tex_.push_back(--t); + facet_nrm_.push_back(--n); + cnt++; + } + if (3!=cnt) { + std::cerr << "Error: the obj file is supposed to be triangulated" << std::endl; + in.close(); + return; } - faces_.push_back(f); } } - 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_tangent.tga", normalmap_); - load_texture(filename, "_spec.tga", specularmap_); + in.close(); + std::cerr << "# v# " << nverts() << " f# " << nfaces() << " vt# " << uv_.size() << " vn# " << norms_.size() << std::endl; + load_texture(filename, "_diffuse.tga", diffusemap_); + load_texture(filename, "_nm_tangent.tga", normalmap_); + load_texture(filename, "_spec.tga", specularmap_); } int Model::nverts() const { @@ -49,58 +56,47 @@ int Model::nverts() const { } int Model::nfaces() const { - return faces_.size(); -} - -std::vector Model::face(const int idx) const { - std::vector face; - for (int i=0; i<(int)faces_[idx].size(); i++) face.push_back(faces_[idx][i][0]); - return face; + return facet_vrt_.size()/3; } -Vec3f Model::vert(const int i) const { +vec3 Model::vert(const int i) const { return verts_[i]; } -Vec3f Model::vert(const int iface, const int nthvert) const { - return verts_[faces_[iface][nthvert][0]]; +vec3 Model::vert(const int iface, const int nthvert) const { + return verts_[facet_vrt_[iface*3+nthvert]]; } -void Model::load_texture(std::string filename, const char *suffix, TGAImage &img) { - std::string texfile(filename); - size_t dot = texfile.find_last_of("."); +void Model::load_texture(std::string filename, const std::string suffix, TGAImage &img) { + size_t dot = filename.find_last_of("."); if (dot!=std::string::npos) { - texfile = texfile.substr(0,dot) + std::string(suffix); + std::string texfile = filename.substr(0,dot) + suffix; std::cerr << "texture file " << texfile << " loading " << (img.read_tga_file(texfile.c_str()) ? "ok" : "failed") << std::endl; img.flip_vertically(); } } -TGAColor Model::diffuse(const Vec2f &uvf) const { - Vec2i uv(uvf[0]*diffusemap_.get_width(), uvf[1]*diffusemap_.get_height()); - return diffusemap_.get(uv[0], uv[1]); +TGAColor Model::diffuse(const vec2 &uvf) const { + return diffusemap_.get(uvf[0]*diffusemap_.get_width(), uvf[1]*diffusemap_.get_height()); } -Vec3f Model::normal(const Vec2f &uvf) const { - Vec2i uv(uvf[0]*normalmap_.get_width(), uvf[1]*normalmap_.get_height()); - TGAColor c = normalmap_.get(uv[0], uv[1]); - Vec3f res; +vec3 Model::normal(const vec2 &uvf) const { + TGAColor c = normalmap_.get(uvf[0]*normalmap_.get_width(), uvf[1]*normalmap_.get_height()); + vec3 res; for (int i=0; i<3; i++) - res[2-i] = (float)c[i]/255.f*2.f - 1.f; + res[2-i] = c[i]/255.f*2.f - 1.f; return res; } -Vec2f Model::uv(const int iface, const int nthvert) const { - return uv_[faces_[iface][nthvert][1]]; +vec2 Model::uv(const int iface, const int nthvert) const { + return uv_[facet_tex_[iface*3+nthvert]]; } -float Model::specular(const Vec2f &uvf) const { - Vec2i uv(uvf[0]*specularmap_.get_width(), uvf[1]*specularmap_.get_height()); - return specularmap_.get(uv[0], uv[1])[0]/1.f; +double Model::specular(const vec2 &uvf) const { + return specularmap_.get(uvf[0]*specularmap_.get_width(), uvf[1]*specularmap_.get_height())[0]/1.f; } -Vec3f Model::normal(const int iface, const int nthvert) const { - int idx = faces_[iface][nthvert][2]; - return norms_[idx]; +vec3 Model::normal(const int iface, const int nthvert) const { + return norms_[facet_nrm_[iface*3+nthvert]]; } diff --git a/model.h b/model.h index 675b742e..5d675fb1 100644 --- a/model.h +++ b/model.h @@ -7,26 +7,27 @@ class Model { private: - std::vector verts_; - std::vector > faces_; // attention, this Vec3i means vertex/uv/normal - std::vector norms_; - std::vector uv_; - TGAImage diffusemap_; - TGAImage normalmap_; - TGAImage specularmap_; - void load_texture(std::string filename, const char *suffix, TGAImage &img); + std::vector verts_; // array of vertices + std::vector uv_; // array of tex coords + std::vector norms_; // array of normal vectors + std::vector facet_vrt_; + std::vector facet_tex_; // indices in the above arrays per triangle + std::vector facet_nrm_; + TGAImage diffusemap_; // diffuse color texture + TGAImage normalmap_; // normal map texture + TGAImage specularmap_; // specular map texture + void load_texture(const std::string filename, const std::string suffix, TGAImage &img); public: - Model(const char *filename); + Model(const std::string filename); int nverts() const; int nfaces() const; - Vec3f normal(const int iface, const int nthvert) const; - Vec3f normal(const Vec2f &uv) const; - Vec3f vert(const int i) const; - Vec3f vert(const int iface, const int nthvert) const; - Vec2f uv(const int iface, const int nthvert) const; - TGAColor diffuse(const Vec2f &uv) const; - float specular(const Vec2f &uv) const; - std::vector face(const int idx) const; + vec3 normal(const int iface, const int nthvert) const; // per triangle corner normal vertex + vec3 normal(const vec2 &uv) const; // fetch the normal vector from the normal map texture + vec3 vert(const int i) const; + vec3 vert(const int iface, const int nthvert) const; + vec2 uv(const int iface, const int nthvert) const; + TGAColor diffuse(const vec2 &uv) const; + double specular(const vec2 &uv) const; }; #endif //__MODEL_H__ diff --git a/our_gl.cpp b/our_gl.cpp index b9581ddd..e461f821 100644 --- a/our_gl.cpp +++ b/our_gl.cpp @@ -3,33 +3,33 @@ #include #include "our_gl.h" -Matrix ModelView; -Matrix Viewport; -Matrix Projection; +mat44 ModelView; +mat44 Viewport; +mat44 Projection; IShader::~IShader() {} -void viewport(int x, int y, int w, int h) { - Viewport = Matrix::identity(); - Viewport[0][3] = x+w/2.f; - Viewport[1][3] = y+h/2.f; - Viewport[2][3] = 1.f; - Viewport[0][0] = w/2.f; - Viewport[1][1] = h/2.f; +void viewport(const int x, const int y, const int w, const int h) { + Viewport = mat44::identity(); + Viewport[0][3] = x+w/2.; + Viewport[1][3] = y+h/2.; + Viewport[2][3] = 1.; + Viewport[0][0] = w/2.; + Viewport[1][1] = h/2.; Viewport[2][2] = 0; } -void projection(float coeff) { - Projection = Matrix::identity(); +void projection(const double coeff) { + Projection = mat44::identity(); Projection[3][2] = coeff; } -void lookat(Vec3f eye, Vec3f center, Vec3f up) { - Vec3f z = (eye-center).normalize(); - Vec3f x = cross(up,z).normalize(); - Vec3f y = cross(z,x).normalize(); - Matrix Minv = Matrix::identity(); - Matrix Tr = Matrix::identity(); +void lookat(const vec3 eye, const vec3 center, const vec3 up) { + vec3 z = (eye-center).normalize(); + vec3 x = cross(up,z).normalize(); + vec3 y = cross(z,x).normalize(); + mat44 Minv = mat44::identity(); + mat44 Tr = mat44::identity(); for (int i=0; i<3; i++) { Minv[0][i] = x[i]; Minv[1][i] = y[i]; @@ -39,41 +39,41 @@ void lookat(Vec3f eye, Vec3f center, Vec3f up) { ModelView = Minv*Tr; } -Vec3f barycentric(Vec2f A, Vec2f B, Vec2f C, Vec2f P) { - Vec3f s[2]; +vec3 barycentric(const vec2 A, const vec2 B, const vec2 C, const vec2 P) { + vec3 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]); + vec3 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 - 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 + return vec3(1.-(u.x+u.y)/u.z, u.y/u.z, u.x/u.z); + return vec3(-1,1,1); // in this case generate negative coordinates, it will be thrown away by the rasterizator } -void triangle(mat<4,3,float> &clipc, IShader &shader, TGAImage &image, float *zbuffer) { - mat<3,4,float> pts = (Viewport*clipc).transpose(); // transposed to ease access to each of the points - mat<3,2,float> pts2; +void triangle(const mat<4,3> &clipc, IShader &shader, TGAImage &image, std::vector &zbuffer) { + mat<3,4> pts = (Viewport*clipc).transpose(); // transposed to ease access to each of the points + mat<3,2> pts2; for (int i=0; i<3; i++) pts2[i] = proj<2>(pts[i]/pts[i][3]); - Vec2f bboxmin( std::numeric_limits::max(), std::numeric_limits::max()); - Vec2f bboxmax(-std::numeric_limits::max(), -std::numeric_limits::max()); - Vec2f clamp(image.get_width()-1, image.get_height()-1); - for (int i=0; i<3; i++) { + vec2 bboxmin( std::numeric_limits::max(), std::numeric_limits::max()); + vec2 bboxmax(-std::numeric_limits::max(), -std::numeric_limits::max()); + vec2 clamp(image.get_width()-1, image.get_height()-1); + for (int i=0; i<3; i++) for (int j=0; j<2; j++) { - bboxmin[j] = std::max(0.f, std::min(bboxmin[j], pts2[i][j])); + bboxmin[j] = std::max(0., std::min(bboxmin[j], pts2[i][j])); bboxmax[j] = std::min(clamp[j], std::max(bboxmax[j], pts2[i][j])); } - } - TGAColor color; - for (int x=bboxmin.x; x<=bboxmax.x; x++) { - for (int y=bboxmin.y; y<=bboxmax.y; y++) { - Vec3f bc_screen = barycentric(pts2[0], pts2[1], pts2[2], {x,y}); - Vec3f bc_clip = Vec3f(bc_screen.x/pts[0][3], bc_screen.y/pts[1][3], bc_screen.z/pts[2][3]); +#pragma omp parallel for + for (int x=(int)bboxmin.x; x<=(int)bboxmax.x; x++) { + for (int y=(int)bboxmin.y; y<=(int)bboxmax.y; y++) { + vec3 bc_screen = barycentric(pts2[0], pts2[1], pts2[2], {(double)x, (double)y}); + vec3 bc_clip = vec3(bc_screen.x/pts[0][3], bc_screen.y/pts[1][3], bc_screen.z/pts[2][3]); bc_clip = bc_clip/(bc_clip.x+bc_clip.y+bc_clip.z); - float frag_depth = clipc[2]*bc_clip; + double frag_depth = clipc[2]*bc_clip; if (bc_screen.x<0 || bc_screen.y<0 || bc_screen.z<0 || zbuffer[x+y*image.get_width()]>frag_depth) continue; + TGAColor color; bool discard = shader.fragment(bc_clip, color); if (!discard) { zbuffer[x+y*image.get_width()] = frag_depth; diff --git a/our_gl.h b/our_gl.h index bc8ed731..d0eda2d7 100644 --- a/our_gl.h +++ b/our_gl.h @@ -3,20 +3,19 @@ #include "tgaimage.h" #include "geometry.h" -extern Matrix ModelView; -extern Matrix Projection; +extern mat44 ModelView; +extern mat44 Projection; -void viewport(int x, int y, int w, int h); -void projection(float coeff=0.f); // coeff = -1/c -void lookat(Vec3f eye, Vec3f center, Vec3f up); +void viewport(const int x, const int y, const int w, const int h); +void projection(const double coeff=0); // coeff = -1/c +void lookat(const vec3 eye, const vec3 center, const vec3 up); struct IShader { virtual ~IShader(); - virtual Vec4f vertex(int iface, int nthvert) = 0; - virtual bool fragment(Vec3f bar, TGAColor &color) = 0; + virtual vec4 vertex(const int iface, const int nthvert) = 0; + virtual bool fragment(const vec3 bar, TGAColor &color) = 0; }; -//void triangle(Vec4f *pts, IShader &shader, TGAImage &image, float *zbuffer); -void triangle(mat<4,3,float> &pts, IShader &shader, TGAImage &image, float *zbuffer); +void triangle(const mat<4,3> &pts, IShader &shader, TGAImage &image, std::vector &zbuffer); #endif //__OUR_GL_H__ diff --git a/tgaimage.h b/tgaimage.h index 43d3f5ad..777fb509 100644 --- a/tgaimage.h +++ b/tgaimage.h @@ -37,9 +37,9 @@ struct TGAColor { std::uint8_t& operator[](const int i) { return bgra[i]; } - TGAColor operator *(const float intensity) const { + TGAColor operator *(const double intensity) const { TGAColor res = *this; - float clamped = std::max(0.f, std::min(intensity, 1.f)); + double clamped = std::max(0., std::min(intensity, 1.)); for (int i=0; i<4; i++) res.bgra[i] = bgra[i]*clamped; return res; }