Browse Source

Added gamma coirrection, working on bump mapping.

angel 7 years ago
parent
commit
3dbba99361
14 changed files with 240 additions and 75 deletions
  1. 1 2
      CMakeLists.txt
  2. 2 0
      include/matrix.h
  3. 9 2
      include/mesh.h
  4. 2 0
      include/model.h
  5. 4 0
      include/rasterizer.h
  6. 79 36
      include/shader.h
  7. 4 1
      include/vector3D.h
  8. 2 2
      src/camera.cpp
  9. 1 1
      src/engine.cpp
  10. 21 0
      src/matrix.cpp
  11. 67 0
      src/mesh.cpp
  12. 5 0
      src/model.cpp
  13. 15 8
      src/rasterizer.cpp
  14. 28 23
      src/softwareRenderer.cpp

+ 1 - 2
CMakeLists.txt

@@ -9,9 +9,8 @@ find_package(OpenMP REQUIRED)
 include_directories(${SDL2_INCLUDE_DIR} include libs)
 include_directories(${SDL2_INCLUDE_DIR} include libs)
 
 
 file(GLOB source_files "*.h" "*.cpp" "src/*.cpp" "include/*.h" "libs/*.h")
 file(GLOB source_files "*.h" "*.cpp" "src/*.cpp" "include/*.h" "libs/*.h")
-message(STATUS $ENV{source_files})
 add_executable(softwareRenderer ${source_files})
 add_executable(softwareRenderer ${source_files})
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}  -g  ")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}  -g")
 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g ")
 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g ")
 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -g ")
 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -g ")
 target_link_libraries(softwareRenderer ${SDL2_LIBRARY})
 target_link_libraries(softwareRenderer ${SDL2_LIBRARY})

+ 2 - 0
include/matrix.h

