JoshButner

Raytracing - main.cpp

Mar 10th, 2022
43
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.56 KB | None | 0 0
  1. #include <cstdlib>
  2. #include <cstdio>
  3. #include <cmath>
  4. #include <fstream>
  5. #include <vector>
  6. #include <iostream>
  7. #include <cassert>
  8. #include <random>
  9. #include <algorithm>
  10. #include <Eigen>
  11.  
  12. using namespace Eigen;
  13.  
  14. // image background color
  15. Vector3f bgcolor(1.0f, 1.0f, 1.0f);
  16.  
  17. // lights in the scene
  18. std::vector<Vector3f> lightPositions = { Vector3f(  0.0, 60, 60)
  19.                                        , Vector3f(-60.0, 60, 60)
  20.                                        , Vector3f( 60.0, 60, 60) };
  21.  
  22. class Sphere
  23. {
  24. public:
  25.     Vector3f center;  // position of the sphere
  26.     float radius;  // sphere radius
  27.     Vector3f surfaceColor; // surface color
  28.  
  29.   Sphere(
  30.         const Vector3f &c,
  31.         const float &r,
  32.         const Vector3f &sc) :
  33.         center(c), radius(r), surfaceColor(sc)
  34.     {
  35.     }
  36.  
  37.     // line vs. sphere intersection (note: this is slightly different from ray vs. sphere intersection!)
  38.     bool intersect(const Vector3f &rayOrigin, const Vector3f &rayDirection, float &t0, float &t1) const
  39.     {
  40.         Vector3f l = center - rayOrigin;
  41.         float tca = l.dot(rayDirection);
  42.         if (tca < 0) return false;
  43.         float d2 = l.dot(l) - tca * tca;
  44.         if (d2 > (radius * radius)) return false;
  45.         float thc = sqrt(radius * radius - d2);
  46.         t0 = tca - thc;
  47.         t1 = tca + thc;
  48.  
  49.         return true;
  50.     }
  51. };
  52.  
  53. // diffuse reflection model
  54. Vector3f diffuse(const Vector3f &L, // direction vector from the point on the surface towards a light source
  55.     const Vector3f &N, // normal at this point on the surface
  56.     const Vector3f &diffuseColor,
  57.     const float kd // diffuse reflection constant
  58.     )
  59. {
  60.     Vector3f resColor = Vector3f::Zero();
  61.   float lightIntensity = 1.0f / (float)lightPositions.size();
  62.  
  63.     resColor = diffuseColor * lightIntensity * kd * std::max(L.dot(N), 0.0f);
  64.  
  65.     return resColor;
  66. }
  67.  
  68. // Phong reflection model
  69. Vector3f phong(const Vector3f &L, // direction vector from the point on the surface towards a light source
  70.                const Vector3f &N, // normal at this point on the surface
  71.                const Vector3f &V, // direction pointing towards the viewer
  72.                const Vector3f &diffuseColor,
  73.                const Vector3f &specularColor,
  74.                const float kd, // diffuse reflection constant
  75.                const float ks, // specular reflection constant
  76.                const float alpha) // shininess constant
  77. {
  78.     Vector3f resColor = Vector3f::Zero();
  79.   Vector3f specularComponent = Vector3f::Zero();
  80.   float lightIntensity = 1.0f / (float)lightPositions.size();
  81.  
  82.   Vector3f reflectionVector = 2 * N * N.dot(L) - L;
  83.   specularComponent = specularColor * lightIntensity * ks * std::pow(std::max(reflectionVector.dot(V), 0.0f), alpha);
  84.     resColor = diffuse(L, N, diffuseColor, kd) + specularComponent;
  85.  
  86.     return resColor;
  87. }
  88.  
  89. Vector3f trace(
  90.     const Vector3f &rayOrigin,
  91.     const Vector3f &rayDirection,
  92.     const std::vector<Sphere> &spheres)
  93. {
  94.     Vector3f pixelColor = Vector3f::Zero();
  95.  
  96.   Vector3f A, R;
  97.   float closestDist = INFINITY;
  98.   float t0, t1;
  99.  
  100.   pixelColor = bgcolor;
  101.   for(int sphereIndex = 0; sphereIndex < spheres.size(); sphereIndex++){
  102.     if(spheres[sphereIndex].intersect(rayOrigin, rayDirection, t0, t1))
  103.     {
  104.       // We check if we're closer than the last sphere painted here
  105.       // We check t0 and t1 since we have no knowledge of which is closer
  106.       float visibleDist = t0 < t1 ? t0 : t1;
  107.       if(visibleDist < closestDist){
  108.         closestDist = visibleDist;
  109.         Vector3f closestPoint = rayOrigin + rayDirection*visibleDist;
  110.  
  111.         // Calculate lighting
  112.         pixelColor = Vector3f(0.0f, 0.0f, 0.0f);
  113.         // Iterate across all lights
  114.         for(int lightIndex = 0; lightIndex < lightPositions.size(); lightIndex++){
  115.           // Calculate the direction of the light ray
  116.           Vector3f lightRayDir = lightPositions[lightIndex] - closestPoint;
  117.           lightRayDir.normalize();
  118.  
  119.  
  120.           bool didCollide = false;
  121.           // Iterate over all spheres and check if the ray from the visible point to the line intercepts with that sphere
  122.           for(int otherSphereIndex = 0; otherSphereIndex < spheres.size(); otherSphereIndex++){
  123.             if(spheres[otherSphereIndex].intersect(closestPoint, lightRayDir, t0, t1)){
  124.               didCollide = true;
  125.             }
  126.           }
  127.           // If there is no interception, add the color value for this light
  128.           if(!didCollide){
  129.             Vector3f sphereNormal = closestPoint - spheres[sphereIndex].center;
  130.             sphereNormal.normalize();
  131.             // pixelColor += diffuse(lightRayDir, sphereNormal, spheres[sphereIndex].surfaceColor, 1.0f);
  132.             pixelColor += phong(lightRayDir, sphereNormal, -rayDirection, spheres[sphereIndex].surfaceColor, Vector3f::Ones(), 1.0f, 3.0f, 100.0f);
  133.           }
  134.         }
  135.  
  136.       }
  137.     }
  138.   }
  139.  
  140.     return pixelColor;
  141. }
  142.  
  143. void render(const std::vector<Sphere> &spheres)
  144. {
  145.   unsigned width = 640;
  146.   unsigned height = 480;
  147.   Vector3f *image = new Vector3f[width * height];
  148.   Vector3f *pixel = image;
  149.   float invWidth  = 1 / float(width);
  150.   float invHeight = 1 / float(height);
  151.   float fov = 30;
  152.   float aspectratio = width / float(height);
  153.     float angle = tan(M_PI * 0.5f * fov / 180.f);
  154.  
  155.     // Trace rays
  156.     for (unsigned y = 0; y < height; ++y)
  157.     {
  158.         for (unsigned x = 0; x < width; ++x)
  159.         {
  160.             float rayX = (2 * ((x + 0.5f) * invWidth) - 1) * angle * aspectratio;
  161.             float rayY = (1 - 2 * ((y + 0.5f) * invHeight)) * angle;
  162.             Vector3f rayDirection(rayX, rayY, -1);
  163.             rayDirection.normalize();
  164.             *(pixel++) = trace(Vector3f::Zero(), rayDirection, spheres);
  165.         }
  166.     }
  167.  
  168.     // Save result to a PPM image
  169.     std::ofstream ofs("./render.ppm", std::ios::out | std::ios::binary);
  170.     ofs << "P6\n" << width << " " << height << "\n255\n";
  171.     for (unsigned i = 0; i < width * height; ++i)
  172.     {
  173.         const float x = image[i](0);
  174.         const float y = image[i](1);
  175.         const float z = image[i](2);
  176.  
  177.         ofs << (unsigned char)(std::min(float(1), x) * 255)
  178.               << (unsigned char)(std::min(float(1), y) * 255)
  179.               << (unsigned char)(std::min(float(1), z) * 255);
  180.     }
  181.  
  182.     ofs.close();
  183.     delete[] image;
  184. }
  185.  
  186. int main(int argc, char **argv)
  187. {
  188.     std::vector<Sphere> spheres;
  189.     // position, radius, surface color
  190.     spheres.push_back(Sphere(Vector3f(0.0, -10004, -20), 10000, Vector3f(0.50, 0.50, 0.50)));
  191.     spheres.push_back(Sphere(Vector3f(0.0, 0, -20), 4, Vector3f(1.00, 0.32, 0.36)));
  192.     spheres.push_back(Sphere(Vector3f(5.0, -1, -15), 2, Vector3f(0.90, 0.76, 0.46)));
  193.     spheres.push_back(Sphere(Vector3f(5.0, 0, -25), 3, Vector3f(0.65, 0.77, 0.97)));
  194.     spheres.push_back(Sphere(Vector3f(-5.5, 0, -13), 3, Vector3f(0.90, 0.90, 0.90)));
  195.  
  196.     render(spheres);
  197.  
  198.     return 0;
  199. }
  200.  
Advertisement
Add Comment
Please, Sign In to add comment