RohamCsiga

Vik Wiki Grafika - Kétirányú sugárkövetés - spekuláris hatás

Jan 30th, 2014
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 26.04 KB | None | 0 0
  1. #include <math.h>
  2. #include <stdlib.h>
  3.  
  4. #if defined(__APPLE__)
  5.   #include <OpenGL/gl.h>
  6.   #include <OpenGL/glu.h>
  7.   #include <GLUT/glut.h>
  8. #else
  9.   #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
  10.     #include <windows.h>
  11.   #endif
  12.   #include <GL/gl.h>
  13.   #include <GL/glu.h>
  14.   #include <GL/glut.h>
  15. #endif
  16.  
  17. #ifndef M_PI
  18.   #define M_PI 3.14159265359
  19. #endif
  20.  
  21. template <typename T>
  22. T max(T a, T b) {
  23.   return a > b ? a : b;
  24. }
  25.  
  26. template <typename T>
  27. T min(T a, T b) {
  28.   return a < b ? a : b;
  29. }
  30.  
  31. template <typename T>
  32. T clamp(T x, T min_v, T max_v) {
  33.   return min(max(x, min_v), max_v);
  34. }
  35.  
  36. struct Vector {
  37.   union { float x, r; }; // x és r néven is lehessen hivatkozni erre a tagra.
  38.   union { float y, g; };
  39.   union { float z, b; };
  40.  
  41.   Vector(float v = 0) : x(v), y(v), z(v) { }
  42.   Vector(float x, float y, float z) : x(x), y(y), z(z) { }
  43.   Vector operator+(const Vector& v) const { return Vector(x + v.x, y + v.y, z + v.z); }
  44.   Vector operator-(const Vector& v) const { return Vector(x - v.x, y - v.y, z - v.z); }
  45.   Vector operator*(const Vector& v) const { return Vector(x * v.x, y * v.y, z * v.z); }
  46.   Vector operator/(const Vector& v) const { return Vector(x / v.x, y / v.y, z / v.z); }
  47.   Vector& operator+=(const Vector& v) { x += v.x, y += v.y, z += v.z; return *this; }
  48.   Vector& operator-=(const Vector& v) { x -= v.x, y -= v.y, z -= v.z; return *this; }
  49.   Vector& operator*=(const Vector& v) { x *= v.x, y *= v.y, z *= v.z; return *this; }
  50.   Vector& operator/=(const Vector& v) { x /= v.x, y /= v.y, z /= v.z; return *this; }
  51.   Vector operator-() const { return Vector(-x, -y, -z); }
  52.   float dot(const Vector& v) const { return x*v.x + y*v.y + z*v.z; }
  53.   Vector cross(const Vector& v) const { return Vector(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x); }
  54.   float length() const { return sqrt(x*x + y*y + z*z); }
  55.   Vector normalize() const { float l = length(); if(l > 1e-3) { return (*this/l); } else { return Vector(); } }
  56.   bool isNull() const { return length() < 1e-3; }
  57.   Vector toneMap() const {
  58.     // Filmic tonemap approximation by Jim Hejl
  59.     Vector v = Vector(max(r - 0.004f, 0.0f), max(g - 0.004f, 0.0f), max(b - 0.004f, 0.0f));
  60.     v = (v*(v*6.2f+0.5f))/(v*(v*6.2f+1.7f)+0.06f);
  61.     return Vector(pow(v.x, 2.2f), pow(v.y, 2.2f), pow(v.z, 2.2f));
  62.   }
  63.   static Vector Random() {
  64.     return Vector(
  65.       -1.0f + 2.0f*rand()/RAND_MAX,
  66.       -1.0f + 2.0f*rand()/RAND_MAX,
  67.       -1.0f + 2.0f*rand()/RAND_MAX
  68.     );
  69.   }
  70. };
  71.  
  72. // Azoknak, akik a shader kódokban használt szintakszishoz hozzá vannak szokva (mint pl. én)
  73. inline float dot(const Vector& lhs, const Vector& rhs) {
  74.   return lhs.dot(rhs);
  75. }
  76.  
  77. inline Vector cross(const Vector& lhs, const Vector& rhs) {
  78.   return lhs.cross(rhs);
  79. }
  80.  
  81. inline Vector operator+(float f, const Vector& v) {
  82.   return v+f;
  83. }
  84. inline Vector operator-(float f, const Vector& v) {
  85.   return Vector(f)-v;
  86. }
  87. inline Vector operator*(float f, const Vector& v) {
  88.   return v*f;
  89. }
  90. inline Vector operator/(float f, const Vector& v) {
  91.   return Vector(f)/v;
  92. }
  93.  
  94. typedef Vector Color;
  95.  
  96. struct Screen {
  97.   static const int width = 600;
  98.   static const int height = 600;
  99.   static Color image[width * height];
  100.   static void Draw() {
  101.     glDrawPixels(width, height, GL_RGB, GL_FLOAT, image);
  102.   }
  103.   static Color& Pixel(size_t x, size_t y) {
  104.     return image[y*width + x];
  105.   }
  106. };
  107. Color Screen::image[width * height]; // A statikus adattagat out-of-line példányosítani kell (kivéve az inteket és enumokat).
  108.  
  109. struct Ray {
  110.   Vector origin, direction;
  111.   bool in_air;
  112.   Ray(Vector origin = Vector(), Vector direction = Vector(), bool in_air = true)
  113.     : origin(origin), direction(direction.normalize()), in_air(in_air) { }
  114. };
  115.  
  116. struct Photon : public Ray {
  117.   Color color;
  118.   Photon(const Color& color, Vector origin = Vector(), Vector direction = Vector(), bool in_air = true)
  119.     : Ray(origin, direction, in_air), color(color) { }
  120. };
  121.  
  122. struct Intersection {
  123.   Ray ray;
  124.   Vector pos, normal;
  125.   bool is_valid;
  126.   Intersection(Ray ray = Ray(), Vector pos = Vector(), Vector normal = Vector(), bool is_valid = false)
  127.     : ray(ray), pos(pos), normal(normal), is_valid(is_valid) { }
  128. };
  129.  
  130. struct Light {
  131.   enum LightType {Ambient, Directional, Point, Spot} type;
  132.   Vector pos, dir;
  133.   Color color;
  134.   float spot_cutoff;
  135. };
  136.  
  137. struct Material {
  138.   virtual ~Material() { }
  139.   virtual Color getColor(Intersection, const Light[], size_t, int) = 0;
  140.   virtual void interact(Photon photon, Intersection inter, int recursion_level) = 0;
  141. };
  142.  
  143. struct Object {
  144.   Material *mat;
  145.   Object(Material* m) : mat(m) { }
  146.   virtual ~Object() { }
  147.   virtual Intersection intersectRay(Ray) = 0;
  148. };
  149.  
  150. struct Scene {
  151.   static const size_t max_obj_num = 100;
  152.   size_t obj_num;
  153.   Object* objs[max_obj_num];
  154.  
  155.   void AddObject(Object *o) {
  156.     objs[obj_num++] = o;
  157.   }
  158.  
  159.   ~Scene() {
  160.     for(int i = 0; i != obj_num; ++i) {
  161.       delete objs[i];
  162.     }
  163.   }
  164.  
  165.   static const size_t max_lgt_num = 10;
  166.   size_t lgt_num;
  167.   Light lgts[max_obj_num];
  168.  
  169.   void AddLight(const Light& l) {
  170.     lgts[lgt_num++] = l;
  171.   }
  172.  
  173.   static const Vector env_color;
  174.  
  175.   Scene() : obj_num(0) { }
  176.  
  177.   Intersection getClosestIntersection(Ray r, int* index = NULL) const {
  178.     Intersection closest_intersection;
  179.     float closest_intersection_dist;
  180.     int closest_index = -1;
  181.  
  182.     for(int i = 0; i < obj_num; ++i) {
  183.       Intersection inter = objs[i]->intersectRay(r);
  184.       if(!inter.is_valid)
  185.         continue;
  186.       float dist = (inter.pos - r.origin).length();
  187.       if(closest_index == -1 || dist < closest_intersection_dist) {
  188.         closest_intersection = inter;
  189.         closest_intersection_dist = dist;
  190.         closest_index = i;
  191.       }
  192.     }
  193.  
  194.     if(index) {
  195.       *index = closest_index;
  196.     }
  197.     return closest_intersection;
  198.   }
  199.  
  200.   Color shootRay(Ray r, int recursion_level = 0) const {
  201.     if(recursion_level >= 8) {
  202.       return env_color;
  203.     }
  204.  
  205.     int index;
  206.     Intersection inter = getClosestIntersection(r, &index);
  207.  
  208.     if(index != -1) {
  209.       return objs[index]->mat->getColor(inter, lgts, lgt_num, recursion_level).toneMap();
  210.     } else {
  211.       return env_color;
  212.     }
  213.   }
  214.  
  215.   void shootPhoton(Photon p, int recursion_level = 0) const {
  216.     if(recursion_level >= 8) {
  217.       return;
  218.     }
  219.  
  220.     int index;
  221.     Intersection inter = getClosestIntersection(p, &index);
  222.  
  223.     if(index != -1) {
  224.       return objs[index]->mat->interact(p, inter, recursion_level);
  225.     }
  226.   }
  227.  
  228.   void shootPhotons(size_t num_per_light) const {
  229.     for(int i = 0; i < lgt_num; ++i) {
  230.       for(int j = 0; j < num_per_light; ++j) {
  231.         if(lgts[i].type == Light::Point) {
  232.           Photon p(lgts[i].color * (100.0f/num_per_light), lgts[i].pos);
  233.           p.direction = Vector::Random().normalize();
  234.  
  235.           shootPhoton(p);
  236.         }
  237.       }
  238.     }
  239.   }
  240. } scene;
  241. const Vector Scene::env_color = Vector(135./255., 206./255., 235./255.);
  242.  
  243. struct Camera {
  244.   Vector pos, plane_pos, right, up;
  245.  
  246.   Camera(float fov, const Vector& eye, const Vector& target, const Vector& plane_up)
  247.       : pos(eye - (target-eye).normalize() / (2*tan((fov*M_PI/180)/2))), plane_pos(eye)
  248.    {
  249.       Vector fwd = (plane_pos - pos).normalize();
  250.       right = cross(fwd, plane_up).normalize();
  251.       up = cross(right, fwd).normalize();
  252.    }
  253.  
  254.   void takePicture() {
  255.     for(int x = 0; x < Screen::height; ++x)
  256.       for(int y = 0; y < Screen::width; ++y)
  257.         capturePixel(x, y);
  258.   }
  259.  
  260.   void capturePixel(float x, float y) {
  261.     Vector pos_on_plane = Vector(
  262.       (x - Screen::width/2) / (Screen::width/2),
  263.       // Itt nem kell megfordítani az y tengelyt. A bal fölső sarok az origó most.
  264.       (y - Screen::height/2) / (Screen::height/2),
  265.       0
  266.     );
  267.  
  268.     Vector plane_intersection = plane_pos + pos_on_plane.x * right + pos_on_plane.y * up;
  269.  
  270.     Ray r = Ray(pos, (plane_intersection - pos).normalize());
  271.     Screen::Pixel(x, y) = scene.shootRay(r);
  272.   }
  273. } camera(60, Vector(-1.2f, 1.5f, -1.5f), Vector(), Vector(0, 1, 0));
  274.  
  275. // Idáig egy általános raytracert definiáltam. Innentől jönnek a konkrétumok.
  276.  
  277. struct DiffuseMaterial : public Material {
  278.   Color diffuse_color;
  279.  
  280.   DiffuseMaterial(const Color& color) : diffuse_color(color) { }
  281.  
  282.   Color getColor(Intersection inter, const Light* lgts, size_t lgt_num, int recursion_level) {
  283.     Color accum_color;
  284.  
  285.     for(int i = 0; i < lgt_num; ++i) {
  286.       const Light& light = lgts[i];
  287.  
  288.       switch(light.type) {
  289.         case Light::Ambient: {
  290.           accum_color += light.color * diffuse_color;
  291.         } break;
  292.         case Light::Directional: {
  293.           // Lőjjünk egy sugarat a fényforrás irányába.
  294.           Ray shadow_checker = Ray(inter.pos + 1e-3*light.dir, light.dir); // Az irányfény iránya nálam a forrás felé futat.
  295.           Intersection shadow_checker_int = scene.getClosestIntersection(shadow_checker);
  296.           if(shadow_checker_int.is_valid) {
  297.             break; // Ha bármivel is ütközik, akkor árnyékban vagyunk
  298.           }
  299.  
  300.           float intensity = max(dot(inter.normal, light.dir.normalize()), 0.0f);
  301.           accum_color += intensity * light.color * diffuse_color;
  302.         } break;
  303.         case Light::Spot: {
  304.           Vector light_to_pos = inter.pos - light.pos;
  305.           if(dot(light_to_pos.normalize(), light.dir) < light.spot_cutoff) {
  306.             break; // Ha nincs megvilágítva, akkor ne csináljuk semmit.
  307.           } // Különben számoljuk pont fényforrással.
  308.         } // NINCS break!
  309.         case Light::Point: {
  310.           // Lőjjünk egy sugarat a fényforrás felől a konkrét pont irányába
  311.           Ray shadow_checker = Ray(light.pos, (inter.pos - light.pos).normalize());
  312.           Intersection shadow_checker_int = scene.getClosestIntersection(shadow_checker);
  313.           if(shadow_checker_int.is_valid &&
  314.             (shadow_checker_int.pos-light.pos).length() + 1e-3 < (inter.pos-light.pos).length()) {
  315.             break; // Ha bármivel is ütközik, ami közelebb van a fényhez, mint mi, akkor árnyékban vagyunk
  316.           }
  317.  
  318.           Vector pos_to_light = light.pos - inter.pos;
  319.           float attenuation = pow(1/pos_to_light.length(), 2);
  320.           float intensity = max(dot(inter.normal, pos_to_light.normalize()), 0.0f);
  321.           accum_color += attenuation * intensity * light.color * diffuse_color;
  322.         } break;
  323.       }
  324.     }
  325.  
  326.     return accum_color;
  327.   }
  328. };
  329.  
  330. inline Vector reflect(Vector I, Vector N) {
  331.   return I - (2.0 * dot(N, I)) * N;
  332. }
  333.  
  334. struct SpecularMaterial : DiffuseMaterial {
  335.   const Color specular_color;
  336.   const float shininess;
  337.  
  338.   SpecularMaterial(const Color& diffuse_color, const Color& specular_color, float shininess)
  339.     : DiffuseMaterial(diffuse_color), specular_color(specular_color), shininess(shininess) { }
  340.  
  341.   Color getColor(Intersection inter, const Light* lgts, size_t lgt_num, int recursion_level) {
  342.     Color accum_color = DiffuseMaterial::getColor(inter, lgts, lgt_num, recursion_level);
  343.  
  344.     for(int i = 0; i < lgt_num; ++i) {
  345.       const Light& light = lgts[i];
  346.  
  347.       switch(light.type) {
  348.         case Light::Directional: {
  349.           // Lőjjünk egy sugarat a fényforrás irányába.
  350.           Ray shadow_checker = Ray(inter.pos + 1e-3*light.dir, light.dir); // Az irányfény iránya nálam a forrás felé futat.
  351.           Intersection shadow_checker_int = scene.getClosestIntersection(shadow_checker);
  352.           if(shadow_checker_int.is_valid) {
  353.             break; // Ha bármivel is ütközik, akkor árnyékban vagyunk
  354.           }
  355.  
  356.           float specular_power =
  357.             pow(
  358.               max(0.0f, dot(
  359.                 reflect(-light.dir.normalize(), inter.normal),
  360.                 (camera.pos-inter.pos).normalize())
  361.               ), shininess
  362.             );
  363.           accum_color += specular_power * light.color * specular_color;
  364.         } break;
  365.         case Light::Spot: {
  366.           Vector light_to_pos = inter.pos - light.pos;
  367.           if(dot(light_to_pos.normalize(), light.dir) < light.spot_cutoff) {
  368.             break;
  369.           }
  370.         }
  371.         case Light::Point: {
  372.           Ray shadow_checker = Ray(light.pos, (inter.pos - light.pos).normalize());
  373.           Intersection shadow_checker_int = scene.getClosestIntersection(shadow_checker);
  374.           if(shadow_checker_int.is_valid &&
  375.             (shadow_checker_int.pos-light.pos).length() + 1e-3 < (inter.pos-light.pos).length()) {
  376.             break; // Ha bármivel is ütközik, ami közelebb van a fényhez, mint mi, akkor árnyékban vagyunk
  377.           }
  378.  
  379.           Vector light_to_pos = inter.pos-light.pos;
  380.           float attenuation = pow(1/light_to_pos.length(), 2);
  381.  
  382.           float specular_power =
  383.             pow(
  384.               max(0.0f, dot(
  385.                 reflect((light_to_pos).normalize(), inter.normal),
  386.                 (camera.pos-inter.pos).normalize())
  387.               ), shininess
  388.             );
  389.           accum_color += specular_power * attenuation * light.color * specular_color;
  390.         } break;
  391.         default:
  392.           break;
  393.       }
  394.     }
  395.  
  396.     return accum_color;
  397.   }
  398. };
  399.  
  400. struct ReflectiveMaterial : public Material {
  401.   const Color F0;
  402.  
  403.   ReflectiveMaterial(Color n, Color k)
  404.     : F0(((n-1)*(n-1) + k*k) /
  405.          ((n+1)*(n+1) + k*k))
  406.   { }
  407.  
  408.   Color F(float cosTheta) {
  409.     return F0 + (1-F0) * pow(1-cosTheta, 5);
  410.   }
  411.  
  412.   Color getColor(Intersection inter, const Light* lgts, size_t lgt_num, int recursion_level) {
  413.     Ray reflected_ray;
  414.     reflected_ray.direction = reflect(inter.ray.direction, inter.normal);
  415.     reflected_ray.origin = inter.pos + 1e-3*reflected_ray.direction;
  416.     return F(fabs(dot(-inter.ray.direction, inter.normal))) * scene.shootRay(reflected_ray, recursion_level+1);
  417.   }
  418.  
  419.   void interact(Photon photon, Intersection inter, int recursion_level) {
  420.     Photon reflected(photon);
  421.     reflected.direction = reflect(inter.ray.direction, inter.normal);
  422.     reflected.origin = inter.pos + 1e-3*reflected.direction;
  423.     reflected.color = photon.color;
  424.     scene.shootPhoton(reflected, recursion_level+1);
  425.   }
  426. };
  427.  
  428. inline Vector refract(Vector I, Vector N, double n) {
  429.   double k = 1.0 - n * n * (1.0 - dot(N, I) * dot(N, I));
  430.   if (k < 0.0) {
  431.     return Vector();
  432.   } else {
  433.     return n * I - (n * dot(N, I) + sqrt(k)) * N;
  434.   }
  435. }
  436.  
  437. struct RefractiveMaterial : public ReflectiveMaterial {
  438.   float n, n_rec;
  439.  
  440.   RefractiveMaterial(float n, Color k)
  441.     : ReflectiveMaterial(n, k), n(n), n_rec(1 / n)
  442.   { }
  443.  
  444.   Color getColor(Intersection inter, const Light* lgts, size_t lgt_num, int recursion_level) {
  445.     if(dot(inter.ray.direction, inter.normal) > 0) {
  446.       inter.normal = -inter.normal;
  447.     }
  448.  
  449.     Ray reflected;
  450.     reflected.direction = reflect(inter.ray.direction, inter.normal);
  451.     reflected.origin = inter.pos + 1e-3*reflected.direction;
  452.  
  453.     Color reflectedColor, refractedColor;
  454.  
  455.     Ray refracted;
  456.     refracted.direction = refract(inter.ray.direction, inter.normal, inter.ray.in_air ? n : n_rec);
  457.     if(!refracted.direction.isNull()) {
  458.       refracted.origin = inter.pos + 1e-3 * refracted.direction;
  459.       refracted.in_air = !inter.ray.in_air;
  460.  
  461.       Color F_vec = F(dot(-inter.ray.direction, inter.normal));
  462.       reflectedColor = F_vec * scene.shootRay(reflected, recursion_level+1);
  463.       refractedColor = (1-F_vec) * scene.shootRay(refracted, recursion_level+1);
  464.     } else {
  465.       reflectedColor = scene.shootRay(reflected, recursion_level+1);
  466.     }
  467.  
  468.     return reflectedColor + refractedColor;
  469.   }
  470.  
  471.   void interact(Photon photon, Intersection inter, int recursion_level) {
  472.     if(dot(inter.ray.direction, inter.normal) > 0) {
  473.       inter.normal = -inter.normal;
  474.     }
  475.  
  476.     Photon reflected(photon);
  477.     reflected.direction = reflect(photon.direction, inter.normal);
  478.     reflected.origin = inter.pos + 1e-3*reflected.direction;
  479.    
  480.     Photon refracted(photon);
  481.     refracted.direction = refract(photon.direction, inter.normal, photon.in_air ? n : n_rec);
  482.     if(!refracted.direction.isNull()) {
  483.       refracted.origin = inter.pos + 1e-3*refracted.direction;
  484.       refracted.in_air = !photon.in_air;
  485.  
  486.       Color F_vec = F(dot(-photon.direction, inter.normal));
  487.       reflected.color = F_vec * photon.color;
  488.       refracted.color = (1-F_vec) * photon.color;
  489.  
  490.       scene.shootPhoton(reflected, recursion_level + 1);
  491.       scene.shootPhoton(refracted, recursion_level + 1);
  492.     } else {
  493.       reflected.color = photon.color;
  494.       scene.shootPhoton(reflected, recursion_level + 1);
  495.     }
  496.   }
  497. };
  498.  
  499. struct UVMap {
  500.   virtual void getTexcoord(const Vector&, float*, float*) = 0;
  501.   ~UVMap() {}
  502. };
  503.  
  504.  
  505. struct GroundUVMap : public UVMap {
  506.   Vector ground_center;
  507.   size_t tex_size, ground_size;
  508.  
  509.   GroundUVMap(size_t tex_size, size_t ground_size, Vector ground_center = Vector())
  510.     : ground_center(ground_center), tex_size(tex_size), ground_size(ground_size) { }
  511.  
  512.   void getTexcoord(const Vector& pos, float* u, float* v) {
  513.     *u = (pos.x - ground_center.x + ground_size/2) * tex_size / ground_size;
  514.     *v = (pos.z - ground_center.z + ground_size/2) * tex_size / ground_size;
  515.   }
  516. };
  517.  
  518. template <size_t size>
  519. struct PhotonMappedMaterial : public SpecularMaterial {
  520. public:
  521.   Color photon_map[size][size];
  522.   UVMap* uvmap;
  523.  
  524.   PhotonMappedMaterial(UVMap* uvmap, const Color& diffuse_color, const Color& specular_color, float shininess)
  525.     : SpecularMaterial(diffuse_color, specular_color, shininess), uvmap(uvmap) { }
  526.  
  527.   Color getColor(Intersection inter, const Light* lgts, size_t lgt_num, int recursion_level) {
  528.     float u, v;
  529.     uvmap->getTexcoord(inter.pos, &u, &v);
  530.     size_t iu = u, iv = v;
  531.     const float fu = u-iu, fv = v-iv, cu = 1-fu, cv = 1-fv;
  532.  
  533.     Color bilinear_sample;
  534.     if(iu+1 <= size-1 && iv+1 <= size-1)  {
  535.       bilinear_sample = cu*cv*photon_map[iu][iv]   + fu*cv*photon_map[iu+1][iv] +
  536.                         cu*fv*photon_map[iu][iv+1] + fu*fv*photon_map[iu+1][iv+1];
  537.     } else {
  538.       bilinear_sample = photon_map[iu][iv];
  539.     }
  540.  
  541.     Color spec = SpecularMaterial::getColor(inter, lgts, lgt_num, recursion_level);
  542.  
  543.     return spec + DiffuseMaterial::diffuse_color * (bilinear_sample);
  544.   }
  545.  
  546.   void interact(Photon photon, Intersection inter, int recursion_level) {
  547.     if(recursion_level == 0) {
  548.       return;
  549.     }
  550.  
  551.     float u, v;
  552.     uvmap->getTexcoord(inter.pos, &u, &v);
  553.  
  554.     size_t iu = u, iv = v;
  555.     const float fu = u-iu, fv = v-iv, cu = 1-fu, cv = 1-fv;
  556.  
  557.     Color color = photon.color;
  558.  
  559.     photon_map[iu][iv] += cu*cv*color;
  560.     if(iu+1 <= size-1) {
  561.       photon_map[iu+1][iv] += fu*cv*color;
  562.     }
  563.     if(iv+1 <= size-1) {
  564.       photon_map[iu][iv+1] += cu*fv*color;
  565.     }
  566.     if(iu+1 <= size-1 && iv+1 <= size-1) {
  567.       photon_map[iu+1][iv+1] += fu*fv*color;
  568.     }
  569.   }
  570. };
  571.  
  572. GroundUVMap groundUV(64, 20, Vector(0, -1.1f, 0));
  573. PhotonMappedMaterial<64> photonMapped(&groundUV, Color(1, 1, 1), Color(4, 4, 4), 32);
  574. ReflectiveMaterial silver(Color(0.14, 0.16, 0.13), Color(4.1, 2.3, 3.1));
  575. ReflectiveMaterial copper(Color(0.2, 1.1, 1.2), Color(3.6, 2.6, 2.3));
  576. RefractiveMaterial glass(1.5, 0);
  577.  
  578. struct Triangle : public Object {
  579.   Vector a, b, c, normal;
  580.  
  581.   // Az óra járásával ellentétes (CCW) körüljárási irányt feltételez ez a kód.
  582.   Triangle(Material* mat, const Vector& a, const Vector& b, const Vector& c)
  583.     : Object(mat), a(a), b(b), c(c) {
  584.       Vector ab = b - a;
  585.       Vector ac = c - a;
  586.       normal = cross(ab.normalize(), ac.normalize()).normalize();
  587.   }
  588.  
  589.   // Ennek a függvénynek a megértéséhez rajzolj magadnak egyszerű ábrákat!
  590.   Intersection intersectRay(Ray r) {
  591.     // Először számoljuk ki, hogy melyen mekkora távot
  592.     // tesz meg a sugár, míg eléri a háromszög síkját
  593.     // A számoláshoz tudnuk kell hogy ha egy 'v' vektort
  594.     // skaliráisan szorzunk egy egységvektorral, akkor
  595.     // az eredmény a 'v'-nek az egységvektorra vetített
  596.     // hossza lesz. Ezt felhasználva, ha a sugár kiindulási
  597.     // pontjából a sík egy pontjba mutató vektort levetítjük
  598.     // a sík normál vektorára, akkor megkapjuk, hogy milyen
  599.     // távol van a sugár kiindulási pontja a síktól. Továbbá,
  600.     // ha az a sugár irányát vetítjük a normálvektorra, akkor meg
  601.     // megtudjuk, hogy az milyen gyorsan halad a sík fele.
  602.     // Innen a már csak a t = s / v képletet kell csak használnunk.
  603.     float ray_travel_dist = dot(a - r.origin, normal) / dot(r.direction, normal);
  604.  
  605.     // Ha a háromszög az ellenkező irányba van, mint
  606.     // amerre a sugár megy, akkor nincs metszéspontjuk
  607.     if(ray_travel_dist < 0)
  608.       return Intersection();
  609.  
  610.     // Számoljuk ki, hogy a sugár hol metszi a sugár síkját.
  611.     Vector plane_intersection = r.origin + ray_travel_dist * r.direction;
  612.  
  613.     /* Most már csak el kell döntenünk, hogy ez a pont a háromszög
  614.        belsejében van-e. Erre két lehetőség van:
  615.      
  616.        - A háromszög összes élére megnézzük, hogy a pontot a hároszög
  617.        egy megfelelő pontjával összekötve a kapott szakasz, és a háromszög
  618.        élének a vektoriális szorzata a normál irányába mutat-e.
  619.        Pl:
  620.      
  621.                  a
  622.                / |
  623.               /  |
  624.              /   |
  625.             /  x |  y
  626.            /     |
  627.           b------c
  628.  
  629.        Nézzük meg az x és y pontra ezt az algoritmust.
  630.        A cross(ab, ax), a cross(bc, bx), és a cross(ca, cx) és kifele mutat a
  631.        képernyőből, ugyan abba az irányba mint a normál vektor. Ezt amúgy a
  632.        dot(cross(ab, ax), normal) >= 0 összefüggéssel egyszerű ellenőrizni.
  633.        Az algoritmus alapján az x a háromszög belsejében van.
  634.  
  635.        Míg az y esetében a cross(ca, cy) befele mutat, a normállal ellenkező irányba,
  636.        tehát a dot(cross(ca, cy), normal) < 0 ami az algoritmus szerint azt jelenti,
  637.        hogy az y pont a háromszögön kívül van.
  638.      
  639.        - A ötlet lehetőség a barycentrikus koordinátáknak azt a tulajdonságát használja
  640.        ki, hogy azok a háromszög belsejében lévő pontokra kivétel nélkül nem negatívak,
  641.        míg a háromszögön kívül lévő pontokra legalább egy koordináta negatív.
  642.        Ennek a megoldásnak a használatához ki kell jelölnünk két tetszőleges, de egymásra
  643.        merőleges vektort a síkon, ezekre le kell vetíteninünk a háromszög pontjait, és
  644.        kérdéses pontot, és az így kapott koordinátákra alakzmanunk kell egy a wikipediáról
  645.        egyszerűen kimásolható képletet:
  646.        http://en.wikipedia.org/wiki/Barycentric_coordinate_system#Converting_to_barycentric_coordinates
  647.      
  648.        Én az első lehetőséget implementálom. */
  649.  
  650.     const Vector& x = plane_intersection;
  651.  
  652.     Vector ab = b - a;
  653.     Vector ax = x - a;
  654.  
  655.     Vector bc = c - b;
  656.     Vector bx = x - b;
  657.  
  658.     Vector ca = a - c;
  659.     Vector cx = x - c;
  660.  
  661.     if(dot(cross(ab, ax), normal) >= 0)
  662.       if(dot(cross(bc, bx), normal) >= 0)
  663.         if(dot(cross(ca, cx), normal) >= 0)
  664.           return Intersection(r, x, normal, true);
  665.  
  666.     return Intersection();
  667.   }
  668. };
  669.  
  670. void onInitialization() {
  671.   Light amb = {Light::Ambient, Vector(), Vector(), Color(0.2f, 0.2f, 0.2f)};
  672.   Light point = {Light::Point, Vector(-2.2f, 3.5f, 2.9f), Vector(), Color(10.0f, 40.0f, 40.0f)};
  673.   Light point2 = {Light::Point, Vector(1.3f, 1.4f, 1.7f), Vector(), Color(10.0f, 10.0f, 5.0f)};
  674.   Light point3 = {Light::Point, Vector(0.0f, 1.6f, 0.0f), Vector(), Color(5.0f, 5.0f, 5.0f)};
  675.   scene.AddLight(amb);
  676.   scene.AddLight(point);
  677.   scene.AddLight(point2);
  678.   scene.AddLight(point3);
  679.  
  680.   // Ground
  681.   scene.AddObject(new Triangle(&photonMapped, Vector(-10, -1.1f, -10), Vector(-10, -1.1f, +10), Vector(+10, -1.1f, +10)));
  682.   scene.AddObject(new Triangle(&photonMapped, Vector(+10, -1.1f, +10), Vector(+10, -1.1f, -10), Vector(-10, -1.1f, -10)));
  683.  
  684.   // Front face
  685.   scene.AddObject(new Triangle(&glass, Vector(+1, -1, -1), Vector(-1, -1, -1), Vector(-1, +1, -1)));
  686.   scene.AddObject(new Triangle(&glass, Vector(-1, +1, -1), Vector(+1, +1, -1), Vector(+1, -1, -1)));
  687.  
  688.   // Back face
  689.   scene.AddObject(new Triangle(&glass, Vector(+1, -1, +1), Vector(-1, -1, +1), Vector(-1, +1, +1)));
  690.   scene.AddObject(new Triangle(&glass, Vector(-1, +1, +1), Vector(+1, +1, +1), Vector(+1, -1, +1)));
  691.  
  692.   // Right face
  693.   scene.AddObject(new Triangle(&glass, Vector(+1, -1, -1), Vector(+1, -1, +1), Vector(+1, +1, +1)));
  694.   scene.AddObject(new Triangle(&glass, Vector(+1, +1, +1), Vector(+1, +1, -1), Vector(+1, -1, -1)));
  695.  
  696.   // Left face
  697.   scene.AddObject(new Triangle(&glass, Vector(-1, -1, -1), Vector(-1, -1, +1), Vector(-1, +1, +1)));
  698.   scene.AddObject(new Triangle(&glass, Vector(-1, +1, +1), Vector(-1, +1, -1), Vector(-1, -1, -1)));
  699.  
  700.   // Upper face
  701.   scene.AddObject(new Triangle(&glass, Vector(-1, +1, -1), Vector(-1, +1, +1), Vector(+1, +1, +1)));
  702.   scene.AddObject(new Triangle(&glass, Vector(+1, +1, -1), Vector(-1, +1, -1), Vector(+1, +1, +1)));
  703.  
  704.   // Lower face
  705.   scene.AddObject(new Triangle(&glass, Vector(-1, -1, +1), Vector(-1, -1, -1), Vector(+1, -1, +1)));
  706.   scene.AddObject(new Triangle(&glass, Vector(+1, -1, -1), Vector(+1, -1, +1), Vector(-1, -1, -1)));
  707.  
  708.   scene.shootPhotons(500000);
  709.   camera.takePicture();
  710. }
  711.  
  712. void onDisplay() {
  713.   glClear(GL_COLOR_BUFFER_BIT);
  714.  
  715.   Screen::Draw();
  716.  
  717.   glutSwapBuffers();
  718. }
  719.  
  720. void onIdle() {
  721.   static bool first_call = true;
  722.   if(first_call) {
  723.     glutPostRedisplay();
  724.     first_call = false;
  725.   }
  726. }
  727.  
  728. void onKeyboard(unsigned char key, int, int) {}
  729.  
  730. void onKeyboardUp(unsigned char key, int, int) {}
  731.  
  732. void onMouse(int, int, int, int) {}
  733.  
  734. void onMouseMotion(int, int) {}
  735.  
  736. int main(int argc, char **argv) {
  737.   glutInit(&argc, argv);
  738.   glutInitWindowSize(Screen::width, Screen::height);
  739.   glutInitWindowPosition(100, 100);
  740.   glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
  741.  
  742.   glutCreateWindow("Grafika pelda program");
  743.  
  744.   glMatrixMode(GL_MODELVIEW);
  745.   glLoadIdentity();
  746.   glMatrixMode(GL_PROJECTION);
  747.   glLoadIdentity();
  748.  
  749.   onInitialization();
  750.  
  751.   glutDisplayFunc(onDisplay);
  752.   glutMouseFunc(onMouse);
  753.   glutIdleFunc(onIdle);
  754.   glutKeyboardFunc(onKeyboard);
  755.   glutKeyboardUpFunc(onKeyboardUp);
  756.   glutMotionFunc(onMouseMotion);
  757.  
  758.   glutMainLoop();
  759.  
  760.   return 0;
  761. }
Advertisement
Add Comment
Please, Sign In to add comment