@@ -47,6 +47,8 @@ class Matrix4{
         //defined as X[-1,1] Y[-1,1] Z[1,0] 
         //defined as X[-1,1] Y[-1,1] Z[1,0] 
         Matrix4 static projectionMatrix(float fov, float AR, float near, float far);
         Matrix4 static projectionMatrix(float fov, float AR, float near, float far);
 
 
+        Matrix4 static TBNMatrix(const Vector3f &tangent, const Vector3f &biTangent, const Vector3f &normal);
+
         //Debug stuff
         //Debug stuff
         void print();
         void print();
     private:
     private:

+ 9 - 2
include/mesh.h

@@ -7,13 +7,17 @@
 //Struct containing information relevant to the renderer about the vertices, normals and
 //Struct containing information relevant to the renderer about the vertices, normals and
 //texture coordinates of a model. Also keeps track of useful stuff for iterations.
 //texture coordinates of a model. Also keeps track of useful stuff for iterations.
 struct Mesh{
 struct Mesh{
+    //Per vertex values
     int numVertices = 0;
     int numVertices = 0;
     std::vector<Vector3f> vertices;
     std::vector<Vector3f> vertices;
     std::vector<Vector3f> normals;
     std::vector<Vector3f> normals;
-    std::vector<Vector3f> fNormals; //Normals for the whole face
     std::vector<Vector3f> texels;
     std::vector<Vector3f> texels;
+    std::vector<Vector3f> tangents;
+    std::vector<Vector3f> biTangents;
 
 
+    //Per face values
     int numFaces = 0;
     int numFaces = 0;
+    std::vector<Vector3f> fNormals; //Normals for the whole face
     std::vector<Vector3i> vertexIndices;
     std::vector<Vector3i> vertexIndices;
     std::vector<Vector3i> textureIndices;
     std::vector<Vector3i> textureIndices;
     std::vector<Vector3i> normalsIndices;
     std::vector<Vector3i> normalsIndices;
@@ -21,8 +25,11 @@ struct Mesh{
     //Simple mesh description for debugging.
     //Simple mesh description for debugging.
     void describeMesh();
     void describeMesh();
 
 
-    //Builds facet normals for early back face culling
+    //Builds facet normals used in early back face culling
     void buildFacetNormals();
     void buildFacetNormals();
+
+    //Builds tangent and bitangent vectors for normal mapping
+    void buildTangentSpace();
 };
 };
 
 
 #endif
 #endif

+ 2 - 0
include/model.h

@@ -15,6 +15,7 @@ class Model{
         Matrix4 *getModelMatrix();
         Matrix4 *getModelMatrix();
         AABox *getBounds();
         AABox *getBounds();
         Texture *getAlbedo();
         Texture *getAlbedo();
+        Texture *getNormal();
 
 
         void update();
         void update();
 
 
@@ -22,6 +23,7 @@ class Model{
         void describeMesh();
         void describeMesh();
     private:
     private:
         Texture mAlbedo{"../models/fire_hydrant_Base_Color.png"};
         Texture mAlbedo{"../models/fire_hydrant_Base_Color.png"};
+        Texture mNormal{"../models/fire_hydrant_Normal_OpenGL.png"};
         Mesh mMesh;
         Mesh mMesh;
         AABox mBounds;
         AABox mBounds;
         Matrix4 mModelMatrix;
         Matrix4 mModelMatrix;

+ 4 - 0
include/rasterizer.h

@@ -36,6 +36,10 @@ class Rasterizer{
 
 
         static bool inside(float edge, float a, float b);
         static bool inside(float edge, float a, float b);
 
 
+        static float clamp(float n, float lower, float upper);
+
+        static float gammaAdjust(float n, float gamma);
+
     private:
     private:
         Rasterizer(){}; //Ensuring an object can never be instanced accidentally
         Rasterizer(){}; //Ensuring an object can never be instanced accidentally
 
 

+ 79 - 36
include/shader.h

@@ -9,7 +9,7 @@
 //Shader Interface for a class that emulates modern GPU fragment and vertex shaders
 //Shader Interface for a class that emulates modern GPU fragment and vertex shaders
 struct IShader {
 struct IShader {
     virtual ~IShader() {};
     virtual ~IShader() {};
-    virtual Vector3f vertex(Vector3f &vertex, Vector3f &normals, Vector3f &textureVals, Vector3f &light, int i) = 0;
+    virtual Vector3f vertex(const Vector3f &vertex, const Vector3f &normal, const Vector3f &textureVals, const Vector3f &tangent, const Vector3f &biTangent, const Vector3f &light, int index) = 0;
     virtual Vector3f fragment(float u, float v) = 0;
     virtual Vector3f fragment(float u, float v) = 0;
 };
 };
 
 
@@ -19,8 +19,8 @@ struct FlatShader : public IShader {
     float varIntensity;
     float varIntensity;
     Vector3f rgb{255,255,255};
     Vector3f rgb{255,255,255};
 
 
-    Vector3f vertex(Vector3f &vertex, Vector3f &normals, Vector3f &textureVals, Vector3f &light, int index) override{
-        varIntensity = std::max(0.0f,normals.dotProduct(light));
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal, const Vector3f &textureVals,const Vector3f &tangent,const Vector3f &biTangent,const Vector3f &light, int index) override{
+        varIntensity = std::max(0.0f,normal.dotProduct(light));
         return MVP.matMultVec(vertex); //Transforms verts into projected space
         return MVP.matMultVec(vertex); //Transforms verts into projected space
     }
     }
 
 
@@ -37,11 +37,11 @@ struct GouraudShader : public IShader {
     float ambientStrength = 0.05, diffStrength = 0, specularStrength = 0.5, spec = 0;
     float ambientStrength = 0.05, diffStrength = 0, specularStrength = 0.5, spec = 0;
     Vector3f ambient, diffuse, specular;
     Vector3f ambient, diffuse, specular;
     Vector3f lightColor1{1,1,1}, lightColor2{0,0,1}, lightColor3{1,1,1};
     Vector3f lightColor1{1,1,1}, lightColor2{0,0,1}, lightColor3{1,1,1};
-    Vector3f varying_diffuse, varying_specular, reflectDir, viewDir, light2;
+    Vector3f varying_diffuse, varying_specular, reflectDir, viewDir, light2, normal2;
     Vector3f rgb{255,255,255};
     Vector3f rgb{255,255,255};
 
 
-    Vector3f vertex(Vector3f &vertex, Vector3f &normal, Vector3f &textureVals, Vector3f &light, int index) override{
-        normal = N.matMultDir(normal).normalized();
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal, const Vector3f &textureVals,const Vector3f &tangent,const Vector3f &biTangent,const Vector3f &light, int index) override{
+        normal2 = N.matMultDir(normal).normalized();
         light2 = V.matMultDir(light).normalized();
         light2 = V.matMultDir(light).normalized();
         reflectDir = Vector3f::reflect(-light2, normal);
         reflectDir = Vector3f::reflect(-light2, normal);
         viewDir = MV.matMultVec(vertex).normalized();
         viewDir = MV.matMultVec(vertex).normalized();
@@ -75,7 +75,7 @@ struct PhongShader : public IShader {
     Vector3f varying_diffuse, varying_specular, reflectDir, light2;
     Vector3f varying_diffuse, varying_specular, reflectDir, light2;
     Vector3f rgb{255,255,255};
     Vector3f rgb{255,255,255};
 
 
-    Vector3f vertex(Vector3f &vertex, Vector3f &normal, Vector3f &textureVals, Vector3f &light, int index) override{
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal, const Vector3f &textureVals,const Vector3f &tangent,const Vector3f &biTangent,const Vector3f &light, int index) override{
         normals[index] = N.matMultDir(normal).normalized();
         normals[index] = N.matMultDir(normal).normalized();
         viewDir[index] = MV.matMultVec(vertex).normalized();
         viewDir[index] = MV.matMultVec(vertex).normalized();
         light2 = V.matMultDir(light).normalized();
         light2 = V.matMultDir(light).normalized();
@@ -106,7 +106,7 @@ struct PhongShader : public IShader {
 //Optimized version of Phong shader that uses a half angle instead of individual reflection
 //Optimized version of Phong shader that uses a half angle instead of individual reflection
 //angles
 //angles
 struct BlinnPhongShader : public IShader {
 struct BlinnPhongShader : public IShader {
-    Texture *albedo;
+    Texture *albedoT, *normalT;
     Matrix4 MVP, MV, V, N;
     Matrix4 MVP, MV, V, N;
     float ambientStrength = 0.05, diffStrength=1 , specularStrength= 0.5;
     float ambientStrength = 0.05, diffStrength=1 , specularStrength= 0.5;
     float diff, spec, shininess = 128;
     float diff, spec, shininess = 128;
@@ -116,7 +116,7 @@ struct BlinnPhongShader : public IShader {
     Vector3f halfwayDir, lightDir;
     Vector3f halfwayDir, lightDir;
     Vector3f interpCol, white{255,255,255};
     Vector3f interpCol, white{255,255,255};
 
 
-    Vector3f vertex(Vector3f &vertex, Vector3f &normal, Vector3f &textureVals, Vector3f &light, int index) override{
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal, const Vector3f &textureVals,const Vector3f &tangent,const Vector3f &biTangent,const Vector3f &light, int index) override{
         normals[index] = N.matMultDir(normal).normalized();
         normals[index] = N.matMultDir(normal).normalized();
         UV[index] = textureVals;
         UV[index] = textureVals;
         viewDir[index] = MV.matMultVec(vertex).normalized();
         viewDir[index] = MV.matMultVec(vertex).normalized();
@@ -130,7 +130,13 @@ struct BlinnPhongShader : public IShader {
         interpViewDir = viewDir[0] + (viewDir[1] - viewDir[0])* u + (viewDir[2] - viewDir[0]) * v;
         interpViewDir = viewDir[0] + (viewDir[1] - viewDir[0])* u + (viewDir[2] - viewDir[0]) * v;
         interpUV = UV[0] + (UV[1] - UV[0])* u + (UV[2] - UV[0]) * v;
         interpUV = UV[0] + (UV[1] - UV[0])* u + (UV[2] - UV[0]) * v;
         //Albedo
         //Albedo
-        interpCol = albedo->getPixelVal(interpUV.x, interpUV.y);
+        interpCol = albedoT->getPixelVal(interpUV.x, interpUV.y);
+        //interpNormal = normalT->getPixelVal(interpUV.x, interpUV.y);
+        // interpNormal.x = (interpNormal.x*2/256.0f) -1;
+        // interpNormal.y = (interpNormal.y*2/256.0f) -1;
+        // interpNormal.z = 1 - interpNormal.z*1/256.0f;
+        // interpNormal = interpNormal.normalized();
+
         //rgb.print();
         //rgb.print();
 
 
         //Ambient 
         //Ambient 
@@ -150,51 +156,88 @@ struct BlinnPhongShader : public IShader {
 
 
 };
 };
 
 
+// Shader that uses normal mapping instead of vertex normal interpolation
+struct NormalMapShader : public IShader {
+    //Variables set per model
+    Texture *albedoT, *normalT;
+    Matrix4 MVP, MV, V, M, N;
+    Vector3f cameraPos;
 
 
-struct TestShader{
-    Texture *albedo;
-    Matrix4 MVP, MV, V, N;
-    float ambientStrength = 0.05, diffStrength=1 , specularStrength= 0.5;
+    //Light Variables
+    Vector3f lightColor{1,1,1}, white{1,1,1};
+    float ambientStrength = 0.05, diffStrength = 1, specularStrength = 0.5;
     float diff, spec, shininess = 128;
     float diff, spec, shininess = 128;
-    Vector3f normals[3], viewDir[3], UV[3];
-    Vector3f ambient, diffuse, specular, interpNormal, interpViewDir, interpUV;
-    Vector3f lightColor{1,1,1};
-    Vector3f halfwayDir, lightDir;
-    Vector3f interpCol, white{255,255,255};
 
 
-    Vector3f vertex(Vector3f &vertex, Vector3f &normal, Vector3f &textureVals, Vector3f &light, int index) {
-        normals[index] = N.matMultDir(normal).normalized();
+    //Variables set per vertex
+    Vector3f normals[3], viewDir[3], UV[3], tangentFragPos[3], viewPos[3];
+    Vector3f lightDir, vertexPos[3],vertTangent[3], vertBiTangent[3] ;
+    
+    //Interpolated variables
+    Vector3f interpUV, interpNormal, interpViewPos, interpCol, interpTangentFragPos;
+
+    //Per fragment
+    Vector3f ambient, diffuse, specular ;
+    Vector3f halfwayDir;
+
+    Vector3f vertex(const Vector3f &vertex, const Vector3f &normal,const Vector3f &textureVals,const Vector3f &tangent,const Vector3f &biTangent,const Vector3f &light, int index) override{
+        //Creating TBN matrix
+        normals[index]           = N.matMultDir(normal).normalized();
+        vertTangent[index]       = N.matMultDir(tangent).normalized();
+        vertBiTangent[index]     = N.matMultDir(biTangent).normalized();
+        vertexPos[index]         = M.matMultVec(vertex);
+        // Matrix4 TBN = Matrix4::TBNMatrix(vertTangent[index], vertBiTangent[index], normals[index]);
+
+        //Getting UV coordinates for use in both albedo and normal textures
         UV[index] = textureVals;
         UV[index] = textureVals;
-        viewDir[index] = MV.matMultVec(vertex).normalized();
-        lightDir = V.matMultDir(light).normalized();
+
+        //Passing all lighting related data to tangent space
+        // tangentFragPos[index] = TBN.matMultVec(N.matMultVec(vertex));
+        // viewPos[index]        = TBN.matMultVec(cameraPos); 
+        // lightDir              = TBN.matMultVec(light);
+
         return MVP.matMultVec(vertex);
         return MVP.matMultVec(vertex);
     }
     }
 
 
-    Vector3f fragment(float u, float v) {
+    Vector3f fragment(float u, float v) override{
         //Interpolated stuff
         //Interpolated stuff
-        interpNormal = (normals[0] + (normals[1] - normals[0])* u + (normals[2] - normals[0]) * v).normalized();
-        interpViewDir = viewDir[0] + (viewDir[1] - viewDir[0])* u + (viewDir[2] - viewDir[0]) * v;
-        interpUV = UV[0] + (UV[1] - UV[0])* u + (UV[2] - UV[0]) * v;
+        // interpTangentFragPos = tangentFragPos[0] + (tangentFragPos[1] - tangentFragPos[0])* u + (tangentFragPos[2] - tangentFragPos[0]) * v;
+        // interpViewPos = viewPos[0] + (viewPos[1] - viewPos[0])* u + (viewPos[2] - viewPos[0]) * v;
+        //interpUV = UV[0] + (UV[1] - UV[0])* u + (UV[2] - UV[0]) * v;
+        Vector3f interpPos =  vertexPos[0] + (vertexPos[1] - vertexPos[0])* u + (vertexPos[2] - vertexPos[0]) * v;
+        Vector3f interpTan =  vertTangent[0] + (vertTangent[1] - vertTangent[0])* u + (vertTangent[2] - vertTangent[0]) * v;
+        Vector3f interpBiTan =  vertBiTangent[0] + (vertBiTangent[1] - vertBiTangent[0])* u + (vertBiTangent[2] - vertBiTangent[0]) * v;
+        Vector3f interpNorm =  normals[0] + (normals[1] - normals[0])* u + (normals[2] - normals[0]) * v;
+
         //Albedo
         //Albedo
-        interpCol = albedo->getPixelVal(interpUV.x, interpUV.y);
-        //rgb.print();
+        // interpCol    = albedoT->getPixelVal(interpUV.x, interpUV.y);
+        // interpNormal = normalT->getPixelVal(interpUV.x, interpUV.y);
+        // interpNormal.x = (interpNormal.x * 2/256.0f) - 1;
+        // interpNormal.y = (interpNormal.y * 2/256.0f) - 1;
+        // interpNormal.z = (interpNormal.z * 2/256.0f) - 1;
+        // interpNormal = interpNormal.normalized();
+
 
 
         //Ambient 
         //Ambient 
-        ambient = lightColor * ambientStrength;
+        // ambient = lightColor * ambientStrength;
 
 
         //Diffuse
         //Diffuse
-        diff = std::max(0.0f, interpNormal.dotProduct(lightDir));
-        diffuse = lightColor * diff * diffStrength;
+        //lightDir = (interpTangentFragPos - lightDir).normalized();
+        // diff = std::max(0.0f, interpNormal.dotProduct(lightDir));
+        // diffuse = lightColor * diff * diffStrength;
         
         
         //Specular
         //Specular
-        halfwayDir = (lightDir - interpViewDir).normalized();
-        spec = std::pow(std::max(0.0f, interpNormal.dotProduct(halfwayDir)), shininess);
-        specular = lightColor * spec * specularStrength;
+        // halfwayDir = (lightDir - interpViewDir).normalized();
+        // spec = std::pow(std::max(0.0f, interpNormal.dotProduct(halfwayDir)), shininess);
+        // specular = lightColor * spec * specularStrength;
 
 
-        return (ambient + diffuse) * interpCol + specular * white;
+        //return (ambient + diffuse) * interpCol + specular * white;
+        return  interpPos;
     }
     }
 
 
 };
 };
 
 
 
 
+
+
+
 #endif
 #endif

+ 4 - 1
include/vector3D.h

@@ -41,7 +41,7 @@ struct Vector3{
     {return Vector3(-x, -y, -z);} 
     {return Vector3(-x, -y, -z);} 
     Vector3 operator*(const T &rhs) const //Scalar-vector multiplication
     Vector3 operator*(const T &rhs) const //Scalar-vector multiplication
     {return Vector3(x*rhs, y*rhs, z*rhs);}
     {return Vector3(x*rhs, y*rhs, z*rhs);}
-    Vector3 operator+(const T &rhs) const //Scalar-vector multiplication
+    Vector3 operator+(const T &rhs) const //Scalar-vector addition
     {return Vector3(x+rhs, y+rhs, z+rhs);}
     {return Vector3(x+rhs, y+rhs, z+rhs);}
 
 
     //Vector-vector operations
     //Vector-vector operations
@@ -51,6 +51,9 @@ struct Vector3{
     Vector3 operator+(const Vector3 &rhs) const
     Vector3 operator+(const Vector3 &rhs) const
     {return Vector3(x + rhs.x, y + rhs.y, z + rhs.z);}
     {return Vector3(x + rhs.x, y + rhs.y, z + rhs.z);}
 
 
+    void operator+=(const Vector3 &rhs) 
+    {(*this) = (*this) + rhs ;}
+
     Vector3 operator*(const Vector3 &rhs) const
     Vector3 operator*(const Vector3 &rhs) const
     {return Vector3(x * rhs.x, y * rhs.y, z * rhs.z);}
     {return Vector3(x * rhs.x, y * rhs.y, z * rhs.z);}
 
 

+ 2 - 2
src/camera.cpp

@@ -12,8 +12,8 @@ Camera::Camera(){
 void Camera::update(){
 void Camera::update(){
     float t = static_cast<float>(SDL_GetTicks());
     float t = static_cast<float>(SDL_GetTicks());
     float radius = 1.4;
     float radius = 1.4;
-    float camX   = std::sin(t/3000) * radius;
-    float camZ   = std::cos(t/3000) * radius;
+    float camX   = std::sin(t/6000) * radius;
+    float camZ   = std::cos(t/6000) * radius;
     position.x   = camX;
     position.x   = camX;
     position.y   = 0;
     position.y   = 0;
     position.z   = camZ;
     position.z   = camZ;

+ 1 - 1
src/engine.cpp

@@ -95,7 +95,7 @@ void Engine::run(){
         end = SDL_GetTicks();
         end = SDL_GetTicks();
         printf("%2.1d: Loop elapsed time (ms):%d\n",count,end - start);
         printf("%2.1d: Loop elapsed time (ms):%d\n",count,end - start);
         total += end - start;
         total += end - start;
-        if (count == 500) break;
+        //if (count == 500) break;
     }
     }
 
 
     printf("Closing down engine:\n");
     printf("Closing down engine:\n");

+ 21 - 0
src/matrix.cpp

@@ -383,6 +383,27 @@ Matrix4 Matrix4::projectionMatrix(float fov, float AR, float near, float far){
     return projectionMat;
     return projectionMat;
 }
 }
 
 
+Matrix4 Matrix4::TBNMatrix(const Vector3f &tangent, const Vector3f &biTangent, const Vector3f &normal){
+    Matrix4 tangentMat;
+
+    //First 
+    tangentMat(0,0) = tangent.x;
+    tangentMat(0,1) = biTangent.x;
+    tangentMat(0,2) = normal.x;
+
+    //Second row
+    tangentMat(1,0) = tangent.y;
+    tangentMat(1,1) = biTangent.y;
+    tangentMat(1,2) = normal.y;
+
+    //third row
+    tangentMat(2,0) = tangent.z;
+    tangentMat(2,1) = biTangent.z;
+    tangentMat(2,2) = normal.z;
+
+    return tangentMat.transpose();
+}
+
 void Matrix4::print(){
 void Matrix4::print(){
     int n = 4;
     int n = 4;
     for(int rows = 0; rows < n; ++rows){
     for(int rows = 0; rows < n; ++rows){

+ 67 - 0
src/mesh.cpp

@@ -14,4 +14,71 @@ void Mesh::buildFacetNormals(){
         Vector3f N2 = vertices[indices.data[2]] - vertices[indices.data[0]];
         Vector3f N2 = vertices[indices.data[2]] - vertices[indices.data[0]];
         fNormals.push_back((N1.crossProduct(N2)).normalized());
         fNormals.push_back((N1.crossProduct(N2)).normalized());
     }
     }
+}
+
+void Mesh::buildTangentSpace(){
+    std::vector<std::vector<Vector3f>> tempTangents(numVertices);
+    std::vector<std::vector<Vector3f>> tempBiTangents(numVertices);
+    Vector3f tangent, biTangent;
+
+    //Extract the tangent and bitangentn of each surface triangle
+    //Assign the value to a temporary vector of vectors of vector3's (yikes)
+    for(int i = 0; i < numFaces; ++i){
+        Vector3i vIndices = vertexIndices[i];
+        Vector3i tIndices = textureIndices[i];
+
+        Vector3f edge1 = vertices[vIndices.data[1]] - vertices[vIndices.data[0]];
+        Vector3f edge2 = vertices[vIndices.data[2]] - vertices[vIndices.data[0]];
+
+        Vector3f deltaUV1 = texels[tIndices.data[1]] - texels[tIndices.data[0]];
+        Vector3f deltaUV2 = texels[tIndices.data[2]] - texels[tIndices.data[0]];
+
+        float f = 1 / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
+
+        tangent.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
+        tangent.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
+        tangent.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
+        tangent = tangent.normalized();
+
+        biTangent.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
+        biTangent.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
+        biTangent.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
+        biTangent = biTangent.normalized();
+
+        tempTangents[vIndices.data[0]].push_back(tangent);
+        tempTangents[vIndices.data[1]].push_back(tangent);
+        tempTangents[vIndices.data[2]].push_back(tangent);
+
+        tempBiTangents[vIndices.data[0]].push_back(biTangent);
+        tempBiTangents[vIndices.data[1]].push_back(biTangent);
+        tempBiTangents[vIndices.data[2]].push_back(biTangent);
+    }
+
+    //Take average of tangents and bitangents at that vertex
+    for(int j = 0; j < numVertices; ++j){
+        int count1 = 0, count2 = 0;
+        Vector3f temp1{0};
+        while(!tempTangents[j].empty()){
+            ++count1;
+            temp1 += tempTangents[j].back();
+            if (temp1.x == 0 && temp1.y == 0 && temp1.z == 0){
+                temp1 += tempTangents[j].back();
+            }
+            tempTangents[j].pop_back();
+        }
+        temp1 = temp1 * (1.0f/count1);
+        tangents.push_back(temp1);
+
+        Vector3f temp2{0};
+        while(!tempBiTangents[j].empty()){
+            ++count2;
+            temp2 += tempBiTangents[j].back();
+             if (temp2.x == 0 && temp2.y == 0 && temp2.z == 0){
+                temp2 += tempBiTangents[j].back();
+            }
+            tempBiTangents[j].pop_back();
+        }
+        temp2 = temp2 * (1.0f/count2);
+        biTangents.push_back(temp2);
+    }
 }
 }

+ 5 - 0
src/model.cpp

@@ -5,6 +5,7 @@ Model::Model(std::string path, TransformParameters &initParameters){
     OBJ::buildMeshFromFile(mMesh, path);
     OBJ::buildMeshFromFile(mMesh, path);
     mBounds.buildAABB(mMesh);
     mBounds.buildAABB(mMesh);
     mMesh.buildFacetNormals();
     mMesh.buildFacetNormals();
+    mMesh.buildTangentSpace();
     mModelMatrix = Matrix4::transformMatrix(initParameters);
     mModelMatrix = Matrix4::transformMatrix(initParameters);
 }
 }
 
 
@@ -28,4 +29,8 @@ Matrix4 *Model::getModelMatrix(){
 
 
 Texture *Model::getAlbedo(){
 Texture *Model::getAlbedo(){
     return &mAlbedo;
     return &mAlbedo;
+}
+
+Texture *Model::getNormal(){
+    return &mNormal;
 }
 }

+ 15 - 8
src/rasterizer.cpp

@@ -114,8 +114,6 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
     e_row.y = edge(vertices[2], vertices[0], point);
     e_row.y = edge(vertices[2], vertices[0], point);
     e_row.z = edge(vertices[0], vertices[1], point);
     e_row.z = edge(vertices[0], vertices[1], point);
 
 
-
-
     //Iterating through each pixel in triangle bounding box
     //Iterating through each pixel in triangle bounding box
     for(int y = yMin; y <= yMax; ++y){
     for(int y = yMin; y <= yMax; ++y){
         //Bary coordinates at start of row
         //Bary coordinates at start of row
@@ -144,9 +142,9 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
 
 
                     //Update pixel buffer with clamped values 
                     //Update pixel buffer with clamped values 
                     (*pixelBuffer)(x,y) = SDL_MapRGB(mappingFormat,
                     (*pixelBuffer)(x,y) = SDL_MapRGB(mappingFormat,
-                    std::min(rgbVals.data[0],255.0f),
-                    std::min(rgbVals.data[1],255.0f),
-                    std::min(rgbVals.data[2],255.0f));
+                    clamp(gammaAdjust(rgbVals.data[0], 2.2), 0, 255.0f),
+                    clamp(gammaAdjust(rgbVals.data[1], 2.2), 0, 255.0f),
+                    clamp(gammaAdjust(rgbVals.data[2], 2.2), 0, 255.0f));
                 }   
                 }   
             }
             }
 
 
@@ -192,15 +190,24 @@ void Rasterizer::triBoundBox(int &xMax, int &xMin, int &yMax, int &yMin,Vector3f
 
 
 
 
 float Rasterizer::edge(Vector3f &a, Vector3f &b, Vector3f &c){
 float Rasterizer::edge(Vector3f &a, Vector3f &b, Vector3f &c){
-    return (b.x - a.x)*(c.y-a.y) - (b.y - a.y)*(c.x - a.x);
+    return (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x);
 }
 }
 
 
 bool Rasterizer::inside(float e, float a, float b){
 bool Rasterizer::inside(float e, float a, float b){
-    if ( e > 0) return true;
-    if ( e < 0) return false;
+    if ( e > 0 )  return true;
+    if ( e < 0 )  return false;
     if ( a > 0 )  return true;
     if ( a > 0 )  return true;
     if ( a < 0 )  return false;
     if ( a < 0 )  return false;
     if ( b > 0 )  return true;
     if ( b > 0 )  return true;
     return false;
     return false;
 }
 }
 
 
+
+float Rasterizer::clamp(float n, float lower, float upper) {
+  return std::max(lower, std::min(n, upper));
+}
+
+
+float Rasterizer::gammaAdjust(float n, float gamma) {
+  return std::pow(n, 1.0/(float)gamma)*255.0f;
+}

+ 28 - 23
src/softwareRenderer.cpp

@@ -29,21 +29,29 @@ void SoftwareRenderer::drawTriangularMesh(Model * currentModel){
     std::vector<Vector3i> * vIndices = &triMesh->vertexIndices;
     std::vector<Vector3i> * vIndices = &triMesh->vertexIndices;
     std::vector<Vector3i> * tIndices = &triMesh->textureIndices;
     std::vector<Vector3i> * tIndices = &triMesh->textureIndices;
     std::vector<Vector3i> * nIndices = &triMesh->normalsIndices;
     std::vector<Vector3i> * nIndices = &triMesh->normalsIndices;
-
-    std::vector<Vector3f> * vertices = &triMesh->vertices;
-    std::vector<Vector3f> * normals  = &triMesh->normals;
     std::vector<Vector3f> * fNormals = &triMesh->fNormals;
     std::vector<Vector3f> * fNormals = &triMesh->fNormals;
-    std::vector<Vector3f> * texels   = &triMesh->texels;
+
+    std::vector<Vector3f> * vertices   = &triMesh->vertices;
+    std::vector<Vector3f> * texels     = &triMesh->texels;
+    std::vector<Vector3f> * normals    = &triMesh->normals;
+    std::vector<Vector3f> * tangents   = &triMesh->tangents;
+    std::vector<Vector3f> * biTangents = &triMesh->biTangents;
     int numFaces = triMesh->numFaces;
     int numFaces = triMesh->numFaces;
 
 
     //Array grouping vertices together into triangle
     //Array grouping vertices together into triangle
-    Vector3f trianglePrimitive[3];
-    Vector3f normalPrim[3];
-    Vector3f uvPrim[3];
+    Vector3f trianglePrimitive[3], normalPrim[3], uvPrim[3],
+             tangentPrim[3], biTangentPrim[3];
 
 
     //Initializing shader 
     //Initializing shader 
-    BlinnPhongShader shader;
-    shader.albedo = currentModel->getAlbedo();
+    NormalMapShader shader;
+    shader.albedoT = currentModel->getAlbedo();
+    shader.normalT = currentModel->getNormal();
+    shader.MV  = (mCamera->viewMatrix)*(*(currentModel->getModelMatrix()));
+    shader.MVP = (mCamera->projectionMatrix)*shader.MV;
+    shader.V   = (mCamera->viewMatrix);
+    shader.M   = *(currentModel->getModelMatrix());
+    shader.N   = (shader.M.inverse()).transpose(); 
+    shader.cameraPos = mCamera->position;
 
 
     //Basic light direction
     //Basic light direction
     float t = static_cast<float>(SDL_GetTicks());
     float t = static_cast<float>(SDL_GetTicks());
@@ -53,17 +61,13 @@ void SoftwareRenderer::drawTriangularMesh(Model * currentModel){
     Vector3f lightDir{1, 0, 0};
     Vector3f lightDir{1, 0, 0};
     lightDir = lightDir.normalized();
     lightDir = lightDir.normalized();
 
 
-    //Building ModelViewProjection matrix
+    //Building worldToObject matrix
     Matrix4 worldToObject = (*(currentModel->getModelMatrix())).inverse();
     Matrix4 worldToObject = (*(currentModel->getModelMatrix())).inverse();
-    shader.MV  = (mCamera->viewMatrix)*(*(currentModel->getModelMatrix()));
-    shader.MVP = (mCamera->projectionMatrix)*shader.MV;
-    shader.V   = (mCamera->viewMatrix);
-    shader.N   = (shader.MV.inverse()).transpose(); 
 
 
-    //Iterate through every triangle
+    // Iterate through every triangle
     int count = 0;
     int count = 0;
 
 
-    #pragma omp parallel for private(trianglePrimitive, normalPrim, uvPrim) firstprivate(shader)
+    #pragma omp parallel for private(trianglePrimitive, normalPrim, uvPrim, tangentPrim, biTangentPrim) firstprivate(shader)
     for (int j= 0; j < numFaces; ++j){
     for (int j= 0; j < numFaces; ++j){
         //Current vertex and normal indices
         //Current vertex and normal indices
         Vector3i f = (*vIndices)[j];
         Vector3i f = (*vIndices)[j];
@@ -71,19 +75,20 @@ void SoftwareRenderer::drawTriangularMesh(Model * currentModel){
         Vector3i u = (*tIndices)[j];
         Vector3i u = (*tIndices)[j];
 
 
         //Pack vertex, normal and UV data into arrays
         //Pack vertex, normal and UV data into arrays
-        buildTri(f,trianglePrimitive, *vertices);
-        buildTri(n,normalPrim, *normals);
-        buildTri(u,uvPrim, *texels);
+        buildTri(f, trianglePrimitive, *vertices);
+        buildTri(n, normalPrim, *normals);
+        buildTri(u, uvPrim, *texels);
+        buildTri(f, tangentPrim, *tangents);
+        buildTri(f, biTangentPrim, *biTangents);
 
 
         //Early quit if 
         //Early quit if 
         if (backFaceCulling((*fNormals)[j], trianglePrimitive[0], worldToObject)) continue;
         if (backFaceCulling((*fNormals)[j], trianglePrimitive[0], worldToObject)) continue;
         ++count;
         ++count;
         //Apply vertex shader
         //Apply vertex shader
         for(int i = 0; i < 3; ++i){
         for(int i = 0; i < 3; ++i){
-            trianglePrimitive[i] = shader.vertex(trianglePrimitive[i],
-                                                normalPrim[i],
-                                                uvPrim[i],
-                                                lightDir, i);
+            trianglePrimitive[i] = shader.vertex(trianglePrimitive[i], normalPrim[i],
+                                                uvPrim[i], tangentPrim[i], 
+                                                biTangentPrim[i], lightDir, i);
         }
         }
 
 
         //Skip triangles that are outside viewing frustrum
         //Skip triangles that are outside viewing frustrum