Ana içeriğe geç

Bölüm 11: Konumlandırılabilir Kamera

Işın izleyicimiz şu ana kadar sabit bir noktaya çakılıydı: Kameramız dünyada \((0, 0, 0)\) merkezindeydi ve sadece \(-Z\) eksenine doğru bakabiliyordu.

Gerçek bir film yönetmeni gibi davranabilmek için: - Kamerayı sahnede istediğimiz noktaya taşıyabilmeli (lookfrom), - İstediğimiz hedefe yöneltebilmeli (lookat), - Kameranın başını dik veya yana eğik tutabilmeli (vup), - Ve merceğimizi geniş açı veya dar telefoto yapabilmeliyiz (Field of View / FOV).


Kamera Görüş Geometrisi (Camera Viewing Geometry)

Görüş açısı (Field of View / FOV), kameranın dünyayı ne kadar geniş bir açıdan gördüğünü belirler. Genellikle dikey görüş açısı (vfov) derece cinsinden kullanılır:

Görüş Açısı Geometrisi

Açı \(\theta\) olduğunda, \(1\) birim odak mesafesindeki görüş penceresinin (viewport) yarı yüksekliği trigonometrik tanjant ile hesaplanır:

\[h = \tan\left(\frac{\theta}{2}\right)\]

Böylece toplam görüş penceresi yüksekliği \(2h\) olur.

Örneğin: - Eğer \(\theta = 90^\circ\) ise: \(h = \tan(45^\circ) = 1.0\), toplam yükseklik \(2.0\)'dır. - Eğer \(\theta = 20^\circ\) ise: \(h = \tan(10^\circ) \approx 0.176\), toplam yükseklik \(\approx 0.35\)'tir (muazzam bir yakınlaştırma / zoom etkisi).


Kamerayı Yönlendirmek: LookFrom, LookAt ve Vup

Kameramızın 3B uzaydaki konumunu ve yönünü tam olarak tanımlamak için üç parametre kullanırız: 1. lookfrom: Kameranın uzaydaki konumu (Göz nerededir?). 2. lookat: Kameranın baktığı hedef nokta (Nereye odaklandık?). 3. vup: Kameranın dikey ekseni (View Up - Başımızın baktığı üst yön; genellikle \((0, 1, 0)\)).

Kamera Bakış Doğrultusu Kamera Yukarı Vektörü

Bu üç parametreden, kameranın kendi yerel koordinat sistemini tanımlayan ortonormal taban vektörlerini (\(\mathbf{u}, \mathbf{v}, \mathbf{w}\)) çıkarırız:

  1. \(\mathbf{w}\) Eksen Vektörü: Kameranın baktığı yönün tam tersi (geriye doğru bakan birim vektör): $\(\mathbf{w} = \text{unit\_vector}(\text{lookfrom} - \text{lookat})\)$
  2. \(\mathbf{u}\) Eksen Vektörü: Kameranın sağına doğru bakan birim vektör (\(\mathbf{vup}\) ile \(\mathbf{w}\) vektörlerinin vektörel çarpımı): $\(\mathbf{u} = \text{unit\_vector}(\mathbf{vup} \times \mathbf{w})\)$
  3. \(\mathbf{v}\) Eksen Vektörü: Kameranın gerçek yerel yukarı vektörü (\(\mathbf{w}\) ile \(\mathbf{u}\) vektörlerinin vektörel çarpımı): $\(\mathbf{v} = \mathbf{w} \times \mathbf{u}\)$

Bu üç vektör birbirine \(90^\circ\) diktir ve kameramızın yerel uzayını oluşturur!


camera.h Sınıfının Güncellenmesi

Kamera sınıfımıza bu yeni özellikleri ekleyelim:

camera.h (Konumlandırılabilir Kamera)
class camera {
  public:
    double aspect_ratio      = 1.0;
    int    image_width       = 100;
    int    samples_per_pixel = 10;
    int    max_depth         = 10;

    double vfov     = 90;              // Dikey görüş açısı (derece)
    point3 lookfrom = point3(0,0,0);   // Kameranın konumu
    point3 lookat   = point3(0,0,-1);  // Baktığı hedef
    vec3   vup      = vec3(0,1,0);     // Yukarı vektörü

    void render(const hittable& world) {
        initialize();
        // ... render döngüsü ...
    }

  private:
    int    image_height;
    point3 center;
    point3 pixel00_loc;
    vec3   pixel_delta_u;
    vec3   pixel_delta_v;
    vec3   u, v, w; // Kamera yerel taban eksenleri

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

        center = lookfrom;

        // Odak mesafesi ve Viewport boyutları
        auto focal_length = (lookfrom - lookat).length();
        auto theta = degrees_to_radians(vfov);
        auto h = std::tan(theta/2);
        auto viewport_height = 2 * h * focal_length;
        auto viewport_width = viewport_height * (double(image_width)/image_height);

        // Kamera yerel eksenlerini hesapla
        w = unit_vector(lookfrom - lookat);
        u = unit_vector(cross(vup, w));
        v = cross(w, u);

        // Viewport kenar vektörleri
        auto viewport_u = viewport_width * u;
        auto viewport_v = viewport_height * -v;

        pixel_delta_u = viewport_u / image_width;
        pixel_delta_v = viewport_v / image_height;

        auto viewport_upper_left = center - (focal_length * w) - viewport_u/2 - viewport_v/2;
        pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
    }
};

Sinematik Kamera Açıları

Artık kameramızı geriye ve yukarıya çekip dar açıyla baktırdığımızda:

main.cc (Kamera Ayarı)
1
2
3
4
cam.vfov     = 20;
cam.lookfrom = point3(-2, 2, 1);
cam.lookat   = point3(0, 0, -1);
cam.vup      = vec3(0, 1, 0);

Render sonucumuz:

Sinematik Açıdan Render

Kameranın konumu ve bakış açısı değiştikçe nesneler arasındaki perspektif ilişkisi ve derinlik hissi sinematik bir tabloya dönüştü!