Ana içeriğe geç

Bölüm 9: Metal ve Ayna Yansıması

Sahnemize farklı optik özelliklere sahip nesneler eklemek istiyoruz: Bazıları mat olsun, bazıları cilalı metal gibi parlasın, bazıları ise cam gibi ışığı kırsın!

Bunun için nesnelerimizi materyal sınıflarından soyutlayacağız.


material.h Soyut Sınıfı

Bir materyal iki temel soruya cevap vermelidir: 1. Gelen ışın yüzeye çarptığında saçılacak mı (yeni bir ışın üretilecek mi)? 2. Saçılırsa ışığın rengi ne kadar zayıflayacak (attenuation / soğurulma)?

material.h
#ifndef MATERIAL_H
#define MATERIAL_H

#include "rtweekend.h"

class hit_record;

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

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

#endif

Lambertian (Mat) Materyali

Önceki bölümdeki mat davranışı material sınıfından türetelim:

material.h (Lambertian Sınıfı)
class lambertian : public material {
  public:
    lambertian(const color& albedo) : albedo(albedo) {}

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

        // Eğer rastgele vektör tam tersi yöndeyse normal sıfırlanabilir
        if (scatter_direction.near_zero())
            scatter_direction = rec.normal;

        scattered = ray(rec.p, scatter_direction);
        attenuation = albedo;
        return true;
    }

  private:
    color albedo;
};

Metal ve Yansıma Vektörü Matematiği

Pürüzsüz, ayna gibi bir metal için gelen ışık yüzey normaline göre simetrik olarak yansır:

Yansıma Geometrisi

Gelen vektör \(\mathbf{v}\) ve birim normal \(\mathbf{n}\) olduğunda, yansıyan vektör formülü:

\[\mathbf{r} = \mathbf{v} - 2(\mathbf{v} \cdot \mathbf{n})\mathbf{n}\]

vec3.h dosyamıza bu reflect fonksiyonunu ekleyelim:

vec3.h (Yansıma Fonksiyonu)
1
2
3
inline vec3 reflect(const vec3& v, const vec3& n) {
    return v - 2 * dot(v, n) * n;
}

Bulanık Yansıma (Fuzzy Reflection / Pürüzlülük)

Gerçek dünyada her metal mükemmel bir ayna değildir. Zımparalanmış veya fırçalanmış metaller ışığı hafifçe bulanık yansıtır.

Bunu modellemek için yansıyan ışının ucuna küçük bir rastgele küre ekler ve bu kürenin yarıçapını fuzz parametresi (\([0.0, 1.0]\)) ile kontrol ederiz:

Bulanık Yansıma

material.h (Metal Sınıfı)
class metal : public material {
  public:
    metal(const color& albedo, double fuzz) 
      : albedo(albedo), fuzz(fuzz < 1 ? fuzz : 1) {}

    bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
    const override {
        vec3 reflected = reflect(r_in.direction(), rec.normal);
        reflected = unit_vector(reflected) + (fuzz * random_unit_vector());
        scattered = ray(rec.p, reflected);
        attenuation = albedo;
        return (dot(scattered.direction(), rec.normal) > 0);
    }

  private:
    color albedo;
    double fuzz;
};

Metal Küreli Sahne Renderı

Sahnemize biri altın rengi parlayan, diğeri ise hafif bulanık gümüş metal iki küre yerleştirelim:

main.cc
1
2
3
4
5
6
7
8
9
auto material_ground = make_shared<lambertian>(color(0.8, 0.8, 0.0));
auto material_center = make_shared<lambertian>(color(0.1, 0.2, 0.5));
auto material_left   = make_shared<metal>(color(0.8, 0.8, 0.8), 0.3); // Gümüş (hafif bulanık)
auto material_right  = make_shared<metal>(color(0.8, 0.6, 0.2), 1.0); // Altın (mat pürüzlü)

world.add(make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground));
world.add(make_shared<sphere>(point3( 0.0,    0.0, -1.2),   0.5, material_center));
world.add(make_shared<sphere>(point3(-1.0,    0.0, -1.0),   0.5, material_left));
world.add(make_shared<sphere>(point3( 1.0,    0.0, -1.0),   0.5, material_right));

Render sonucumuz:

Metal Küreler Renderı

Kürelerin üzerinde birbirlerinin, zeminin ve gökyüzünün kusursuz yansımalarını görebilirsiniz! Sırada optik fiziğin en büyüleyici konusu var: Cam ve Kırılma (Dielectrics)!