Преглед изворни кода

Added camera controls and some optimizations.

angel пре 7 година
родитељ
комит
f7baeb9a0f

+ 1 - 1
CMakeLists.txt

@@ -10,7 +10,7 @@ include_directories(${SDL2_INCLUDE_DIR} include libs)
 
 file(GLOB source_files "*.h" "*.cpp" "src/*.cpp" "include/*.h" "libs/*.h")
 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 -ffast-math")
 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g ")
 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -g ")
 target_link_libraries(softwareRenderer ${SDL2_LIBRARY})

+ 10 - 1
include/camera.h

@@ -12,7 +12,7 @@ struct Camera{
     bool checkVisibility(AABox *bounds);
 
     //In the future user input should control this. For now just simple movement
-    void update();
+    void update(unsigned int deltaT);
 
     Matrix4 viewMatrix;
     Matrix4 projectionMatrix;
@@ -21,6 +21,15 @@ struct Camera{
     Vector3f position{0,0,8};
     Vector3f target{0,0,0};
     Vector3f up{0,1,0};
+    Vector3f front{0, 0, -1};
+    Vector3f side;
+
+    //Values related to orbiting mode
+    float radius = 2;
+    bool orbiting = true;
+
+    //Momentary fixed camera speed (FPS dependent)
+    float camSpeed = 0.1f;
 
     Frustrum cameraFrustrum{DisplayManager::SCREEN_ASPECT_RATIO};
 };

+ 1 - 1
include/geometry.h

@@ -33,7 +33,7 @@ class Frustrum{
         };
     public:
         float  fov, AR, near, far , nearH, nearW, farH, farW;
-        Frustrum(float ratio): fov(45), near(0.1), far(100), AR(ratio){};
+        Frustrum(float ratio): fov(50), near(0.1), far(100), AR(ratio){};
         Plane pl[6];
 
         void setCamInternals();

+ 5 - 2
include/inputManager.h

@@ -3,6 +3,7 @@
 
 //Headers
 #include "sceneManager.h"
+#include "camera.h"
 #include "SDL.h"
 
 class InputManager{
@@ -17,10 +18,12 @@ class InputManager{
         void shutDown();
 
         //Processes all the SDL events that have ocurred in the given frame
-        void processInput(bool &done);
+        void processInput(bool &done, unsigned int deltaT);
     private:
+        
         SceneManager *sceneController;
-        void handleEvent(SDL_Event * event, bool &done);
+        Camera *sceneCamera;
+        void handleEvent(SDL_Event * event, bool &done, unsigned int deltaT);
 };
 
 

+ 1 - 1
include/rasterizer.h

@@ -38,7 +38,7 @@ class Rasterizer{
 
         static float clamp(float n, float lower, float upper);
 
-        static float gammaAdjust(float n, float gamma);
+        static float gammaAdjust(float n);
 
     private:
         Rasterizer(){}; //Ensuring an object can never be instanced accidentally

+ 1 - 1
include/scene.h

@@ -18,7 +18,7 @@ class Scene{
         ~Scene();
 
         //Updates all models, lights and cameras in scene
-        void update();
+        void update(unsigned int deltaT);
 
         //Returns the list of models not culled by the frustrum
         std::queue<Model*>* getVisiblemodels();

+ 1 - 1
include/sceneManager.h

@@ -19,7 +19,7 @@ class SceneManager{
         bool switchScene(std::string sceneID);
 
         // Update current scene
-        void update();
+        void update(unsigned int deltaT);
 
         //Called by the rendermanager to prep the render queue 
         Scene* getCurrentScene();

+ 15 - 13
include/shader.h

@@ -256,7 +256,9 @@ struct PBRShader : public IShader {
 
     //BRDF functions
     Vector3f fresnelSchlick(float cosTheta, Vector3f &fresnel0 ){
-        return fresnel0 + (Vector3f(1.0)- fresnel0)* std::pow(1.0 - cosTheta, 5.0);
+        //return fresnel0 + (Vector3f(1.0)- fresnel0)* std::pow(2.0,(-5.55473*cosTheta * cosTheta) - 6.98316*cosTheta);
+        float invcCosTheta = 1.0 - cosTheta;
+        return fresnel0 + (Vector3f(1.0)- fresnel0) * (invcCosTheta * invcCosTheta * invcCosTheta * invcCosTheta * invcCosTheta);
     }
     float distributionGGX(Vector3f normal, Vector3f halfway, float roughness){
         float a      = roughness*roughness;
@@ -265,16 +267,16 @@ struct PBRShader : public IShader {
         float NdotH2 = NdotH*NdotH;
         
         float denom = (NdotH2 * (a2 - 1.0) + 1.0);
-        denom = M_PI * denom * denom;
+        denom = M_1_PI / (denom * denom);
         
-        return a2 / denom;
+        return a2 * denom;
     }
     float GeometrySchlickGGX(float NdotV, float roughness){
         float r = (roughness + 1.0); 
         float k = (r*r) / 8.0; //Only useful for direct lighting must be changed in ibr
-        float denom = NdotV * (1.0 - k) + k;
+        float denom = 1 / (NdotV * (1.0 - k) + k);
         
-        return NdotV / denom;
+        return NdotV * denom;
     }
     float GeometrySmith(float roughness){
         return GeometrySchlickGGX(nDotL, roughness) * GeometrySchlickGGX(nDotV, roughness);
@@ -296,7 +298,7 @@ struct PBRShader : public IShader {
             int indc2 = (lIndex*3) + index;
             lightDirVal[indc2]  = TBN.matMultDir(lightPos[lIndex]);
         }
-        viewDir[index]   = TBN.matMultVec(cameraPos - M.matMultVec(vertex));
+        viewDir[index]   = TBN.matMultDir(cameraPos - M.matMultVec(vertex));
         
         return MVP.matMultVec(vertex);
     }
@@ -312,12 +314,12 @@ struct PBRShader : public IShader {
         vTexture = std::modf(interpCoords.y, &intPart);
 
         //Reading data from textures for use in lighting calculations
-        interpCol    = albedoT->getPixelVal(uTexture, vTexture);
-        interpAO     = ambientOT->getIntensityVal(uTexture, vTexture);
-        interpRough  = roughT->getIntensityVal(uTexture, vTexture);;
-        interpMetal  = metalT->getIntensityVal(uTexture, vTexture);
-        interpNormal = normalT->getPixelVal(uTexture, vTexture);
-        interpNormal = interpNormal.normalized();
+        interpCol     = albedoT->getPixelVal(uTexture, vTexture);
+        interpAO      = ambientOT->getIntensityVal(uTexture, vTexture);
+        interpRough   = roughT->getIntensityVal(uTexture, vTexture);;
+        interpMetal   = metalT->getIntensityVal(uTexture, vTexture);
+        interpNormal  = normalT->getPixelVal(uTexture, vTexture);
+        interpNormal  = interpNormal.normalized();
         interpViewDir = interpViewDir.normalized();
 
         //Setting up Direct Lighting variables
@@ -330,7 +332,7 @@ struct PBRShader : public IShader {
             nDotL = std::max(interpNormal.dotProduct(interpLightDir), 0.0f);
             F0corrected = (F0 * (1.0f-interpMetal)) + (interpCol * interpMetal);//Varying f0 based on metallicness of surface
 
-            //We assume the only light in the scene is the sun so there is no attenuation
+            //We assume the only lights in the scene are far away so there is no attenuation
             
             //Setting up BRDF
             F   = fresnelSchlick(std::max(halfwayDir.dotProduct(interpViewDir), 0.0f), F0corrected);

+ 3 - 0
include/vector3D.h

@@ -54,6 +54,9 @@ struct Vector3{
     void operator+=(const Vector3 &rhs) 
     {(*this) = (*this) + rhs ;}
 
+    void operator-=(const Vector3 &rhs) 
+    {(*this) = (*this) - rhs ;}
+
     Vector3 operator*(const Vector3 &rhs) const
     {return Vector3(x * rhs.x, y * rhs.y, z * rhs.z);}
 

BIN
scenes/teapot/.teapot_mesh.obj.swp


+ 14 - 12
src/camera.cpp

@@ -1,23 +1,25 @@
 #include "camera.h"
-#include "SDL.h"
-
 
 Camera::Camera(){
-    viewMatrix = Matrix4::lookAt(position,target,up);
+    side = front.crossProduct(up).normalized();
+    viewMatrix = Matrix4::lookAt(position, target, up);
     projectionMatrix = Matrix4::projectionMatrix(cameraFrustrum.fov, cameraFrustrum.AR, cameraFrustrum.near, cameraFrustrum.far);
     cameraFrustrum.setCamInternals();
     cameraFrustrum.updatePlanes(viewMatrix, position);
 }
 
-void Camera::update(){
-    float t = static_cast<float>(SDL_GetTicks());
-    float radius = 4;
-    float camX   = std::sin(t/6000) * radius;
-    float camZ   = std::cos(t/6000) * radius;
-    position.x   = camX;
-    position.y   = camX;
-    position.z   = camZ;
-    target.z     = 0;
+void Camera::update(unsigned int deltaT){
+    if(orbiting){
+        float t = static_cast<float>(SDL_GetTicks());
+        float camX   = std::sin(t/6000) * radius;
+        float camZ   = std::cos(t/6000) * radius;
+        position.x   = camX;
+        position.y   = camX;
+        position.z   = camZ;
+    }
+    else{
+        target = position + front;
+    }
     viewMatrix   = Matrix4::lookAt(position,target,up);
     cameraFrustrum.updatePlanes(viewMatrix, position);
 }

+ 7 - 7
src/engine.cpp

@@ -61,7 +61,7 @@ void Engine::run(){
 
     //Iteration and time keeping counters
     int count = 0;
-    unsigned int diff = 0;
+    unsigned int deltaT = 0;
     unsigned int start = 0;;
     unsigned int total = 0;
 
@@ -72,19 +72,19 @@ void Engine::run(){
 
         //Handle all user input
         //Switches scene too
-        gInputManager.processInput(done);
+        gInputManager.processInput(done, deltaT);
         
         //Update all models, camera and lighting in the current scene
-        gSceneManager.update();
+        gSceneManager.update(deltaT);
 
         //Update Rendering Queue and draw each item 
         gRenderManager.render();
 
         //Stats about frame
-        diff = SDL_GetTicks() - start;
-        printf("%2.1d: Loop elapsed time (ms):%d\n",count, diff);
-        total += diff;
-
+        deltaT = SDL_GetTicks() - start;
+        printf("%2.1d: Loop elapsed time (ms):%d\n",count, deltaT);
+        total += deltaT;
+        if(count == 500) break;
     }
 
     printf("Closing down engine.\n");

+ 77 - 8
src/inputManager.cpp

@@ -4,8 +4,9 @@ InputManager::InputManager(){}
 InputManager::~InputManager(){}
 
 bool InputManager::startUp(SceneManager &sceneManager){
-
     sceneController = &sceneManager;
+    sceneCamera = (sceneController->getCurrentScene()->getCurrentCamera());
+
     return true;
 }
 
@@ -13,7 +14,7 @@ void InputManager::shutDown(){
     //Nothing to do yet
 }
 
-void InputManager::processInput(bool &done){
+void InputManager::processInput(bool &done, unsigned int deltaT){
     SDL_Event event;
     while(SDL_PollEvent(&event)){
 
@@ -25,21 +26,23 @@ void InputManager::processInput(bool &done){
         //Handle any other relevant input data 
         //Keypresses, mouse etc
         else{
-            handleEvent(&event, done);
+            handleEvent(&event, done, deltaT);
         }
     }
 }
 
 //Handles user keyboard input
 //TODO: handle mouse input 
-void InputManager::handleEvent(SDL_Event * event, bool &done ){
-
+void InputManager::handleEvent(SDL_Event * event, bool &done, unsigned int deltaT){
+    float speed = sceneCamera->camSpeed;// * deltaT;
     //Handling keyboard input
     if( event->type == SDL_KEYDOWN ){
+        //keys 1-5 switch to different scene
+        //WASD control strafe movement
         std::string sceneID = "0";
-        //Switch scenes based on keypresses
         switch( event->key.keysym.sym )
-        {
+        {   
+            //SCENE CODE
             case SDLK_1:
             sceneID = "teapot";
             break;
@@ -47,10 +50,73 @@ void InputManager::handleEvent(SDL_Event * event, bool &done ){
             case SDLK_2:
             sceneID = "firehydrant";
             break;
+
+            case SDLK_3:
+            sceneID = "firehydrant";
+            break;
+
+            case SDLK_4:
+            sceneID = "firehydrant";
+            break;
+
+            case SDLK_5:
+            sceneID = "firehydrant";
+            break;
+
+            //WINDOW CONTROL OPTIONS
+            case SDLK_ESCAPE:
+            done = true;
+            return; 
+
+            //MOVEMENT CONTROLS (STRAFING)
+            case SDLK_w:
+            if(sceneCamera->orbiting){
+                sceneCamera->radius += sceneCamera->radius * speed;
+            }
+            else{
+                sceneCamera->position += sceneCamera->front * speed;
+            }
+            break;
+
+            case SDLK_s:
+            if(sceneCamera->orbiting){
+                sceneCamera->radius -= sceneCamera->radius * speed;
+            }
+            else{
+                sceneCamera->position -= sceneCamera->front * speed;
+            }
+            break;
+
+            case SDLK_a:
+            sceneCamera->position -= sceneCamera->side * speed;
+            break;
+
+            case SDLK_d:
+            sceneCamera->position += sceneCamera->side * speed;
+            break;
+
+            //CAMERA CONTROLS (RESET AND ORBITING)
+            case SDLK_r:
+            sceneCamera->position = Vector3f(0, 0, 8.0);
+            sceneCamera->target.zero();  
+            sceneCamera->radius = 3;  
+            break;
+
+            case SDLK_TAB:
+            sceneCamera->orbiting = !sceneCamera->orbiting;
+            sceneCamera->position = Vector3f(0, 0, 8.0);
+            sceneCamera->target.zero();
+            sceneCamera->radius = 3;    
+            break;
+
+            default:
+            break;
+
         }
 
+        //Only switch scene if a scene-key (1-5) was pressed
+        //Exit if the scene could not be loaded for some reason
         if ( sceneID != "0" ){
-
             if( !sceneController->switchScene(sceneID) ){
                 printf("Failed to switch scene! Quitting.\n");
                 done = true;
@@ -58,6 +124,9 @@ void InputManager::handleEvent(SDL_Event * event, bool &done ){
             }
             else{
                 printf("Loaded %s Scene.\n", sceneID.c_str());
+                sceneCamera = (sceneController->getCurrentScene()->getCurrentCamera());
+                sceneCamera->position = Vector3f(0, 0, 8.0);
+                sceneCamera->target.zero();
             }
 
         }

+ 9 - 8
src/rasterizer.cpp

@@ -87,7 +87,7 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
 
     //Per fragment variables
     float depth, uPers, vPers, areaPers, count = 0; //u, v, are perspective corrected
-    Vector3f e, e_row, e_init, f;
+    Vector3f e, e_row, f;
     Vector3f rgbVals{255,255,255};
     
 
@@ -123,7 +123,8 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
 
         for(int x = xMin; x <= xMax; ++x){
             //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) ){
+            // if(inside(e.x, A01, B01) && inside(e.y, A12, B12) && inside(e.z, A20, B20) ){
+            if( (e.x >= 0) && (e.y >= 0 ) && (e.z >= 0 )){
 
                 //Zbuffer check
                 depth = (e*area).dotProduct(zVals);
@@ -136,13 +137,13 @@ void Rasterizer::drawTriangles(Vector3f *vertices, IShader &shader, Buffer<Uint3
                     uPers =  f.data[1] * areaPers;
                     vPers =  f.data[2] * areaPers;
 
-                    //Run fragment shader
+                    //Run fragment shader (U, v are barycentric coords)
                     rgbVals = shader.fragment(uPers , vPers);
                     //Update pixel buffer with clamped values 
                     (*pixelBuffer)(x,y) = SDL_MapRGB(mappingFormat,
-                    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));//
+                    clamp(gammaAdjust(rgbVals.data[0]), 0, 255.0f), //
+                    clamp(gammaAdjust(rgbVals.data[1]), 0, 255.0f),//
+                    clamp(gammaAdjust(rgbVals.data[2]), 0, 255.0f));//
                     //(*pixelBuffer)(x,y) = SDL_MapRGB(mappingFormat,0xFF, 0xFF, 0xFF);
                 }   
             }
@@ -207,6 +208,6 @@ float Rasterizer::clamp(float n, float lower, float upper) {
 }
 
 
-float Rasterizer::gammaAdjust(float n, float gamma) {
-  return std::pow(n, 1.0/gamma)*255.0f;
+float Rasterizer::gammaAdjust(float n) {
+  return std::pow(n, 1.0/2.2)*255.0f;
 }

+ 3 - 4
src/scene.cpp

@@ -32,8 +32,8 @@ Scene::~Scene(){
     }
 }
 
-void Scene::update(){
-    mainCamera.update();
+void Scene::update(unsigned int deltaT){
+    mainCamera.update(deltaT);
     for(Model *models : modelsInScene){
         models->update();
     }
@@ -53,10 +53,9 @@ void Scene::loadSceneModel(const std::string &baseFilePath, const TransformParam
 }
 
 void Scene::frustrumCulling(){
-    bool visible = true;
     for(Model *model : modelsInScene){
 
-        visible = mainCamera.checkVisibility(model->getBounds());
+        bool visible = mainCamera.checkVisibility(model->getBounds());
 
         if (visible) {
             visibleModels.push(model);

+ 2 - 2
src/sceneManager.cpp

@@ -35,8 +35,8 @@ bool SceneManager::loadScene(std::string sceneID){
     return  !currentScene->checkIfEmpty(); //True if empty, so it's negated for startup
 }
 
-void SceneManager::update(){
-    currentScene->update();
+void SceneManager::update(unsigned int deltaT){
+    currentScene->update(deltaT);
 }
 
 Scene* SceneManager::getCurrentScene(){