Bölüm 6: Kamera Sınıfı ve Kod Düzeni
Kodlarımız büyüdükçe main.cc dosyamızın içine hem görüntü çözünürlüğü hesapları, hem ışın üretimi, hem de sahne render döngüsü sıkışmaya başladı.
İyi bir yazılım mimarisinde iki temel sorumluluk birbirinden ayrılmalıdır:
1. Sahneyi Kurmak (main.cc): Nesneleri, materyalleri ve ışıkları tanımlamak.
2. Sahneyi Görüntülemek (camera.h): Işınları göndermek, pikselleri örneklemek ve görseli üretmek.
camera.h Sınıfının Tasarımı
Kamera sınıfımız iki temel kamuya açık (public) metoda ve üyelere sahip olacaktır:
- double aspect_ratio: En/boy oranı (örneğin 16:9).
- int image_width: Piksel genişliği (örneğin 400).
- void render(const hittable& world): Sahneyi render edip PPM çıktısını döken ana fonksiyon.
Aşağıdaki temiz yapıyı camera.h olarak kaydedelim:
| camera.h |
|---|
| #ifndef CAMERA_H
#define CAMERA_H
#include "rtweekend.h"
#include "hittable.h"
#include "color.h"
#include <iostream>
class camera {
public:
double aspect_ratio = 1.0; // Görüntü en/boy oranı
int image_width = 100; // Çıktı genişliği (piksel)
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 << "\rKalan satır: " << (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);
}
}
std::clog << "\rTamamlandı! \n";
}
private:
int image_height; // Hesaplanan görsel yüksekliği
point3 center; // Kamera merkez konumu
point3 pixel00_loc; // (0,0) pikselinin 3B uzaydaki konumu
vec3 pixel_delta_u; // Sağdaki komşu piksele geçiş vektörü
vec3 pixel_delta_v; // Aşağıdaki komşu piksele geçiş vektörü
void initialize() {
image_height = int(image_width / aspect_ratio);
image_height = (image_height < 1) ? 1 : image_height;
center = point3(0, 0, 0);
// Viewport Boyutları
auto focal_length = 1.0;
auto viewport_height = 2.0;
auto viewport_width = viewport_height * (double(image_width)/image_height);
// Viewport kenar vektörleri
auto viewport_u = vec3(viewport_width, 0, 0);
auto viewport_v = vec3(0, -viewport_height, 0);
// Pikseller arası mesafeler
pixel_delta_u = viewport_u / image_width;
pixel_delta_v = viewport_v / image_height;
// Sol üst pikselin 3B konumu
auto viewport_upper_left = center - vec3(0, 0, focal_length) - viewport_u/2 - viewport_v/2;
pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
}
color ray_color(const ray& r, const hittable& world) const {
hit_record rec;
if (world.hit(r, 0, infinity, rec)) {
return 0.5 * (rec.normal + color(1,1,1));
}
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);
}
};
#endif
|
Sadeleşen main.cc
Bakın ana programımız ne kadar berrak ve minimalist bir hale geldi:
| main.cc |
|---|
| #include "rtweekend.h"
#include "camera.h"
#include "hittable.h"
#include "hittable_list.h"
#include "sphere.h"
int main() {
// Sahne Nesneleri
hittable_list world;
world.add(make_shared<sphere>(point3(0,0,-1), 0.5));
world.add(make_shared<sphere>(point3(0,-100.5,-1), 100));
// Kamera Ayarları
camera cam;
cam.aspect_ratio = 16.0 / 9.0;
cam.image_width = 400;
// Render!
cam.render(world);
}
|
Bu modüler yapı sayesinde ileride kameramıza alan derinliği, serbest hareket etme yeteneği veya örtüşme önleme eklerken main.cc kodumuza dokunmamız bile gerekmeyecek!