# T5 Supersampling (Milestone 2)

Now we are going to cast multiple rays through a pixel to obtain better results. It is similar that you are using a mobile phone/digital camera with more number of pixel sensors to take a high-resolution picture.

<figure><img src="https://3464970502-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3JUKGJZ67JX02QZdPhsy%2Fuploads%2FT1hQMtNUfP5a3jbDEAzE%2Fe098e441-f763-4c72-8cf9-eb607439ca27.png?alt=media&#x26;token=71c6d7c9-d318-448e-ab10-d5b6963f23bb" alt="" width="375"><figcaption></figcaption></figure>

This is not only important to achieve better edge renderings, but is also critial for the upcoming many-ray sampling.

#### T1 Add random number generation in rtweekend.h

Please add the content between&#x20;

\=================================&#x20;

in the following code:

Make sure to put color.h after interval.h in the common header section at the end.

```cpp
#ifndef RTWEEKEND_H
#define RTWEEKEND_H

#include <cmath>
//================================================
#include <cstdlib>
//================================================
#include <iostream>
#include <limits>
#include <memory>


// C++ Std Usings
using std::make_shared;
using std::shared_ptr;

// Constants
const double infinity = std::numeric_limits<double>::infinity();
const double pi = 3.1415926535897932385;

// Utility Functions
inline double degrees_to_radians(double degrees) {
    return degrees * pi / 180.0;
}

//================================================
inline double random_double() {
    // Returns a random real in [0,1).
    return std::rand() / (RAND_MAX + 1.0);
}

inline double random_double(double min, double max) {
    // Returns a random real in [min,max).
    return min + (max-min)*random_double();
}
//================================================

// Common Headers
// Make sure to put color.h after interval.h
#include "interval.h"
#include "color.h"
#include "ray.h"
#include "vec3.h"

#endif
```

### Generating Pixels with Multiple Samples

#### T2 Add a clamp() function in interval.h

Add a clamp(double x) function in interval.h to ensure all colour values are in the range of \[0, 1]. It is a straightforward function to check the values and limit them into \[0, 1].

Add the following clamp function to class interval:

```cpp
#ifndef INTERVAL_H
#define INTERVAL_H

class interval {
public:
// ....

    //================================================
    double clamp(double x) const {
        if (x < min) return min;
        if (x > max) return max;
        return x;
    }
    // ===============================================
// ...
};

const interval interval::empty    = interval(+infinity, -infinity);
const interval interval::universe = interval(-infinity, +infinity);

#endif
```

#### T3 Revise color.h to use the clamp function

```cpp
#ifndef COLOR_H
#define COLOR_H

#include "vec3.h"

using color = vec3;

void write_color(std::ostream& out, const color & pixel_color) {
    auto r = pixel_color.x();
    auto g = pixel_color.y();
    auto b = pixel_color.z();

    // Translate the [0,1] component values to the byte range [0,255].
    // int rbyte = int(255.999 * r);
    // int gbyte = int(255.999 * g);
    // int bbyte = int(255.999 * b);

    // ============================================
    static const interval intensity(0.000, 0.999);
    int rbyte = int(256 * intensity.clamp(r));
    int gbyte = int(256 * intensity.clamp(g));
    int bbyte = int(256 * intensity.clamp(b));
    // ============================================

    // Write out the pixel color components.
    out << rbyte << ' ' << gbyte << ' ' << bbyte << '\n';
}

#endif
```

#### T4  Add two class members to the camera class

In camera.h, do the following:

1. Add a public member samples\_per\_pixel.&#x20;

```cpp
//=====================================
    int    samples_per_pixel = 10; 
//=====================================
```

Revise your render() function as follows

```cpp
    void render(const hittable& world) {
        initialize();

        std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

        for (int j = 0; j < image_height; j++) {
            std::clog << "\rScanlines remaining: " << (image_height - j) << ' ' << std::flush;
            for (int i = 0; i < image_width; i++) {
                //auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);
                //auto ray_direction = pixel_center - center;
                //ray r(center, ray_direction);

                //color pixel_color = ray_color(r, world);
                //write_color(std::cout, pixel_color);

                color pixel_color(0,0,0);
                for (int sample = 0; sample < samples_per_pixel; sample++) {
                    ray r = get_ray(i, j);
                    pixel_color += ray_color(r, world);
                }
                write_color(std::cout, pixel_samples_scale * pixel_color);
            }
        }
        std::clog << "\rDone.                 \n";
    }
```

2. Add a private member double pixel\_samples\_scale;

```cpp
class camera {
private:
    int    image_height;   // Rendered image height
    point3 center;         // Camera center
    point3 pixel00_loc;    // Location of pixel 0, 0
    vec3   pixel_delta_u;  // Offset to pixel to the right
    vec3   pixel_delta_v;  // Offset to pixel below

    // ===================================
    double pixel_samples_scale;
    // ===================================
 
 // ...
 };
```

Use this variable in initialise() by adding one line

```cpp
void initialize() {
        image_height = int(image_width / aspect_ratio);
        image_height = (image_height < 1) ? 1 : image_height;

        //==============================================
        pixel_samples_scale = 1.0 / samples_per_pixel;
        //==============================================

        center = point3(0, 0, 0);
        ...
}
```

#### T5 Add two methods: `get_ray(i,j)` and sample\_square()

Function camera::get\_ray(i,j) obtain a ray from a subpixel.

sample\_square() is doing a random sampling in that pixel.   &#x20;

```cpp
    //=====================================
    ray get_ray(int i, int j) const {
        // Construct a camera ray originating from the origin and directed at randomly sampled
        // point around the pixel location i, j.

        auto offset = sample_square();
        auto pixel_sample = pixel00_loc
                          + ((i + offset.x()) * pixel_delta_u)
                          + ((j + offset.y()) * pixel_delta_v);

        auto ray_origin = center;
        auto ray_direction = pixel_sample - ray_origin;

        return ray(ray_origin, ray_direction);
    }
    
    vec3 sample_square() const {
        // Returns the vector to a random point in the [-.5,-.5]-[+.5,+.5] unit square.
        return vec3(random_double() - 0.5, random_double() - 0.5, 0);
    }
    //=====================================
```

#### Finally add oneline in your main()

```cpp
int main() {
    camera cam;
    cam.aspect_ratio = 16.0 / 9.0;
    cam.image_width = 400;

    //=======================================
    cam.samples_per_pixel = 100;
    //=======================================
    
    //...
}
```

### Build And Run Your Programme

Build you programme to make sure everything is correct.

Run your programme, for example:

```
./ray01.exe > image7.ppm
```

As we are using multiple rays per pixel, it will take much more time to generate one image.

If successful, you will see a similar result as previous, but with much smoother edges.

<figure><img src="https://3464970502-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3JUKGJZ67JX02QZdPhsy%2Fuploads%2FoaPiR6rcwIgEe768TmCZ%2F429c206a-a9ed-41fd-97eb-be5cf693aeda.png?alt=media&#x26;token=0527d10d-0d7b-4e39-9b60-44aef8c385b5" alt="" width="464"><figcaption></figcaption></figure>

<figure><img src="https://3464970502-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3JUKGJZ67JX02QZdPhsy%2Fuploads%2Fjh6O1fdWAtuEZxrxm6QN%2F9687c7eb-0952-4dfc-b3a0-0fef8a0b66b5.png?alt=media&#x26;token=e8c3e032-cc06-4932-b94a-f0d3dd5afe40" alt="" width="375"><figcaption></figcaption></figure>
