diff --git a/README.md b/README.md index b866827..e9ea5a4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ A simple C++ Raytracer based on "Ray Tracing in One Weekend" book. ![render image with motion blur](docs/render-motion-blur.png) -![render image with marble textyre](docs/render-marble.png) +![render image with marble texture](docs/render-marble.png) + +![render image with diffuse light](docs/render-light.png) ## Features @@ -25,6 +27,7 @@ A simple C++ Raytracer based on "Ray Tracing in One Weekend" book. * Motion blur. * Checked textures. * Perlin noise based textures. +* Diffuse area light. ## Building diff --git a/docs/render-light.png b/docs/render-light.png new file mode 100644 index 0000000..c8cfd9f Binary files /dev/null and b/docs/render-light.png differ diff --git a/src/camera.cpp b/src/camera.cpp index 8745a86..5c50a25 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -5,29 +5,34 @@ using namespace std; -inline Color background(const Ray& ray) { +Color Camera::background(const Ray& ray) { + /* auto unitDir = ray.dir().unit(); auto a = 0.5 * (unitDir.y() + 1.0); return (1.0 - a) * Color(1.0, 1.0, 1.0) + a * Color(0.5, 0.7, 1.0); + */ + return _background; } -inline Color color(const Ray& ray, int depth, const shared_ptr& intersectable) { +Color Camera::color(const Ray& ray, int depth, const shared_ptr& intersectable) { if (depth <= 0) return Color(0.0, 0.0, 0.0); Hit hit; - if (intersectable->intersects(ray, Interval(0.001), hit)) { - Ray scattered; - Color attenuation; - if (hit.material()->scatter(ray, hit, attenuation, scattered)) - return attenuation * color(scattered, depth - 1, intersectable); - return Color(0,0,0); - } - - return background(ray); + if (!intersectable->intersects(ray, Interval(0.001), hit)) return background(ray); + + Ray scattered; + Color attenuation; + Color color_from_emission = hit.material()->emitted(hit.u(), hit.v(), hit.point()); + + if (!hit.material()->scatter(ray, hit, attenuation, scattered)) return color_from_emission; + + Color color_from_scatter = attenuation * color(scattered, depth - 1, intersectable); + + return color_from_emission + color_from_scatter; } Camera::Camera(double aspect, int samplesPerPixel, - int maxDepth, int imageWidth, double vfov, Vector lookFrom, Vector lookAt, Vector vup, double defocusAngle, double focusDist): _aspect(aspect), _samplesPerPixel(samplesPerPixel), _maxDepth(maxDepth), _lookFrom(lookFrom), - _lookAt(lookAt), _vup(vup), _defocusAngle(defocusAngle), _focusDist(focusDist) + int maxDepth, int imageWidth, double vfov, Vector lookFrom, Vector lookAt, Vector vup, Color background, double defocusAngle, double focusDist): _aspect(aspect), _samplesPerPixel(samplesPerPixel), _maxDepth(maxDepth), _lookFrom(lookFrom), + _lookAt(lookAt), _vup(vup), _background(background), _defocusAngle(defocusAngle), _focusDist(focusDist) { auto imageHeight = int(imageWidth / aspect); imageHeight = (imageHeight < 1) ? 1 : imageHeight; diff --git a/src/camera.h b/src/camera.h index 6e5f080..69660be 100644 --- a/src/camera.h +++ b/src/camera.h @@ -35,6 +35,8 @@ class Camera { Vector _defocusDiskU; Vector _defocusDiskV; + Color _background; + Point defocusDiskSample() { auto p = Vector::randomInUnitDisc(); return _lookFrom + (p.x() * _defocusDiskU) + (p.y() * _defocusDiskV); @@ -50,12 +52,15 @@ class Camera { Vector lookFrom = Vector(13.0, 2.0, 3.0), Vector lookAt = Vector(0.0, 0.0, 0.0), Vector vup = Vector(0.0, 1.0, 0.0), + Color background = Color(0.7, 0.8, 1.0), double defocusAngle = 0.6, double focusDist = 10.0); double aspect() const { return _aspect; } const Viewport& viewport() const { return _viewport; } + Color color(const Ray& ray, int depth, const std::shared_ptr& intersectable); + Color background(const Ray& ray); void render(const std::shared_ptr& intersectable, const std::string& filename); }; diff --git a/src/main.cpp b/src/main.cpp index 0ed8333..007ce20 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,7 +67,7 @@ void twoSpheres() { scene->add(make_shared(Point(0.0, -10.0, 0.0), 10.0, make_shared(checker))); scene->add(make_shared(Point(0.0, 10.0, 0.0), 10.0, make_shared(checker))); - Camera camera(16.0 / 9.0, 50, 50, 400, 20.0, Vector(13.0, 2.0, 3.0), Vector(0.0, 0.0, 0.0), Vector(0.0, 1.0, 0.0), 0.0, 10.0); + Camera camera(16.0 / 9.0, 50, 50, 400, 20.0, Vector(13.0, 2.0, 3.0), Vector(0.0, 0.0, 0.0), Vector(0.0, 1.0, 0.0), Color(0.7, 0.8, 1.0), 0.0, 10.0); camera.render(scene, "image.ppm"); } @@ -80,7 +80,7 @@ void earth() { shared_ptr scene = make_shared(); scene->add(globe); - Camera camera(16.0 / 9.0, 100, 50, 400, 20.0, Vector(0.0, 0.0, 12.0), Vector(0.0, 0.0, 0.0), Vector(0.0, 1.0, 0.0), 0.0, 10.0); + Camera camera(16.0 / 9.0, 100, 50, 400, 20.0, Vector(0.0, 0.0, 12.0), Vector(0.0, 0.0, 0.0), Vector(0.0, 1.0, 0.0), Color(0.7, 0.8, 1.0), 0.0, 10.0); camera.render(scene, "image.ppm"); } @@ -113,18 +113,34 @@ void quads() { scene->add(make_shared(Point(-2, 3, 1), Vector(4, 0, 0), Vector(0, 0, 4), upper_orange)); scene->add(make_shared(Point(-2,-3, 5), Vector(4, 0, 0), Vector(0, 0,-4), lower_teal)); - Camera camera(1.0, 100, 50, 400, 80.0, Vector(0, 0, 9), Vector(0, 0, 0), Vector(0.0, 1.0, 0.0), 0.0); + Camera camera(1.0, 100, 50, 400, 80.0, Vector(0, 0, 9), Vector(0, 0, 0), Vector(0.0, 1.0, 0.0), Color(0.7, 0.8, 1.0), 0.0); + + camera.render(scene, "image.png"); +} + +void simple_light() { + shared_ptr scene = make_shared(); + + auto pertext = make_shared(4); + scene->add(make_shared(Point(0.0, -1000.0, 0.0), 1000.0, make_shared(pertext))); + scene->add(make_shared(Point(0.0, 2.0, 0.0), 2.0, make_shared(pertext))); + + auto difflight = make_shared(Color(4.0, 4.0, 4.0)); + scene->add(make_shared(Point(3.0, 1.0, -2.0), Vector(2.0, 0.0, 0.0), Vector(0.0, 2.0, 0.0), difflight)); + + Camera camera(16.0 / 9.0, 500, 50, 1920, 20.0, Vector(26.0, 3.0, 6.0), Vector(0.0, 2.0, 0.0), Vector(0.0, 1.0, 0.0), Color(0.0, 0.0, 0.0), 0.0); camera.render(scene, "image.png"); } int main() { - switch (5) { + switch (6) { case 1: randomSpheres(); break; case 2: twoSpheres(); break; case 3: earth(); break; case 4: twoPerlinSpheres(); break; case 5: quads(); break; + case 6: simple_light(); break; } return 0; } diff --git a/src/material.h b/src/material.h index 595b3c6..f2fc5fc 100644 --- a/src/material.h +++ b/src/material.h @@ -9,6 +9,9 @@ class Material { virtual ~Material() = default; virtual bool scatter(const Ray& ray, const Hit& hit, Color& attenuation, Ray& scattered) const = 0; + virtual Color emitted(double u, double v, const Point& point) const { + return Color(0.0, 0.0, 0.0); + } }; @@ -89,3 +92,24 @@ class Dielectric : public Material { } }; + +class DiffuseLight : public Material { + +private: + + std::shared_ptr _texture; + +public: + + DiffuseLight(const std::shared_ptr& texture):_texture(texture) {} + DiffuseLight(const Color& color):_texture(std::make_shared(color)) {} + + bool scatter(const Ray &ray, const Hit &hit, Color &attenuation, Ray &scattered) const override { + return false; + } + + Color emitted(double u, double v, const Point &point) const override { + return _texture->color(u, v, point); + } + +};