Advertisement
ehzcl

camera.h

Dec 21st, 2019
599
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.68 KB | None | 0 0
  1. #ifndef CAMERAH
  2. #define CAMERAH
  3. #include <limits.h>
  4. #include "vec3.h"
  5. #include "vec2.h"
  6. #include "matrix44.h"
  7. #include "object.h"
  8. #include "algorithm"
  9. #ifdef _WIN32 || WIN32
  10. #include <SDL.h>
  11. #elif defined(__unix__)
  12. #include <SDL2/SDL.h>
  13. #endif
  14.  
  15. #define INF (unsigned)!((int)0)
  16.  
  17. const int WIDTH = 600;
  18. const int HEIGHT = 400;
  19. const int INSIDE = 0; // 0000
  20. const int LEFT = 1;   // 0001
  21. const int RIGHT = 2;  // 0010
  22. const int BOTTOM = 4; // 0100
  23. const int TOP = 8;    // 1000
  24.  
  25. vec3 frameBuffer[WIDTH * HEIGHT];
  26. float zBuffer[WIDTH * HEIGHT];
  27.  
  28. class camera
  29. {
  30. public:
  31.     int imgWidth, imgHeight;
  32.     float fov, _near, _far;
  33.     float bottom, left, top, right;
  34.     matrix44 camToWorld;
  35.     matrix44 worldToCamera;
  36.  
  37.     vec3 _from, _at, _up;
  38.     vec3 axisX, axisY, axisZ;
  39.  
  40. public:
  41.     camera();
  42.     camera(const vec3 &from, const vec3 &at, const vec3 &up,
  43.            const float &f, const float &n, const float &far,
  44.            const int &iwidth, const int &iheight) : fov(f), _near(n), imgWidth(iwidth), imgHeight(iheight),
  45.                                                     _from(from), _at(at), _up(up), _far(far)
  46.     {
  47.         look_at(from, at, up);
  48.     }
  49.  
  50.     void look_at(const vec3 &from, const vec3 &at, const vec3 &up)
  51.     {
  52.         axisZ = from - at;
  53.         axisZ.make_unit_vector();
  54.  
  55.         axisY = up - ((dot(up, axisZ) / dot(axisZ, axisZ)) * axisZ);
  56.         axisY.make_unit_vector();
  57.  
  58.         axisX = cross(axisY, axisZ);
  59.         axisX.make_unit_vector();
  60.  
  61.         float i = 1;
  62.  
  63.         camToWorld = matrix44(
  64.             axisX.x(), axisX.y(), axisX.z(), 0,
  65.             axisY.x(), axisY.y(), axisY.z(), 0,
  66.             axisZ.x(), axisZ.y(), axisZ.z(), 0,
  67.             from.x(), from.y(), from.z(), 1);
  68.  
  69.         worldToCamera = camToWorld.inverse();
  70.     }
  71.  
  72.     bool compute_pixel_coordinates(const vec3 &pWorld, vec2 &pRaster, float &z)
  73.     {
  74.         vec3 screen, projPerspectiva, pJanela;
  75.  
  76.           if (pWorld.z() >= _from.z())
  77.         { // pois o Z é negativo
  78.             return false;
  79.         }
  80.  
  81.         worldToCamera.mult_point_matrix(pWorld, screen);
  82.  
  83.         z = -screen.e[2];
  84.  
  85.         projPerspectiva = vec3(
  86.             screen.x() * (_near / screen.z()),
  87.             screen.y() * (_near / screen.z()),
  88.             _near);
  89.  
  90.         matrix44 applicationWindowMatrix = matrix44(
  91.             (2 * _near) / (right - left), 0, 0, 0,
  92.             0, (2 * _near) / (bottom - top), 0, 0,
  93.             -(right + left) / (right - left), -(bottom + top) / (bottom - top), (_far + _near) / (_far - _near), 1,
  94.             0, 0, -(2 * _near) / (_far - _near), 0);
  95.  
  96.         applicationWindowMatrix.mult_point_matrix(projPerspectiva, pJanela); // normalizando o ponto para mapear para janela da aplicação
  97.  
  98.         float aspect_ratio = (float)imgWidth / (float)imgHeight;
  99.         top = tan((fov / 2) * (M_PI / 180.0));
  100.         right = top * aspect_ratio;
  101.         left = -right;
  102.         bottom = -top;
  103.  
  104.         pRaster = vec2(
  105.             (1 + pJanela.e[0]) / 2 * imgWidth,
  106.             (1 - pJanela.e[1]) / 2 * imgHeight);
  107.  
  108.         if (pJanela.x() >= left && pJanela.x() <= right && pJanela.y() >= bottom && pJanela.y() <= top)
  109.         {
  110.             return true; // o ponto pode ser visto
  111.         }
  112.         return false; // o ponto não pode ser visto
  113.     }
  114.  
  115.     void DrawLine(SDL_Renderer *renderer, vec2 &p0, vec2 &p1)
  116.     {
  117.         vec2 director = p1 - p0;
  118.         vec2 start = p0;
  119.         int iterations = (int)director.length();
  120.         director.make_unit_vector();
  121.  
  122.         if (ClipLine(p0, p1))
  123.         {
  124.             for (int i = 0; i < iterations; i++)
  125.             {
  126.                 SDL_RenderDrawPoint(renderer, start.e[0], start.e[1]);
  127.                 start += director;
  128.             }
  129.         }
  130.     }
  131.  
  132.     int GetOutCode(vec2 &p0)
  133.     {
  134.         int outcode = 0;
  135.  
  136.         if (p0.e[1] > HEIGHT)
  137.         {
  138.             outcode |= TOP;
  139.         }
  140.         else if (p0.e[1] < 0)
  141.         {
  142.             outcode |= BOTTOM;
  143.         }
  144.         if (p0.e[0] > WIDTH)
  145.         {
  146.             outcode |= RIGHT;
  147.         }
  148.         else if (p0.e[0] < 0)
  149.         {
  150.             outcode |= LEFT;
  151.         }
  152.  
  153.         return outcode;
  154.     }
  155.  
  156.     bool intersecao(vec3 N, vec3 RayDirection)
  157.     {
  158.         double EPSILON = 0.00001;
  159.         double i = dot(N, RayDirection);
  160.  
  161.         if (i >= EPSILON)
  162.             return true; // houve intersecao
  163.         else
  164.             return false; // nao houve intersecao
  165.     }
  166.  
  167.     bool ClipLine(vec2 &p0, vec2 &p1)
  168.     {
  169.  
  170.         int outp0 = GetOutCode(p0);
  171.         int outp1 = GetOutCode(p1);
  172.         int slope = 0;
  173.         int tmp_x, tmp_y = 0;
  174.  
  175.         bool accept = false;
  176.         int outcodeOutside = 0;
  177.  
  178.         while (true)
  179.         {
  180.             if (outp0 | outp1 == 0)
  181.             {
  182.                 accept = true;
  183.                 break;
  184.             }
  185.             else if (outp0 & outp1)
  186.             {
  187.                 break;
  188.             }
  189.             else
  190.             {
  191.                 outcodeOutside = outp1 != 0 ? outp1 : outp0;
  192.  
  193.                 if (outcodeOutside & TOP)
  194.                 {
  195.                     tmp_x = p0.e[0] + (p1.e[0] - p0.e[0]) * (HEIGHT - p0.e[1]) / (p1.e[1] - p0.e[1]);
  196.                     tmp_y = HEIGHT;
  197.                 }
  198.                 else if (outcodeOutside & BOTTOM)
  199.                 {
  200.                     tmp_x = p0.e[0] + (p1.e[0] - p0.e[0]) * (0 - p0.e[1]) / (p1.e[1] - p0.e[1]);
  201.                     tmp_y = 0;
  202.                 }
  203.                 if (outcodeOutside & RIGHT)
  204.                 {
  205.                     tmp_y = p0.e[1] + (p1.e[1] - p0.e[1]) * (WIDTH - p0.e[0]) / (p1.e[0] - p0.e[0]);
  206.                     tmp_x = WIDTH;
  207.                 }
  208.                 else if (outcodeOutside & LEFT)
  209.                 {
  210.                     tmp_y = p0.e[1] + (p1.e[1] - p0.e[1]) * (0 - p0.e[0]) / (p1.e[0] - p0.e[0]);
  211.                     tmp_x = 0;
  212.                 }
  213.  
  214.                 if (outcodeOutside == outp0)
  215.                 {
  216.                     p0.e[0] = tmp_x;
  217.                     p0.e[1] = tmp_y;
  218.                     outp0 = GetOutCode(p0);
  219.                 }
  220.                 else
  221.                 {
  222.                     p1.e[0] = tmp_x;
  223.                     p1.e[1] = tmp_y;
  224.                     outp1 = GetOutCode(p1);
  225.                 }
  226.             }
  227.         }
  228.         return accept;
  229.     }
  230.  
  231.     vec3 phong(vec3 normal, vec3 Kd, vec3 Ks, float n, Obj obj, vec2 textura)
  232.     {
  233.         /* ALTERANDO ESSE VALOR dir CONSEGUI ALGUMAS COISAS DIFERENTES,
  234.            A LUZ FINALMENTE COMEÇOU A APARECER MAS AINDA TÁ BUGADO */
  235.         vec3 dir(-2.0f, 4.0f, -1.0f);
  236.         vec3 componente_ambiente(40, 40, 40);
  237.         float L = -dot(unit_vector(normal), dir);
  238.         float cos = std::max(0.0f, L);
  239.         vec3 componente_difusa = cos * Kd;
  240.         vec3 R = dir - 2 * (dot(normal, dir)) * dir;
  241.         vec3 componente_especular = Ks * (pow(std::max(dot(axisZ, R), 0.0f), n));
  242.         float aux = 1.0f - textura.y();
  243.         int x = obj.texture_width * textura.x();
  244.         int y = obj.texture_height * aux;
  245.         vec3 cor = obj.texture_buffer[y * obj.texture_width + x];
  246.  
  247.         return componente_difusa + componente_ambiente + componente_especular;
  248.     }
  249.  
  250.     float edge(const vec2 &v0, const vec2 &v1, const vec2 &p)
  251.     {
  252.         return ((p.e[0] - v0.e[0]) * (v1.e[1] - v0.e[1]) - (v1.e[0] - v0.e[0]) * (p.e[1] - v0.e[1]));
  253.     }
  254.  
  255.     int value_at(int x, int y)
  256.     {
  257.         return y * WIDTH + x;
  258.     }
  259.  
  260.     void fill_triangle(SDL_Renderer *renderer, const vec2 &v0, const vec2 &v1, const vec2 &v2, vec3 &z, Triangle tr, Obj objeto)
  261.     {
  262.         vec2 min, max, temp;
  263.         int min_Y, min_X, max_Y, max_X;
  264.         float wa, wb, wc, area;
  265.  
  266.         max_X = (v0.e[0] > v1.e[0]) ? ((v0.e[0] > v2.e[0]) ? v0.e[0] : v2.e[0]) : ((v1.e[0] > v2.e[0]) ? v1.e[0] : v2.e[0]);
  267.         max_Y = (v0.e[1] > v1.e[1]) ? ((v0.e[1] > v2.e[1]) ? v0.e[1] : v2.e[1]) : ((v1.e[1] > v2.e[1]) ? v1.e[1] : v2.e[1]);
  268.         min_X = (v0.e[0] < v1.e[0]) ? ((v0.e[0] < v2.e[0]) ? v0.e[0] : v2.e[0]) : ((v1.e[0] < v2.e[0]) ? v1.e[0] : v2.e[0]);
  269.         min_Y = (v0.e[1] < v1.e[1]) ? ((v0.e[1] < v2.e[1]) ? v0.e[1] : v2.e[1]) : ((v1.e[1] < v2.e[1]) ? v1.e[1] : v2.e[1]);
  270.  
  271.         area = edge(v0, v1, v2);
  272.         for (int o = min_Y; o <= max_Y; o++)
  273.         {
  274.             for (int i = min_X; i <= max_X; i++)
  275.             {
  276.                 temp = vec2(i, o);
  277.  
  278.                 wa = edge(v0, v1, temp);
  279.                 wb = edge(v1, v2, temp);
  280.                 wc = edge(v2, v0, temp);
  281.  
  282.                 vec3 Kd(30, 30, 30);
  283.                 vec3 Ks(50, 50, 50);
  284.                 float n = 4;
  285.  
  286.                 if (wa >= 0 && wb >= 0 && wc >= 0)
  287.                 {
  288.                     wa /= area;
  289.                     wb /= area;
  290.                     wc /= area;
  291.  
  292.                     float actual_z = (wb * (1.0 / z[0]) + wc * (1.0 / z[1]) + wa * (1.0 / z[2]));
  293.                     actual_z = 1.0 / actual_z;
  294.  
  295.                       if(zBuffer[value_at(i,o)] == LONG_MAX || actual_z < zBuffer[value_at(i,o)]) {
  296.                         zBuffer[value_at(i, o)] = actual_z;
  297.                         vec3 normal = wb * tr.vertex[0].nor + wc * tr.vertex[1].nor + wa * tr.vertex[2].nor;
  298.                         vec2 textura = wb * tr.vertex[0].text + wc * tr.vertex[1].text + wa * tr.vertex[2].text;
  299.                         vec3 color = phong(normal, Kd, Ks, n, objeto, textura);
  300.                         frameBuffer[value_at(i,o)] = color;
  301.                       }
  302.                 }
  303.             }
  304.         }
  305.     }
  306.  
  307.     bool overlaps(float* zBuffer)
  308.  
  309.     // desenha na tela os pixels com suas respectivas cores
  310.     void drawFrame(SDL_Renderer *renderer) {
  311.       SDL_SetRenderDrawColor(renderer,0,0,0,255);
  312.       SDL_RenderClear(renderer);
  313.       for(int i = 0; i < WIDTH; i++) {
  314.         for(int o = 0; o < HEIGHT; o++) {
  315.           SDL_SetRenderDrawColor(renderer, std::min(frameBuffer[value_at(i,o)].r(), 255.0f), std::min(frameBuffer[value_at(i,o)].g(), 255.0f), std::min(frameBuffer[value_at(i,o)].b(), 255.0f), 255);
  316.           SDL_RenderDrawPoint(renderer, i, o);
  317.         }
  318.       }
  319.  
  320.     }
  321.  
  322.     bool insideScreen(const vec2 &v0)
  323.     {
  324.         return ((v0.e[0] >= 0) && (v0.e[0] <= WIDTH) && (v0.e[1] >= 0) && (v0.e[1] <= HEIGHT));
  325.     }
  326.  
  327.     void render_scene(std::vector<Obj> objs, SDL_Renderer *renderer)
  328.     {
  329.         vec3 light(0.0f, 0.0f, 0.0f);
  330.         light.make_unit_vector();
  331.         std::fill(std::begin(zBuffer), std::begin(zBuffer) + WIDTH*HEIGHT, LONG_MAX);
  332.         std::fill(std::begin(frameBuffer), std::begin(frameBuffer) + WIDTH*HEIGHT, 0);
  333.         for (auto obj : objs)
  334.         {
  335.             for (int i = 0; i < obj.mesh.tris.size(); i++)
  336.             {
  337.                 vec2 praster1;
  338.                 vec2 praster2;
  339.                 vec2 praster3;
  340.  
  341.                 vec3 col(255, 255, 255);
  342.                 SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
  343.  
  344.                 bool v1, v2, v3;
  345.                 vec3 z;
  346.  
  347.                 v1 = compute_pixel_coordinates(obj.mesh.tris[i].vertex[0].pos, praster1, z.e[0]);
  348.                 v2 = compute_pixel_coordinates(obj.mesh.tris[i].vertex[1].pos, praster2, z.e[1]);
  349.                 v3 = compute_pixel_coordinates(obj.mesh.tris[i].vertex[2].pos, praster3, z.e[2]);
  350.  
  351.  
  352.                 if (praster1.x() >= 0 & praster1.x() <= WIDTH & praster1.y() >= 0 & praster1.y() <= HEIGHT & praster2.x() >= 0 & praster2.x() <= WIDTH & praster2.y() >= 0 & praster2.y() <= HEIGHT & praster3.x() >= 0 & praster3.x() <= WIDTH & praster3.y() >= 0 & praster3.y() < HEIGHT)
  353.                     fill_triangle(renderer, praster1, praster2, praster3, z, obj.mesh.tris[i], obj);
  354.             }
  355.         }
  356.         drawFrame(renderer);
  357.     }
  358. };
  359.  
  360. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement