# T5 Light Source and the Cornell Box (MS5)

### Add emitted() method in class material

add the virtual method emitted() in the abstract class material in material.h

```cpp
class material {
  public:
    virtual ~material() = default;

    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    virtual color emitted(double u, double v, const point3& p) const {
        return color(0,0,0);
    }
    // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


    virtual bool scatter(
        const ray& r_in, const hit_record& rec, color & attenuation, ray& scattered
    ) const {
        return false;
    }
};
```

### Add Emissive Material

Add a new emissive diffuse\_light material at the end of material.h

```cpp
class diffuse_light : public material {
  public:
    diffuse_light(shared_ptr<texture> tex) : tex(tex) {}
    diffuse_light(const color& emit) : tex(make_shared<solid_color>(emit)) {}

    color emitted(double u, double v, const point3& p) const override {
        return tex->value(u, v, p);
    }

  private:
    shared_ptr<texture> tex;
};
```

### Add Background Colour to class camera

Add a public color background in class camera in camera.h

```cpp
class camera {
  // ...
  public:
  // ...
    double aspect_ratio = 1.0;  // Ratio of image width over height
    int    image_width  = 100;  // Rendered image width in pixel count
    int    samples_per_pixel = 10; 
    int    max_depth = 10;   // Maximum number of ray bounces into scene

    double vfov = 90;  // Vertical view angle (field of view)
    // ...
      
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    color  background;               // Scene background color
    // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    //...
};
```

Revise the ray\_color() function of the camera class to return the background color if ray hits nothing.

```cpp
    color ray_color(const ray& r, int depth, const hittable& world) const {
        // If we've exceeded the ray bounce limit, no more light is gathered.
        if (depth <= 0)
            return color(0,0,0);

        hit_record rec;

        // choose a random direction to perform recursive ray tracing
        /*
        if (world.hit(r, interval(0.001, infinity), rec)) {
            ray scattered;
            color attenuation;
            if (rec.mat->scatter(r, rec, attenuation, scattered))
                return attenuation * ray_color(scattered, depth-1, world);
            return color(0,0,0);
        }

        vec3 unit_direction = unit_vector(r.direction());
        auto a = 0.5*(unit_direction.y() + 1.0);
        return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
        */
       
        // If the ray hits nothing, return the background color.
        if (!world.hit(r, interval(0.001, infinity), rec))
            return background;

        ray scattered;
        color attenuation;
        color color_from_emission = rec.mat->emitted(rec.u, rec.v, rec.p);

        if (!rec.mat->scatter(r, rec, attenuation, scattered))
            return color_from_emission;

        color color_from_scatter = attenuation * ray_color(scattered, depth-1, world);

        return color_from_emission + color_from_scatter;

    }
```

### Turn Objects into Lights

Add a simple light scene in main.cpp.

As we skipped the perlin noise part, we are still using the earth map texture here.

```cpp
void simple_light() {
    hittable_list world;

    // We skipped the perlin noise, so don't use this
    // auto pertext = make_shared<noise_texture>(4);
    auto pertext = make_shared<image_texture>("earthmap.jpg");
    world.add(make_shared<sphere>(point3(0,-1000,0), 1000, make_shared<lambertian>(pertext)));
    world.add(make_shared<sphere>(point3(0,2,0), 2, make_shared<lambertian>(pertext)));

    auto difflight = make_shared<diffuse_light>(color(4,4,4));
    world.add(make_shared<quad>(point3(3,1,-2), vec3(2,0,0), vec3(0,2,0), difflight));

    camera cam;

    cam.aspect_ratio      = 16.0 / 9.0;
    cam.image_width       = 400;
    cam.samples_per_pixel = 100;
    cam.max_depth         = 50;
    cam.background        = color(0,0,0);

    cam.vfov     = 20;
    cam.lookfrom = point3(26,3,6);
    cam.lookat   = point3(0,2,0);
    cam.vup      = vec3(0,1,0);

    cam.defocus_angle = 0;

    cam.render(world);
}

int main() {
    simple_light();
}
```

### Build and Run

If successful, you are going to see the following image

<figure><img src="https://3464970502-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3JUKGJZ67JX02QZdPhsy%2Fuploads%2FNFRkFDT8hkg68c9ab2vL%2F6aad4f1a-bb87-497f-bdf2-a15d23712f2e.png?alt=media&#x26;token=f29812e2-9f7c-4ff2-81f9-c92c3cef9021" alt="" width="310"><figcaption></figcaption></figure>

### Build the Cornell Box

Finally, we can set up the well-known cornell box&#x20;

```cpp
void cornell_box() {
    hittable_list world;

    auto red   = make_shared<lambertian>(color(.65, .05, .05));
    auto white = make_shared<lambertian>(color(.73, .73, .73));
    auto green = make_shared<lambertian>(color(.12, .45, .15));
    auto light = make_shared<diffuse_light>(color(15, 15, 15));

    world.add(make_shared<quad>(point3(555,0,0), vec3(0,555,0), vec3(0,0,555), green));
    world.add(make_shared<quad>(point3(0,0,0), vec3(0,555,0), vec3(0,0,555), red));
    world.add(make_shared<quad>(point3(343, 554, 332), vec3(-130,0,0), vec3(0,0,-105), light));
    world.add(make_shared<quad>(point3(0,0,0), vec3(555,0,0), vec3(0,0,555), white));
    world.add(make_shared<quad>(point3(555,555,555), vec3(-555,0,0), vec3(0,0,-555), white));
    world.add(make_shared<quad>(point3(0,0,555), vec3(555,0,0), vec3(0,555,0), white));

    camera cam;

    cam.aspect_ratio      = 1.0;
    cam.image_width       = 600;
    cam.samples_per_pixel = 200;
    cam.max_depth         = 50;
    cam.background        = color(0,0,0);

    cam.vfov     = 40;
    cam.lookfrom = point3(278, 278, -800);
    cam.lookat   = point3(278, 278, 0);
    cam.vup      = vec3(0,1,0);

    cam.defocus_angle = 0;

    cam.render(world);
}

int main() {
    cornell_box();
}
```

### Build and Run

Build your programme, if successful, run your programme from the powershell terminal.

The following is my command:

```
Measure-Command { ./ray01.exe > image29.ppm}
```

The output message from Mesuare-Command shows that it takes nearly 2 minutes to finish on my laptop

```
Days              : 0
Hours             : 0
Minutes           : 1
Seconds           : 57
Milliseconds      : 317
Ticks             : 1173177977
TotalDays         : 0.00135784488078704
TotalHours        : 0.0325882771388889
TotalMinutes      : 1.95529662833333
TotalSeconds      : 117.3177977
TotalMilliseconds : 117317.7977
```

The following is the output image, we can see a lot of noise in the image due to undersampling.

<figure><img src="https://3464970502-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3JUKGJZ67JX02QZdPhsy%2Fuploads%2FTw0z2X7wfzerxyaEXUgx%2F1029d1c2-12c8-4e62-9047-9a9b569ef41d.png?alt=media&#x26;token=fb5a00fa-fdf8-4d9e-bfd0-9ca8b161ab69" alt="" width="563"><figcaption></figcaption></figure>
