Kaynağa Gözat

Added perspective correct interp, improved raster and specular.

angel 7 yıl önce
ebeveyn
işleme
f8b0126afb

+ 24 - 34
include/shader.h

@@ -10,7 +10,7 @@
 struct IShader {
     virtual ~IShader() {};
     virtual Vector3f vertex(Vector3f &vertex, Vector3f &normals, Vector3f &textureVals, Vector3f &light, int i) = 0;
-    virtual bool fragment(const Vector3f &bari, Vector3f &color, float &depth, Vector3f &zVerts) = 0;
+    virtual Vector3f fragment(float u, float v) = 0;
 };
 
 //Simplest shader. Calculates light intensity per triangle.
@@ -24,10 +24,8 @@ struct FlatShader : public IShader {
         return MVP.matMultVec(vertex); //Transforms verts into projected space
     }
 
-    bool fragment(const Vector3f &bari, Vector3f &color, float &depth, Vector3f &zVerts) override{
-        depth = bari.dotProduct(zVerts);
-        color = rgb*varIntensity;
-        return false;
+    Vector3f fragment(float u, float v) override{
+        return rgb*varIntensity;
     }
 
 };
@@ -52,19 +50,16 @@ struct GouraudShader : public IShader {
         return MVP.matMultVec(vertex);
     }
 
-    bool fragment(const Vector3f &bari, Vector3f &color, float &depth, Vector3f &zVerts) override{
+    Vector3f fragment(float u, float v) override{
         ambient = lightColor1 * ambientStrength;
 
-        diffStrength = bari.dotProduct(varying_diffuse);
+        diffStrength = varying_diffuse.x + u*(varying_diffuse.y - varying_diffuse.x) + v*(varying_diffuse.z - varying_diffuse.x);
         diffuse = lightColor2 * diffStrength;
 
-        spec = bari.dotProduct(varying_specular);
+        spec = varying_specular.x + u*(varying_specular.y - varying_specular.x) + v*(varying_specular.z - varying_specular.x);
         specular = lightColor3 * (specularStrength * spec);
 
-        color = (ambient + diffuse + specular) * rgb;
-
-        depth = bari.dotProduct(zVerts);
-        return false;
+        return (ambient + diffuse + specular) * rgb;
     }
 
 };
@@ -87,10 +82,10 @@ struct PhongShader : public IShader {
         return MVP.matMultVec(vertex);
     }
 
