Advertisement
Guest User

main.cpp

a guest
Mar 30th, 2022
309
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.92 KB | None | 0 0
  1. #include <iostream>
  2. #include "EngineMath.h"
  3. #include "Defines.h"
  4. #include <vector>
  5.  
  6. struct Sphere {
  7.     TVECTOR color = { 0.0f, 0.0f, 0.0f, 0.0f };
  8.     TVECTOR center = { 0.0f, 0.0f, 0.0f, 1.0f };
  9.     float radius = 0.0f;
  10.  
  11.     // material
  12.     float specular_exponent = 0.0f;
  13.     float reflective = 0.0f;
  14. };
  15.  
  16. enum class ELightType : uint8_t {
  17.     Point,
  18.     Spot,
  19.     Directional,
  20.     Ambient
  21. };
  22.  
  23. struct Light {
  24.     TVECTOR postion = { 0.0f, 0.0f, 0.0f, 1.0f };
  25.     TVECTOR direction = { 1.0f, 1.0f, 1.0f, 0.0f };
  26.     TVECTOR color = { 1.0f, 1.0f, 1.0f, 1.0f };
  27.     float intensity = 1.0f;
  28.     ELightType type = ELightType::Point;
  29. };
  30.  
  31. struct Scene {
  32.     std::vector<Sphere> spheres;
  33.     std::vector<Light> lights;
  34.  
  35. } scene;
  36.  
  37. TVECTOR canvas_to_viewport(int x, int y)
  38. {
  39.     TVECTOR v;
  40.     v.x = x * 1.77777f / static_cast<float>(canvas_width);
  41.     v.y = y * viewport_height / static_cast<float>(canvas_height);
  42.     v.z = static_cast<float>(projection_plane_z);
  43.     v.w = 0.0f;
  44.  
  45.     return v;
  46. }
  47.  
  48. // Determines if a ray from the origin location intersects the given sphere using the quadratic formula
  49. bool ray_intersect_sphere(const TVECTOR origin, const TVECTOR ray_direction, const Sphere& sphere, float& t1, float& t2)
  50. {
  51.     float r = sphere.radius;
  52.     TVECTOR CO_v = Vector_Sub(origin, sphere.center);
  53.  
  54.     // Quadratic formula
  55.     float a = Vector_Dot(ray_direction, ray_direction);
  56.     float b = 2.0f * Vector_Dot(CO_v, ray_direction);
  57.     float c = Vector_Dot(CO_v, CO_v) - r * r;
  58.  
  59.     float discriminant = b * b - 4 * a * c;
  60.     if (discriminant < 0.0f) // no intersection/no solution for t
  61.     {
  62.         t1 = t2 = INFINITY;
  63.         return false;
  64.     }
  65.  
  66.     t1 = (-b + sqrt(discriminant)) / (2.0f * a);
  67.     t2 = (-b - sqrt(discriminant)) / (2.0f * a);
  68.     return true;
  69. }
  70.  
  71. // returns the closest intersection on the given ray and stores the closest sphere intersected by the ray
  72. float closest_intersection(const TVECTOR ray_origin, const TVECTOR ray_direction, const float near_plane, const float far_plane, Sphere& closest_sphere)
  73. {
  74.     float t1, t2, closest_t = far_plane;
  75.  
  76.     for (const Sphere& s : scene.spheres)
  77.     {
  78.         if (ray_intersect_sphere(ray_origin, ray_direction, s, t1, t2))
  79.         {
  80.             if (near_plane < t1 && t1 < far_plane && t1 < closest_t)
  81.             {
  82.                 closest_t = t1;
  83.                 closest_sphere = s;
  84.             }
  85.             if (near_plane < t2 && t2 < far_plane && t2 < closest_t)
  86.             {
  87.                 closest_t = t2;
  88.                 closest_sphere = s;
  89.             }
  90.         }
  91.     }
  92.  
  93.     return closest_t;
  94. }
  95.  
  96. float compute_lighting(TVECTOR point, TVECTOR normal, TVECTOR eye, float specular)
  97. {
  98.     float illumination = 0.0f;
  99.     for (const Light& light : scene.lights)
  100.     {
  101.         if (light.type == ELightType::Ambient)
  102.         {
  103.             illumination += light.intensity;
  104.         }
  105.         else
  106.         {
  107.             TVECTOR light_v = { 0.0f, 0.0f, 0.0f, 0.0f };
  108.             float t_max = 0.0f;
  109.             if (light.type == ELightType::Point)
  110.             {
  111.                 light_v = Vector_Sub(light.postion, point);
  112.                 t_max = 1.0f;
  113.             }
  114.             else // if directional light
  115.             {
  116.                 light_v = light.direction;
  117.                 t_max = INFINITY;
  118.             }
  119.  
  120.             //Shadow check
  121.             Sphere shadow_sphere;
  122.             float shadow_t = closest_intersection(point, light_v, 0.001f, t_max, shadow_sphere);
  123.             if (shadow_t != t_max) // if there was an intersection/there is something blocking the light
  124.                 continue;
  125.  
  126.             // Diffuse Reflection
  127.             float n_dot_l = Vector_Dot(normal, light_v);
  128.             if (n_dot_l > 0.0f)
  129.                 illumination += light.intensity * n_dot_l / (Vector_Length(normal) * Vector_Length(light_v));
  130.  
  131.             //Specular Reflection
  132.             if (specular != -1.0f)
  133.             {
  134.                 TVECTOR reflection_v = Vector_Reflect(light_v, normal);
  135.  
  136.                 float r_dot_v = Vector_Dot(reflection_v, eye);
  137.                 if (r_dot_v > 0.0f)
  138.                     illumination += light.intensity * powf(r_dot_v / (Vector_Length(reflection_v) * Vector_Length(eye)), specular);
  139.             }
  140.  
  141.         }
  142.     }
  143.  
  144.     return illumination;
  145. }
  146.  
  147. // Computes the intersection of the ray with every sphere
  148. // and returns the color of the sphere at the nearest intersection inside the requested range of t
  149. TVECTOR trace_ray(const TVECTOR ray_origin, const TVECTOR ray_direction, const float near_plane, const float far_plane, const int recursion_depth = 0)
  150. {
  151.     Sphere closest_sphere;
  152.     float closest_t = closest_intersection(ray_origin, ray_direction, near_plane, far_plane, closest_sphere);
  153.  
  154.     if (closest_t == far_plane) // if there was no sphere intersection
  155.         return BACKGROUND_COLOR;
  156.  
  157.     TVECTOR point = Vector_Add(ray_origin, Vector_Scalar_Multiply(ray_direction, closest_t));// Compute Intersection (O + t*D)
  158.     TVECTOR normal = Vector_Normalize(Vector_Sub(point, closest_sphere.center)); // Compute Sphere Normal
  159.     TVECTOR eye = Vector_Negate(ray_direction);
  160.  
  161.     float lighting = saturate(compute_lighting(point, normal, eye, closest_sphere.specular_exponent));
  162.     TVECTOR local_color = Vector_Scalar_Multiply(closest_sphere.color, lighting);
  163.  
  164.     // If we hit the recursion limit or the object is not reflective, we’ re done
  165.     float reflective = closest_sphere.reflective;
  166.     if (recursion_depth <= 0 || reflective <= 0.0f)
  167.         return /*Vector_Saturate*/(local_color);
  168.  
  169.     // Compute the reflected color
  170.     TVECTOR reflection_v = Vector_Reflect(eye, normal);
  171.     TVECTOR reflected_color = trace_ray(point, reflection_v, 0.001f, INFINITY, recursion_depth - 1);
  172.  
  173.     TVECTOR out_color = Vector_Add(
  174.         Vector_Scalar_Multiply(local_color, (1.0f - reflective)),
  175.         Vector_Scalar_Multiply(reflected_color, reflective));
  176.  
  177.     return Vector_Saturate(out_color);
  178. }
  179.  
  180. int main()
  181. {
  182.     TVECTOR cam_pos = { 0.0f, 0.0f, 0.0f, 1.0f };
  183.     const int32_t canvas_size = canvas_width * canvas_height;
  184.     std::vector<Pixel> pixels(canvas_size + 1);
  185.  
  186.     // define the scene
  187.     {
  188.         Sphere s1, s2, s3, s4;
  189.         // red sphere
  190.         s1.color = { 1.0f, 0.0f, 0.0f, 1.0f };
  191.         s1.center = { 0.0f, -1.0f, 3.0f, 1.0f };
  192.         s1.radius = 1.0f;
  193.         s1.specular_exponent = 500.0f; // shiny
  194.         s1.reflective = 0.2f;
  195.         // green sphere
  196.         s2.color = { 0.0f, 1.0f, 0.0f, 1.0f };
  197.         s2.center = { -2.0f, 0.0f, 4.0f, 1.0f};
  198.         s2.radius = 1.0f;
  199.         s2.specular_exponent = 10.0f; // not so shiny
  200.         s2.reflective = 0.4f;
  201.         // blue sphere
  202.         s3.color = { 0.0f, 0.0f, 1.0f, 1.0f };
  203.         s3.center = { 2.0f, 0.0f, 4.0f, 1.0f};
  204.         s3.radius = 1.0f;
  205.         s3.specular_exponent = 500.0f; // shiny
  206.         s3.reflective = 0.3f;
  207.         // yellow sphere
  208.         s4.color = { 1.0f, 1.0f, 0.0f, 1.0f };
  209.         s4.center = { 0.0f, -5001.0f, 0.0f, 1.0f };
  210.         s4.radius = 5000.0f;
  211.         s4.specular_exponent = 1000.0f; // very shiny
  212.         s4.reflective = 0.5f;
  213.  
  214.         scene.spheres.push_back(s1);
  215.         scene.spheres.push_back(s2);
  216.         scene.spheres.push_back(s3);
  217.         scene.spheres.push_back(s4);
  218.  
  219.         Light amb_l, point_l, dir_l;
  220.         // Ambient light
  221.         amb_l.type = ELightType::Ambient;
  222.         amb_l.intensity = 0.2f;
  223.         // Point light
  224.         point_l.type = ELightType::Point;
  225.         point_l.intensity = 0.6f;
  226.         point_l.postion = { 1.0f, 0.0f, 1.0f, 1.0f };
  227.         // Directional light
  228.         dir_l.type = ELightType::Directional;
  229.         dir_l.intensity = 0.2f;
  230.         dir_l.direction = { 1.0f, 4.0f, 4.0f, 0.0f };
  231.  
  232.         scene.lights.push_back(amb_l);
  233.         scene.lights.push_back(point_l);
  234.         scene.lights.push_back(dir_l);
  235.     }
  236.    
  237.     int width = canvas_width >> 1;
  238.     int height = canvas_height >> 1;
  239.    
  240.     // for every pixel on the canvas
  241.     for (int y = -height; y < height; ++y)
  242.     {
  243.         for (int x = -width; x < width; ++x)
  244.         {
  245.             // convert 2d coordinate to 3d space
  246.             TVECTOR ray = canvas_to_viewport(x, y);
  247.             TVECTOR color = trace_ray(cam_pos, ray, 1.0f, INFINITY, 3);
  248.  
  249.             int p_index = (y + height) * canvas_width + (x + width);
  250.             pixels[p_index].red =  static_cast<uint8_t>(color.x * 255);
  251.             pixels[p_index].green =  static_cast<uint8_t>(color.y * 255);
  252.             pixels[p_index].blue =  static_cast<uint8_t>(color.z * 255);
  253.         }
  254.     }
  255.  
  256.     // PutPixel
  257.     std::ofstream file("RayTrace.bmp", std::ios::trunc | std::ios::out);
  258.  
  259.     assert(file.is_open());
  260.  
  261.     if (file.is_open())
  262.     {
  263.         bmpHeader.write_to_file(file);
  264.         bmpInfoHeader.write_to_file(file);
  265.  
  266.         for (size_t i = 0; i < canvas_size; ++i)
  267.         {
  268.             pixels[i].write_to_file(file);
  269.         }
  270.     }
  271.     file.close();
  272. }
  273.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement