Трассировка лучей на Rust. Часть 2. Луч.

2020-01-02 • edited 2021-02-06

В этой части мы создадим базовую структуру луча и применим его для генерации фоновой заливки.

Оглавление

Реализация структуры луча

Для определения того, какой цвет видит наблюдатель будем применять виртуальные лучи, при помощи которых мы определим какие пиксели изображения пересекаются лучами и каким должен быть цвет в точке пересечения. В рассматриваемом нами алгоритме трассировки лучей “глаза” испускают лучи, а не наоборот, как происходит в реальности. Зато этот механизм был бы весьма близок философам древности, которые именно так представляли себе механизм работы зрения.

Наша структура будет иметь следующий вид:

#[derive(Debug, Copy, Clone)]
pub struct Ray {
    pub origin: Vec3,
    pub direction: Vec3,
}

У каждого луча есть начало и направления, также мы просим компилятор реализовать за нас трейты Copy, Clone, Debug. Реализуем сразу трейт PartialEq:

impl PartialEq for Ray {
    fn eq(&self, other: &Self) -> bool {
        self.origin == other.origin && self.direction == other.direction
    }
}

и функции, которые понадобятся далее:

impl Ray {
    pub fn point_at(&self, t: f64) -> Vec3 {
        self.origin + t * self.direction
    }

    pub fn new(origin: Vec3, direction: Vec3) -> Ray {
        Ray {
            origin: origin,
            direction: direction,
        }
    }
}

Функция new упрощает создание нового луча, а point_at позволяет вычислить положение точки на луче в момент времени t, предполагая, что в начальный момент времени луч находится в точке origin.

Применение лучей для расчёта фонового цвета

Вернёмся к основной функции программы, реализованной в первой части. В прошлый раз мы заливали фон градиентом, теперь же попробуем учесть положение наблюдателя при раскраске фона.

Пусть ось x направлена вправо, ось y “вверх”, а полотно в противоположном оси z направлении.

scene

Цвет фона будет определяться при помощи следующей функции по простому линейному правилу - пиксели находящиеся “ниже” по оси y будут более белыми, а те что выше - более синими:

fn color(ray: &Ray) -> Vec3 {
    let unit_direction = ray.direction.unit_vector();

    let t = 0.5_f64 * (unit_direction.y() + 1_f64);

    (1_f64 - t) * Vec3::new(1_f64, 1_f64, 1_f64) + t * Vec3::new(0.5_f64, 0.7_f64, 1.0_f64)
}

В этой функции мы сначала нормализуем направляющий вектор виртуального луча (unit_direction), следовательно $$ -1 \leqslant y \leqslant 1.$$ Затем масштабированием $$y$$ получаем $$t$$ из диапазона $$0 \leqslant t \leqslant 1.$$ Значение $$t = 1$$ соответствует синему цвету, а $$t = 0$$ - белому. Промежуточные цвета получим при помощи линейной интерполяции:

$$ interColor = (1-t) \cdot startColor + t\cdot endColor. $$

Далее перепишем функцию main, применив функцию color для определения фонового цвета.

fn main() {
    let mut file = File::create("img.ppm").expect("Unable to create file!");
    let nx = 400;
    let ny = 200;
    writeln!(&mut file, "P3\n {} {} \n255", nx, ny).expect("Unable to write to file!");

    let lower_left_corner = Vec3::new(-2_f64, -1_f64, -1_f64);
    let horizontal = Vec3::new(4_f64, 0_f64, 0_f64);
    let vertical = Vec3::new(0_f64, 2_f64, 0_f64);
    let origin = Vec3::default();

    for j in (0..ny).rev() {
        for i in 0..nx {
            let u = (i as f64) / (nx as f64);
            let v = (j as f64) / (ny as f64);

            let r = Ray::new(origin, lower_left_corner + u * horizontal + v * vertical);
            let col = color(&r);
            let ir = (255.99 * col.r()) as i64;
            let ig = (255.99 * col.g()) as i64;
            let ib = (255.99 * col.b()) as i64;
            writeln!(&mut file, "{} {} {}", ir, ig, ib).expect("Unable to write to file");
        }
    }
}

В результате получим градиентный фон:

background

Примечание

Данная заметка написана в рамках реализации трассировки лучей на Rust. Остальные статьи из этой серии можно найти по следующему тегу или в первой публикации из цикла .

Исходный код проекта доступен на github.

Полезные материалы

  1. Лекции по программированию на Rust от Computer Science Center.
  2. Programming Rust: Fast, Safe Systems Development.
  3. Серия книг про трассировку лучей.
developmentrustdevelopmentstudyraytracerrustraytracer
License: MIT

Трассировка лучей на Rust. Часть 3. Сфера.

К постам теперь можно оставлять комментарии

comments powered by Disqus