# T2 Texture Mapping (MS2)

### Create class texture

create texture.h where you are writing your abstract texture class.

It only defines a virtual method value() which returns a colour value.

We also define a class solid\_color to implemented texture. It only has a private member albedo and the value() method returns that colour.

```cpp
#ifndef TEXTURE_H
#define TEXTURE_H

class texture {
  public:
    virtual ~texture() = default;
    virtual color value(double u, double v, const point3& p) const = 0;
};

class solid_color : public texture {
  public:
    solid_color(const color& albedo) : albedo(albedo) {}
    solid_color(double red, double green, double blue) : solid_color(color(red,green,blue)) {}

    color value(double u, double v, const point3& p) const override {
        return albedo;
    }

  private:
    color albedo;
};

#endif
```

### Add u, v in hit\_record (hittable.h)

We need the (u,v) coordinates to retrieve colour from the texture.

```cpp
class hit_record {
  public:
    point3 p;
    vec3 normal;
    shared_ptr<material> mat; 
    double t;
    
    double u; // <<<<<<<<<<<<<<<<<<<<<<<<<
    double v; // <<<<<<<<<<<<<<<<<<<<<<<<<

    // if the intersected face orients to the viewer
    bool front_face;
    // ...
};
```

### Checker Texture

add class checker\_texture in texture.h to implement the abstract texture classs

```cpp
class checker_texture : public texture {
  public:
    checker_texture(double scale, shared_ptr<texture> even, shared_ptr<texture> odd)
      : inv_scale(1.0 / scale), even(even), odd(odd) {}

    checker_texture(double scale, const color& c1, const color& c2)
      : checker_texture(scale, make_shared<solid_color>(c1), make_shared<solid_color>(c2)) {}

    color value(double u, double v, const point3& p) const override {
        auto xInteger = int(std::floor(inv_scale * p.x()));
        auto yInteger = int(std::floor(inv_scale * p.y()));
        auto zInteger = int(std::floor(inv_scale * p.z()));

        bool isEven = (xInteger + yInteger + zInteger) % 2 == 0;

        return isEven ? even->value(u, v, p) : odd->value(u, v, p);
    }

  private:
    double inv_scale;
    shared_ptr<texture> even;
    shared_ptr<texture> odd;
};
```

### Add texture to the lambertian class in material.h

change the lambertian class in material.h to use the texture.

Use texture to replace albedo colour, revise the constructor of lambertian to use the texture.&#x20;

Revise the scatter method to use colour from the texture.

```cpp
#include "hittable.h"
#include "texture.h " // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

class material {
  // ...
};

class lambertian : public material {
  private:
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // color albedo;
    shared_ptr<texture> tex;
   // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

  public:
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    //lambertian(const color& albedo) : albedo(albedo) {}
    lambertian(const color& albedo) : tex(make_shared<solid_color>(albedo)) {}
    lambertian(shared_ptr<texture> tex) : tex(tex) {}
    // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


    bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
    const override {
        auto scatter_direction = rec.normal + random_unit_vector();

        // Catch degenerate scatter direction
        if (scatter_direction.near_zero())
            scatter_direction = rec.normal;

        scattered = ray(rec.p, scatter_direction);

        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        // attenuation = albedo;
        attenuation = tex->value(rec.u, rec.v, rec.p);
        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

        return true;
    }
};

// ...

```

### Modify the scene in main.cpp to use the textured lambertian material

Revise main.cpp

Add texture.h

Use the complex scene at the end of Book 1 ( Lab B03), replace the ground material  with our new material.

```cpp
#include "rtweekend.h"

#include "bvh.h"  
#include "camera.h"
#include "hittable.h"
#include "hittable_list.h"
#include "material.h" 
#include "sphere.h"
#include "texture.h" // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

int main() {
    hittable_list world;
    
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // auto ground_material = make_shared<lambertian>(color(0.5, 0.5, 0.5));
    // world.add(make_shared<sphere>(point3(0,-1000,0), 1000, ground_material));
    auto checker = make_shared<checker_texture>(0.32, color(.2, .3, .1), color(.9, .9, .9));
    world.add(make_shared<sphere>(point3(0,-1000,0), 1000, make_shared<lambertian>(checker)));
    // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    for (int a = -11; a < 11; a++) {
        for (int b = -11; b < 11; b++) {
        /// ...
        }
    }
    // ...
}
    
```

### Build and Run

Set a lower image resolution for testing.

```
    cam.image_width       = 400;
    cam.samples_per_pixel = 100;
```

Build your programme into the Release version.

If successfully built, run your program:

```
./ray01.exe > image24.ppm
```

With powershell, you can use Measure-Command to know the running time of your programme.

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

On Linux, you can use the time command.

The ouput of Measure-Command looks like the following, so that I can know it takes almost 1 minute and 39 seconds to run the programme.

```
Days              : 0
Hours             : 0
Minutes           : 1
Seconds           : 38
Milliseconds      : 889
Ticks             : 988898915
TotalDays         : 0.00114455892939815
TotalHours        : 0.0274694143055556
TotalMinutes      : 1.64816485833333
TotalSeconds      : 98.8898915
TotalMilliseconds : 98889.8915
```

The final result is the following, it looks darder because I skipped Gamma correction in the first book.

<figure><img src="https://3464970502-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3JUKGJZ67JX02QZdPhsy%2Fuploads%2FeE9yku8FAv8HS6aRcIGo%2Fd7b927fb-a602-4dd9-be47-490cea99a0e5.png?alt=media&#x26;token=df77d347-0c8c-4fb2-9cc6-a389f08438cc" alt="" width="461"><figcaption></figcaption></figure>
