diff --git a/README.md b/README.md index 3e3be25..379f7fa 100644 --- a/README.md +++ b/README.md @@ -20,3 +20,7 @@ To build the project and run locally, cmake --build build ./build/Rendera/Rendera ``` + +```bash +cmake -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11 -S. -Bbuild -DCMAKE_BUILD_TYPE=Release +``` diff --git a/Rendera/include/cube.hpp b/Rendera/include/cube.hpp index bde78b8..1e81445 100644 --- a/Rendera/include/cube.hpp +++ b/Rendera/include/cube.hpp @@ -7,6 +7,23 @@ #include "ray.hpp" #include "material.hpp" + +//debug +class HitInfo{ + bool if_hit; + vec3 dist_v; + Material mat; + ray r; + int depth; + + public: + HitInfo(bool if_hit, vec3 v, Material m, ray r, int d):if_hit{if_hit}, dist_v{v}, mat{m}, r{r}, depth{d}{}; + +}; + + +// + // checks which point is farther going along the ray vec3 max(vec3 a, vec3 b, ray r) { @@ -41,7 +58,8 @@ class Cube vec3 m_position; vec3 m_a, m_b, m_c; Material m_material; - static const double m_epsilon = 1e-5; + vec3 int_pt; + const double m_epsilon = 1e-5; public: Cube(vec3 position, vec3 a, vec3 b, vec3 c, Material mat) : m_position{position}, m_a{a}, m_b{b}, m_c{c}, m_material{mat} {}; @@ -163,7 +181,7 @@ class Cube (all occurences are referenced when traversing along the ray direction) */ - HitInfo hit(const ray &r, int recursion_depth) + bool hit(const ray &r) { vec3 temp_a = plane_intersect(cross(m_b, m_c), m_position, r); vec3 temp_b = plane_intersect(cross(m_b, m_c), m_position + m_a, r); @@ -183,20 +201,33 @@ class Cube // if the ray is outside the cube amin comes after amax when going along the ray if(dot((amin-r.get_origin()),r.get_direction())>dot((amax-r.get_origin()),r.get_direction())) { - return {false, vec3(0,0,0), m_material, r, recursion_depth}; + // return {false, vec3(0,0,0), m_material, r, recursion_depth}; + return false; + } else if(dot(r.get_direction(),amax - r.get_origin())<0 ) // checks if both intersection are behind the r.origin { - return {false, vec3(0,0,0), m_material, r, recursion_depth}; + // return {false, vec3(0,0,0), m_material, r, recursion_depth}; + return false; } else if(dot(r.get_direction(),amin - r.get_origin())<0) // checks if r.origin is inside the cube { - return {true, amax, m_material, r, recursion_depth-1}; + // return {true, amax, m_material, r, recursion_depth-1}; + int_pt = amax; + return true; } - return {true, amin, m_material, r, recursion_depth-1}; // if two intersections, returns the closest one + // return {true, amin, m_material, r, recursion_depth-1}; // if two intersections, returns the closest one + int_pt = amin; + return true; } + vec3 get_int_pt(){ + return int_pt; + } + Material mat(){ + return m_material; + } }; #endif // CUBE_HPP diff --git a/Rendera/include/scene.hpp b/Rendera/include/scene.hpp index 9422cc6..1984eac 100644 --- a/Rendera/include/scene.hpp +++ b/Rendera/include/scene.hpp @@ -4,7 +4,7 @@ #include "sphere.hpp" #include "intersection.hpp" #include "camera.hpp" - +#include "cube.hpp" class Hitinfo{ public: bool ishitting = false; @@ -16,6 +16,7 @@ class Hitinfo{ color shade_new = {0,0,0}; color rgb; ray ref_ray; + Hitinfo() = default; }; color lighting(Material mat, ray cam_ray, ray normal, vec3 point, vec3 light_src, color intensity){ @@ -54,21 +55,25 @@ color lighting(Material mat, ray cam_ray, ray normal, vec3 point, vec3 light_src class Scene{ public: - int n_sphere; + int n_sphere = 1; + int n_cube = 0; uint16_t img_width; uint16_t img_height; Hitinfo *hitinfo = new Hitinfo[img_height*img_width]; - sphere *hitable_sphere = new sphere[n_sphere]; + std::vector hitable_sphere; + std::vector hitable_cube; vec3 light_src = {-5,3,5}; color light_col = {1,1,1}; + vec3 light_src2 = {0, 10, 0}; + - vec3 cam_origin = {0,0,0}; - float port_width = 8; - float port_height = 8; - float focal_length = 2; + vec3 cam_origin = {0,0,1}; + float port_width = 10; + float port_height = 10; + float focal_length = 4; int max_col = 255; Camera cam; @@ -85,29 +90,34 @@ class Scene{ } ~Scene(){ - delete hitable_sphere; delete hitinfo; } - void set_sphere(int index, vec3 center, float radius, Material mat){ - if (index < n_sphere) - hitable_sphere[index] = sphere(center, radius, mat); - else - std::cout<<"accessing wrong index"<::iterator sp; + std::vector::iterator cb; + hitinfo[y*img_width + x].ray_ = cam.get_ray(x, y); + // std::cout< i_.dist_1()){ hitinfo[y*img_width + x].dist = i_.dist_1(); hitinfo[y*img_width + x].intersection_pt = hitinfo[y*img_width + x].ray_.fetch(hitinfo[y*img_width + x].dist); - hitinfo[y*img_width + x].normal = hitable_sphere[i].normal(hitinfo[y*img_width + x].intersection_pt); - hitinfo[y*img_width + x].shade = lighting(hitable_sphere[i].mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].normal = (*sp).normal(hitinfo[y*img_width + x].intersection_pt); + hitinfo[y*img_width + x].shade = lighting((*sp).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].shade += lighting((*sp).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src2, light_col); hitinfo[y*img_width + x].rgb = hitinfo[y*img_width + x].shade.get_int(); hitinfo[y*img_width + x].ref_ray = reflect(hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal); } @@ -116,43 +126,92 @@ class Scene{ hitinfo[y*img_width + x].ishitting = true; hitinfo[y*img_width + x].dist = i_.dist_1(); hitinfo[y*img_width + x].intersection_pt = hitinfo[y*img_width + x].ray_.fetch(hitinfo[y*img_width + x].dist); - hitinfo[y*img_width + x].normal = hitable_sphere[i].normal(hitinfo[y*img_width + x].intersection_pt); - hitinfo[y*img_width + x].shade = lighting(hitable_sphere[i].mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].normal = (*sp).normal(hitinfo[y*img_width + x].intersection_pt); + hitinfo[y*img_width + x].shade = lighting((*sp).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].shade += lighting((*sp).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src2, light_col); + hitinfo[y*img_width + x].rgb = hitinfo[y*img_width + x].shade.get_int(); + hitinfo[y*img_width + x].ref_ray = reflect(hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal); + + } + } + + for(cb = hitable_cube.begin(); cb != hitable_cube.end(); ++cb){ + bool hits = (*cb).hit(hitinfo[y*img_width + x].ray_); + if(hitinfo[y*img_width + x].ishitting && hits){ + float d = (*cb).get_int_pt().norm(); + if (hitinfo[y*img_width + x].dist>d){ + hitinfo[y*img_width + x].ishitting = true; + hitinfo[y*img_width + x].intersection_pt = (*cb).get_int_pt(); + hitinfo[y*img_width + x].dist = d; + hitinfo[y*img_width + x].normal = (*cb).normal(hitinfo[y*img_width + x].intersection_pt); + hitinfo[y*img_width + x].shade = lighting((*cb).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].shade += lighting((*cb).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src2, light_col); + hitinfo[y*img_width + x].rgb = hitinfo[y*img_width + x].shade.get_int(); + hitinfo[y*img_width + x].ref_ray = reflect(hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal); + } + + } + else if(hits){ + hitinfo[y*img_width + x].ishitting = true; + hitinfo[y*img_width + x].intersection_pt = (*cb).get_int_pt(); + hitinfo[y*img_width + x].dist = hitinfo[y*img_width + x].intersection_pt.norm(); + hitinfo[y*img_width + x].normal = (*cb).normal(hitinfo[y*img_width + x].intersection_pt); + hitinfo[y*img_width + x].shade = lighting((*cb).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].shade += lighting((*cb).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src2, light_col); hitinfo[y*img_width + x].rgb = hitinfo[y*img_width + x].shade.get_int(); hitinfo[y*img_width + x].ref_ray = reflect(hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal); + } } } void next_depth(int x, int y){ - for(int i = 0; i < n_sphere; i++){ + std::vector::iterator sp; + std::vector::iterator cb; + for(sp = hitable_sphere.begin(); sp != hitable_sphere.end(); ++sp){ if(hitinfo[y*img_width + x].ishitting){ Intersection i_; - bool hits = i_.hit(hitable_sphere[i], hitinfo[y*img_width + x].ref_ray); - if (hitinfo[y*img_width + x].ishitting && hits){ + bool hits = i_.hit(*sp, hitinfo[y*img_width + x].ref_ray); + if (hits){ if (hitinfo[y*img_width + x].dist > i_.dist_1()){ hitinfo[y*img_width + x].dist = i_.dist_1(); hitinfo[y*img_width + x].intersection_pt = hitinfo[y*img_width + x].ref_ray.fetch(hitinfo[y*img_width + x].dist); - hitinfo[y*img_width + x].normal = hitable_sphere[i].normal(hitinfo[y*img_width + x].intersection_pt); - hitinfo[y*img_width + x].shade_new = lighting(hitable_sphere[i].mat(), hitinfo[y*img_width + x].ref_ray, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].normal = (*sp).normal(hitinfo[y*img_width + x].intersection_pt); + hitinfo[y*img_width + x].shade_new = lighting((*sp).mat(), hitinfo[y*img_width + x].ref_ray, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].shade_new = lighting((*sp).mat(), hitinfo[y*img_width + x].ref_ray, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src2, light_col); hitinfo[y*img_width + x].ref_ray = reflect(hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal); } } } } + + for(cb = hitable_cube.begin(); cb != hitable_cube.end(); ++cb){ + if(hitinfo[y*img_width + x].ishitting){ + bool hits = (*cb).hit(hitinfo[y*img_width + x].ray_); + if (hits){ + float d = (*cb).get_int_pt().norm(); + if (hitinfo[y*img_width + x].dist>d){ + hitinfo[y*img_width + x].intersection_pt = (*cb).get_int_pt(); + hitinfo[y*img_width + x].dist = d; + hitinfo[y*img_width + x].normal = (*cb).normal(hitinfo[y*img_width + x].intersection_pt); + hitinfo[y*img_width + x].shade_new = lighting((*cb).mat(), hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal, hitinfo[y*img_width + x].intersection_pt, light_src, light_col); + hitinfo[y*img_width + x].ref_ray = reflect(hitinfo[y*img_width + x].ray_, hitinfo[y*img_width + x].normal); + } + } + + } + } } void render(){ for(int x=0; x #include #include +#include + + + + int main(){ int n_sphere = 3; - int img_width = 5000; - int img_height = 5000; + int img_width = 500; + int img_height = 500; vec3 center = {3,-2,0}; vec3 center1 = {3, 1, 0}; vec3 center2 = {5, 0, 5}; + vec3 pos = {1,1,1}; + vec3 a_ = {1,0,0}; + vec3 b_ = {0, 1, 0}; + vec3 c_ = {0, 0, 1}; - float specular_cosine = dot(-cam_ray.get_direction(), reflect_ray.get_direction()); - float spec_factor = 0; color b = {0,0, 1}; color g = {0,1,0}; color r = {1, 0,0}; Material mat_1 ={b, 0.1, 1, 0.9, 200}; Material mat_2 = {g, 0.1, 1, 0.9, 200}; - Material mat_3 = {0.5*r + 0.2*b, 0.1, 1, 0.9, 200}; + Material mat_3 = {0.5*r + 0.2*b, 0.5, 1, 0.9, 200}; Scene sc(n_sphere, img_height, img_width); - sc.set_sphere(0, center, 1, mat_1); - sc.set_sphere(1, center1, 1, mat_2); - sc.set_sphere(2, center2, 1, mat_3); + sc.add_sphere(center, 1, mat_1); + sc.add_sphere(center1, 1, mat_2); + sc.add_sphere(center2, 1, mat_3); + sc.add_cube(pos, (a_+ b_)/4, (b_+c_)/2, (c_+a_)/2, mat_3); sc.render(); - int max_col = 255; - Camera cam(cam_origin, port_width, port_height, img_width, img_height, focal_length); - // Jpeg and png - // Making an array of such size as there are width*height pixels and each pixel has 3 RGB values. - std::uint8_t* pixels = new std::uint8_t[img_width * img_height * 3]; - int index = 0; //Index of the array containing RGB values of image for the current pixel - vec3 center = {3,-2,0}; - vec3 center1 = {3, 1, 0}; - vec3 center2 = {5, 0, 5}; - - color b = {0,0, 1}; - color g = {0,1,0}; - color r = {1, 0,0}; - Material mat_1 ={b, 0.1, 1, 0.9, 200}; - Material mat_2 = {g, 0.1, 1, 0.9, 200}; - Material mat_3 = {0.5*r + 0.2*b, 0.1, 1, 0.9, 200}; - Scene sc(n_sphere, img_height, img_width); - sc.set_sphere(0, center, 1, mat_1); - sc.set_sphere(1, center1, 1, mat_2); - sc.set_sphere(2, center2, 1, mat_3); - sc.render(); - int max_col = 255; std::ofstream image("sphere.ppm"); image << "P3\n"; image << img_width << " " << img_height << "\n"; image << max_col << "\n"; - for(int i = 0; i < img_height*img_width ; i++){ - if(sc.hitinfo[i].ishitting){ - image << sc.hitinfo[i].rgb.get_R() << " " << sc.hitinfo[i].rgb.get_G() << " " << sc.hitinfo[i].rgb.get_B()<<" " ; - pixels[index++] = sc.hitinfo[i].rgb.get_R(); - pixels[index++] = sc.hitinfo[i].rgb.get_G(); - pixels[index++] = sc.hitinfo[i].rgb.get_B(); - for(int i = 0; i < img_height*img_width ; i++){ if(sc.hitinfo[i].ishitting){ image << sc.hitinfo[i].rgb.get_R() << " " << sc.hitinfo[i].rgb.get_G() << " " << sc.hitinfo[i].rgb.get_B()<<" " ; @@ -83,12 +59,5 @@ int main(){ else image << "0 0 0 "; } - - stbi_write_png("Sphere.png", img_width, img_height, 3, pixels, img_width * 3); - std::cout<<"PNG image generated\n"; - stbi_write_jpg("Sphere.jpg", img_width, img_height, 3, pixels, 100); - std::cout<<"JPG image generated\n"; - delete[] pixels; - image.close() - return 0; + image.close(); } diff --git a/utilities/include/intersection.hpp b/utilities/include/intersection.hpp index 7031c37..2ffd264 100644 --- a/utilities/include/intersection.hpp +++ b/utilities/include/intersection.hpp @@ -10,13 +10,12 @@ class Intersection{ float t_2; public: - bool hit(const sphere &s, const ray &ray_1){ + bool hit(const Sphere &s, const ray &ray_1){ //make a quadratic equation in t vec3 a = ray_1.get_direction(); vec3 b = ray_1.get_origin(); vec3 c = s.c(); float radius = s.r(); - float alpha = a.norm()*a.norm(); //tsquare coeff float beta = 2*dot(a,b-c); //t coeff float gamma = (b-c).norm()*(b-c).norm() - radius*radius; //constant diff --git a/utilities/include/vec3.hpp b/utilities/include/vec3.hpp index e7cd116..f831d9a 100644 --- a/utilities/include/vec3.hpp +++ b/utilities/include/vec3.hpp @@ -35,6 +35,8 @@ class alignas(ALIGN_WIDTH) vec3 : public vec4{ constexpr explicit vec3(Utype x) : vec4{x,x,x,0} {} constexpr vec3(Utype x,Utype y,Utype z) : vec4{x,y,z,0} {} explicit vec3(xsimd::batch x) : vec4{x} {} + constexpr vec3(vec4 a): vec4{a.x(), a.y(), a.z(), a.w()}{} + vec3() = default; // cross-product friend constexpr vec3 cross(const vec3& v1,const vec3& v2){ diff --git a/utilities/include/vec4.hpp b/utilities/include/vec4.hpp index 398fec0..5e5a167 100644 --- a/utilities/include/vec4.hpp +++ b/utilities/include/vec4.hpp @@ -7,7 +7,6 @@ #include // for std::is_constant_evaluated #include - #include "config.hpp" /* *Macros provided by config.hpp - ALIGN_WIDTH: Alignment width for class, since it is dependent on Arch. @@ -59,15 +58,14 @@ class alignas(ALIGN_WIDTH) vec4{ return sum(temp); } } - - CONSTEXPR_CMATH Utype norm() const{ + constexpr Utype norm() const{ return std::sqrt(dot(*this,*this)); } - CONSTEXPR_CMATH Utype angle(const vec4& v1,const vec4& v2){ + constexpr Utype angle(const vec4& v1,const vec4& v2){ return std::acos(dot(v1,v2)/(v1.norm()*v2.norm())); } - CONSTEXPR_CMATH vec4 unit() const{ + constexpr vec4 unit() const{ return *this/this->norm(); }