Browse Source

Fixed pixel inaccuracies in rasterizer.

angel 7 years ago
parent
commit
b8d7094c9e
7 changed files with 63 additions and 75 deletions
  1. 3 2
      include/buffer.h
  2. 5 3
      include/rasterizer.h
  3. 1 1
      include/shader.h
  4. 5 6
      src/camera.cpp
  5. 1 1
      src/engine.cpp
  6. 47 61
      src/rasterizer.cpp
  7. 1 1
      src/softwareRenderer.cpp

+ 3 - 2
include/buffer.h

@@ -13,15 +13,16 @@ struct Buffer{
         int mHeight;
         int mPixelCount;
         int mPitch;
+        int mOrigin;
         T *buffer;
 
         T& operator()(size_t x, size_t y){
-            return buffer[y*mWidth + x];
+            return buffer[mOrigin + -y*mWidth + x];
         }
 
         Buffer(int w, int h, T * array) 
         : mWidth(w), mHeight(h), mPixelCount(w*h),
-                mPitch(w*sizeof(T)), buffer(array) 
+                mPitch(w*sizeof(T)),mOrigin(mHeight*mWidth - mWidth), buffer(array) 
         {}
 
         ~Buffer(){

+ 5 - 3
include/rasterizer.h

@@ -7,7 +7,7 @@
 #include "shader.h"
 
 //Shorthand of repeated types.
-typedef std::array<int, 3> arr3i;
+typedef std::array<float, 3> arr3f;
  
 //Takes in vertex data, rasterizes the surface and applies the fragment shader at
 //each fragment. If it passes the depth test the fragment is written to the pixel buffer.
@@ -28,13 +28,15 @@ class Rasterizer{
         static void drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint32> *pixelBuffer, Buffer<float> *zBuffer);
 
         //Transforms coordinates from NDC to pixel values(Integers)
-        static void viewportTransform(Buffer<Uint32> *pixelBuffer, Vector3f *vertices, arr3i &xV, arr3i   &yV, Vector3f  &zV);
+        static void viewportTransform(Buffer<Uint32> *pixelBuffer, Vector3f *vertices);
 
         //Given a set of vertex values, the triangle area in screen space
         //and a target point returns the barycentric coordinates.
         static void barycentric(Vector3f &lambdas, float denom, float d00, float d01, float d11, float d20, float d21);
 
-        static void triBoundBox(int &xMax, int &xMin, int &yMax, int &yMin, arr3i &xV, arr3i &yV, Buffer<Uint32> *pixelBuffer);
+        static void triBoundBox(int &xMax, int &xMin, int &yMax, int &yMin, Vector3f *vertices, Buffer<Uint32> *pixelBuffer);
+
+        static float edge(Vector3f &a, Vector3f &b, Vector3f &c);
 
     private:
         Rasterizer(){}; //Ensuring an object can never be instanced accidentally

+ 1 - 1
include/shader.h

@@ -44,7 +44,7 @@ struct GouraudShader : public IShader {
 
     bool fragment(Vector3f &bari, Vector3f &color, float &depth, Vector3f &zVerts) override{
         float intensity = bari.dotProduct(varying_intensity);
-        color = rgb;// * intensity;
+        color = rgb * intensity;
         depth = bari.dotProduct(zVerts);
         return false;
     }

+ 5 - 6
src/camera.cpp

@@ -11,14 +11,13 @@ Camera::Camera(){
 
 void Camera::update(){
     float t = static_cast<float>(SDL_GetTicks());
-    float radius = 15;
-    float camX   = std::sin(t/20000) * radius;
-    float camZ   = std::cos(t/20000) * radius;
-    position.x   = camX;
+    float radius = 12;
+    float camX   = std::sin(t/2000) * radius;
+    float camZ   = std::cos(t/2000) * radius;
+    position.x   = 0;
     position.y   = 0;
     position.z   = camZ;
-    printf("X: %f, Z: %f\n", camX, camZ);
-   // target.z     = -1000;
+    target.z     = 0;
     viewMatrix   = Matrix4::lookAt(position,target,up);
     cameraFrustrum.updatePlanes(viewMatrix, position);
 }

+ 1 - 1
src/engine.cpp

@@ -92,7 +92,7 @@ void Engine::run(){
         //Stats about frame
         end = SDL_GetTicks();
         printf("%2.1d: Loop elapsed time (ms):%d\n",count,end - start);
-        break;
+        //break;
     }
     printf("Closing engine\n");
 }

+ 47 - 61
src/rasterizer.cpp

@@ -81,77 +81,53 @@ void Rasterizer::drawWireFrame(Vector3f *vertices, IShader &shader, Buffer<Uint3
 //Draws triangles using baricentric coordinates,
 void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint32> *pixelBuffer, Buffer<float> *zBuffer){
 
-    //Converting to viewport space 
-    arr3i  xV, yV;
-    Vector3f zVerts;
-    Rasterizer::viewportTransform(pixelBuffer, vertices, xV, yV, zVerts);
-
+    Rasterizer::viewportTransform(pixelBuffer, vertices);
     //Finding triangle bounding box limits & clips it to the screen width and height
     int xMax, xMin, yMax, yMin;
-    Rasterizer::triBoundBox(xMax, xMin, yMax, yMin, xV, yV, pixelBuffer);
-
-    //Per triangle variables
-    Vector3i v0(xV[1]-xV[0], yV[1]-yV[0], 0);
-    Vector3i v1(xV[2]-xV[0], yV[2]-yV[0], 0);
-    int d00 = v0.dot2D(v0);
-    int d01 = v0.dot2D(v1);
-    int d11 = v1.dot2D(v1);
-    //printf("%d, %d, %d\n",d00, d01, d11);
-    float denom = 1.0 / (float)((d00 * d11) - (d01 *d01));
-    if (denom == INFINITY) return;
-    //printf("%lf\n", denom);
+    Rasterizer::triBoundBox(xMax, xMin, yMax, yMin, vertices, pixelBuffer);
+
     //Per fragment variables            
-    float depth = 0;
-    int d20   = 0;
-    int d21   = 0;
-    Vector3f lambdas;
+    float depth, w0, w1, w2, area;
+    Vector3f bari;
     Vector3f rgbVals;
-    Vector3i v2;
+    Vector3f point;
+    Vector3f zVals{vertices[0].z,vertices[1].z,vertices[2].z};
+    area = 1/edge(vertices[0],vertices[1],vertices[2]);
 
     //Iterating through each pixel in triangle bounding box
-    for(int y = yMin; y <= yMax; ++y){
-        for(int x = xMin; x <= xMax; ++x){
-            v2.x = x-xV[0];
-            v2.y = y-yV[0];
-            d20 = v2.dot2D(v0);
-            d21 = v2.dot2D(v1);
-            Rasterizer::barycentric(lambdas, denom, d00, d01, d11, d20, d21);
-
-            // if (lambdas.data[0] < 0 && lambdas.data[0] > -0.1 ){
-            //     lambdas.print();
-            // }
-
-            //Throw pixel away if not in triangle
-            //if( lambdas.y < 0 || lambdas.z < 0  || lambdas.x < 0 ) continue;
-            if( lambdas.y > 1 || lambdas.y < 0 || lambdas.z > 1 || lambdas.z < 0  || ((lambdas.y + lambdas.z) > 1) ) continue;
-            //if( (lambdas.x >= 0) && (lambdas.y >= 0) && (lambdas.z >= 0)){
+    for(point.y = yMin; point.y <= yMax; ++point.y){
+        for(point.x = xMin; point.x <= xMax; ++point.x){
 
-                //Run fragment shader
-                shader.fragment(lambdas, rgbVals, depth, zVerts);
+            bari.x = edge(vertices[1], vertices[2], point);
+            bari.y = edge(vertices[2], vertices[0], point);
+            bari.z = edge(vertices[0], vertices[1], point);
 
+            //Only draw if inside pixel
+            if(bari.x >= 0 && bari.y >= 0 && bari.z >= 0 ){
+                //Run fragment shader
+                bari = bari* area;
+                shader.fragment(bari, rgbVals, depth, zVals);
+                
                 //Zbuffer check
-                if((*zBuffer)(x,y) < depth){
+                if((*zBuffer)(point.x,point.y) < depth){
                     if(depth <= 1.0){
-                        (*zBuffer)(x,y) = depth;
-                        (*pixelBuffer)(x,y) = SDL_MapRGBA(mappingFormat,
+                        (*zBuffer)(point.x,point.y) = depth;
+                        (*pixelBuffer)(point.x,point.y) = SDL_MapRGBA(mappingFormat,
                         rgbVals.data[0],rgbVals.data[1],rgbVals.data[2],0xFF);
                     }   
                 }
-            
-
-             
+            }
         }
     }
 }  
 
-void Rasterizer::viewportTransform(Buffer<Uint32> *pixelBuffer, Vector3f *vertices,arr3i   &xV,arr3i  &yV, Vector3f   &zV){
+void Rasterizer::viewportTransform(Buffer<Uint32> *pixelBuffer, Vector3f *vertices){
     for(int i = 0; i < 3; ++i){
-        xV[i] = ((vertices[i].x + 1 ) * pixelBuffer->mWidth * 0.5);
-        yV[i] = ((-vertices[i].y + 1 ) * pixelBuffer->mHeight * 0.5);
-        zV.data[i] = vertices[i].z;
-
-        printf("%f , %f \n", vertices[i].x, ((vertices[i].x + 1 ) * pixelBuffer->mWidth * 0.5));
+        vertices[i].x = ((vertices[i].x + 1 ) * pixelBuffer->mWidth * 0.5);
+        vertices[i].y = ((vertices[i].y + 1 ) * pixelBuffer->mHeight * 0.5);
     }
+    //Swap because inverting y changes winding order
+
 }
 
 //Calculates baricentric coordinates of triangles using the cross product
@@ -161,18 +137,28 @@ void Rasterizer::barycentric(Vector3f &lambdas, float denom, float d00, float d0
     lambdas.data[0] = 1.0f - lambdas.data[1] - lambdas.data[2];
 }
 
-void Rasterizer::triBoundBox(int &xMax, int &xMin, int &yMax, int &yMin, arr3i &xV, arr3i &yV, Buffer<Uint32> *pixelBuffer){
-    xMax = *std::max_element(xV.begin(),xV.end());
-    xMax = (xMax > pixelBuffer->mWidth) ? pixelBuffer->mWidth -1 : xMax;
+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,}));
+    xMax = std::max({vertices[0].x, vertices[1].x, vertices[2].x});
+    xMin = std::min({vertices[0].x, vertices[1].x, vertices[2].x});
+
+    // yMax = std::ceil(std::max({vertices[0].y, vertices[1].y, vertices[2].y,}));
+    // yMin = std::ceil(std::min({vertices[0].y, vertices[1].y, vertices[2].y,}));
+    yMax = std::max({vertices[0].y, vertices[1].y, vertices[2].y});
+    yMin = std::min({vertices[0].y, vertices[1].y, vertices[2].y});
 
-    xMin = *std::min_element(xV.begin(),xV.end());
-    xMin = (xMin < 0) ? 0 : xMin;
+    //Clip against screen
+    xMax = std::min(xMax, pixelBuffer->mWidth -1);
+    xMin = std::max(xMin, 0);
+
+    yMax = std::min(yMax, pixelBuffer->mHeight -1);
+    yMin = std::max(yMin, 0);
+}
 
-    yMax = *std::max_element(yV.begin(),yV.end());
-    yMax = (yMax > pixelBuffer->mHeight) ? pixelBuffer->mHeight -1 : yMax;
 
-    yMin = *std::min_element(yV.begin(),yV.end());
-    yMin = (yMin < 0) ? 0 : yMin;
+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);
 }
 
 

+ 1 - 1
src/softwareRenderer.cpp

@@ -53,7 +53,7 @@ void SoftwareRenderer::drawTriangularMesh(Mesh* triMesh){
         buildTri(n,normalPrim, *normals);
 
         //Skip faces that are pointing away from us
-        if (backFaceCulling(trianglePrimitive)) continue;
+       if (backFaceCulling(trianglePrimitive)) continue;
 
         //Apply vertex shader
         for(int i = 0; i < 3; ++i){