-    bool fragment(const Vector3f &bari, Vector3f &color, float &depth, Vector3f &zVerts) override{
+    Vector3f fragment(float u, float v) override{
         //Interpolated stuff
-        interpNormal  = (normals[0] * bari.x) + (normals[1] * bari.y)  + (normals[2] * bari.z);
-        interpViewDir = (viewDir[0] * bari.x) + (viewDir[1] * bari.y)  + (viewDir[2] * bari.z);
+        interpNormal = normals[0] + (normals[1] - normals[0])* u + (normals[2] - normals[0]) * v;
+        interpViewDir = viewDir[0] + (viewDir[1] - viewDir[0])* u + (viewDir[2] - viewDir[0]) * v;
         //Ambient 
         ambient = lightColor * ambientStrength;
 
@@ -103,10 +98,7 @@ struct PhongShader : public IShader {
         spec = std::pow( std::max( (-interpViewDir.normalized()).dotProduct(reflectDir), 0.0f), 50.0f);
         specular = lightColorSpec * (specularStrength * spec);
 
-        color = (ambient + diffuse + specular) * rgb;
-
-        depth = bari.dotProduct(zVerts);
-        return false;
+        return (ambient + diffuse + specular) * rgb;
     }
 
 };
@@ -116,12 +108,13 @@ struct PhongShader : public IShader {
 struct BlinnPhongShader : public IShader {
     Texture *albedo;
     Matrix4 MVP, MV, V, N;
-    float ambientStrength = 0.05, diffStrength, spec,shininess = 200;
+    float ambientStrength = 0.05, diffStrength=1 , specularStrength= 0.5;
+    float diff, spec, shininess = 128;
     Vector3f normals[3], viewDir[3], UV[3];
     Vector3f ambient, diffuse, specular, interpNormal, interpViewDir, interpUV;
-    Vector3f lightColor{1,1,1},lightColorSpec{1,1,1};
+    Vector3f lightColor{1,1,1};
     Vector3f halfwayDir, lightDir;
-    Vector3f rgb{255,255,255};
+    Vector3f interpCol, white{255,255,255};
 
     Vector3f vertex(Vector3f &vertex, Vector3f &normal, Vector3f &textureVals, Vector3f &light, int index) override{
         normals[index] = N.matMultDir(normal).normalized();
@@ -131,31 +124,28 @@ struct BlinnPhongShader : public IShader {
         return MVP.matMultVec(vertex);
     }
 
-    bool fragment(const Vector3f &bari, Vector3f &color, float &depth, Vector3f &zVerts) override{
+    Vector3f fragment(float u, float v) override{
         //Interpolated stuff
-        interpNormal  = ((normals[0] * bari.x) + (normals[1] * bari.y)  + (normals[2] * bari.z)).normalized();
-        interpViewDir = (viewDir[0] * bari.x) + (viewDir[1] * bari.y)  + (viewDir[2] * bari.z);
-        interpUV = (UV[0] * bari.x) + (UV[1] * bari.y)  + (UV[2] * bari.z);
+        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;
         //Albedo
-        rgb = albedo->getPixelVal(interpUV.x, interpUV.y);
+        interpCol = albedo->getPixelVal(interpUV.x, interpUV.y);
         //rgb.print();
 
         //Ambient 
         ambient = lightColor * ambientStrength;
 
         //Diffuse
-        diffStrength = std::max(0.0f, interpNormal.dotProduct(lightDir));
-        diffuse = lightColor * diffStrength;
+        diff = std::max(0.0f, interpNormal.dotProduct(lightDir));
+        diffuse = lightColor * diff * diffStrength;
         
         //Specular
         halfwayDir = (lightDir -interpViewDir).normalized();
         spec = std::pow(std::max(0.0f, interpNormal.dotProduct(halfwayDir)), shininess);
-        specular = lightColorSpec * spec;
-
-        color = (ambient + diffuse + specular) * rgb;
+        specular = lightColor * spec * specularStrength;
 
-        depth = bari.dotProduct(zVerts);
-        return false;
+        return (ambient + diffuse) * interpCol + specular * white;
     }
 
 };

+ 0 - 1
include/vector3D.h

@@ -33,7 +33,6 @@ struct Vector3{
         x /= w;
         y /= w;
         z /= w;
-        w  = 1;
         return *this;
     }
 

BIN
models/.FireHydrantMesh.obj.swp


+ 2 - 2
src/camera.cpp

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

+ 31 - 18
src/rasterizer.cpp

@@ -78,11 +78,17 @@ void Rasterizer::drawWireFrame(Vector3f *vertices, IShader &shader, Buffer<Uint3
     drawLine(vertices[0], vertices[2], blue, pixelBuffer);
 }  
 
-//Draws triangles using baricentric coordinates,
+//Draws triangles
 void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint32> *pixelBuffer, Buffer<float> *zBuffer){
-    //Per fragment variables            
-    float depth, area;
-    Vector3f e, e_row, rgbVals{255,255,255};
+    //Per triangle variables
+    float area;
+    Vector3f hW{1/vertices[0].w, 1/vertices[1].w, 1/vertices[2].w};
+
+    //Per fragment variables
+    float depth, uPers, vPers, areaPers; //u, v, are perspective corrected
+    Vector3f e, e_row, f;
+    Vector3f rgbVals{255,255,255};
+    
 
     //Transform into viewport coordinates 
     Rasterizer::viewportTransform(pixelBuffer, vertices);
@@ -101,7 +107,7 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
     float A12 = vertices[1].y - vertices[2].y, B12= vertices[2].x - vertices[1].x;
     float A20 = vertices[2].y - vertices[0].y, B20= vertices[0].x - vertices[2].x;
 
-    //Bary coordinates at 
+    //Edge values at the first corner of the bounding box
     Vector3f point{(float)xMin, (float)yMin, 0};
     e_row.x = edge(vertices[1], vertices[2], point);
     e_row.y = edge(vertices[2], vertices[0], point);
@@ -120,19 +126,27 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
             //Only draw if inside pixel and following top left rule
             if(inside(e.x, A01, B01) && inside(e.y, A12, B12) && inside(e.z, A20, B20) ){
 
-                //Run fragment shader
-                shader.fragment((e*area), rgbVals, depth, zVals);
                 //Zbuffer check
-                if((*zBuffer)(point.x,point.y) < depth){
-                    if(depth <= 1.0){
-                        (*zBuffer)(point.x,point.y) = depth;
-                        (*pixelBuffer)(point.x,point.y) = SDL_MapRGBA(mappingFormat,
-                        std::min(rgbVals.data[0],255.0f),
-                        std::min(rgbVals.data[1],255.0f),
-                        std::min(rgbVals.data[2],255.0f),
-                        0xFF);
-                    }   
-                }
+                depth = (e*area).dotProduct(zVals);
+                if((*zBuffer)(point.x,point.y) < depth &&  depth <= 1.0){
+                    (*zBuffer)(point.x,point.y) = depth;
+
+                    //Get perspective correct barycentric coords
+                    f = e * hW;
+                    areaPers = 1 / (f.data[0] + f.data[1] + f.data[2]);
+                    uPers =  f.data[1] * areaPers;
+                    vPers =  f.data[2] * areaPers;
+
+                    //Run fragment shader
+                    rgbVals = shader.fragment(uPers , vPers);
+
+                    //Update pixel buffer with clamped values 
+                    (*pixelBuffer)(point.x,point.y) = SDL_MapRGBA(mappingFormat,
+                    std::min(rgbVals.data[0],255.0f),
+                    std::min(rgbVals.data[1],255.0f),
+                    std::min(rgbVals.data[2],255.0f),
+                    0xFF);
+                }   
             }
 
             //One step to the right
@@ -156,7 +170,6 @@ void Rasterizer::viewportTransform(Buffer<Uint32> *pixelBuffer, Vector3f *vertic
 }
 
 
-
 void Rasterizer::triBoundBox(int &xMax, int &xMin, int &yMax, int &yMin,Vector3f *vertices, Buffer<Uint32> *pixelBuffer){
     xMax = std::ceil(std::max({vertices[0].x, vertices[1].x, vertices[2].x,}));
     xMin = std::ceil(std::min({vertices[0].x, vertices[1].x, vertices[2].x,}));

+ 1 - 1
src/softwareRenderer.cpp

@@ -47,7 +47,7 @@ void SoftwareRenderer::drawTriangularMesh(Model * currentModel){
     float radius = 1;
     float lX   = std::sin(t/4000) * radius;
     float lY   = std::cos(t/4000) * radius;
-    Vector3f lightDir{1, 1, 0};
+    Vector3f lightDir{1, 0, 0};
     lightDir = lightDir.normalized();
 
     //Building ModelViewProjection matrix

+ 2 - 1
src/texture.cpp

@@ -3,13 +3,14 @@
 #include "stb_image.h"
 
 Texture::Texture(std::string path){
+    stbi_set_flip_vertically_on_load(true);  
     pixelData = stbi_load(path.c_str(), &width, &height, &channels, 0);
 }
 
 Vector3f Texture::getPixelVal(float u, float v){
     float intpart;
     int uInt = std::modf(u, &intpart) * (width-1); 
-    int vInt = (1 - std::modf(v, &intpart)) * (height-1);
+    int vInt = std::modf(v, &intpart) * (height-1);
     int index = (vInt*width + uInt)*3;
     //printf("%d, %d, %d, %x, %x, %x\n",vInt, uInt, index ,pixelData[index],pixelData[index+1],pixelData[index+2]);
     return Vector3f{pixelData[index], pixelData[index+1], pixelData[index+2]};