Raytracer - вычислительные лучи

Я пишу трассировщик лучей (в основном для удовольствия), и хотя я написал один в прошлом, и потратил приличное количество времени на поиск, никакие учебники, похоже, не пролили свет на способ вычисления лучей глаз в перспективная проекция без использования матриц.

Я полагаю, что в последний раз, когда я это делал, это было (потенциально) неэффективно вращением векторов глаз x/y градусов от вектора направления камеры с использованием класса Quaternion. Это было на С++, и я делаю это на С#, хотя это не так важно.

Псевдокод (при условии, что V * Q = операция преобразования)

yDiv = fovy / height
xDiv = fovx / width

for x = 0 to width
    for y = 0 to height

        xAng = (x / 2 - width) * xDiv
        yAng = (y / 2 - height) * yDiv
        Q1 = up vector, xAng
        Q2 = camera right vector, yAng
        Q3 = mult(Q1, Q2)

        pixelRay = transform(Q3, camera direction)
        raytrace pixelRay

    next
next

Я думаю, что реальная проблема заключается в том, что он имитирует сферическую поверхность экрана, а не плоскую поверхность экрана.

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

Итак, дано:

  • Положение камеры, направление и верхний вектор
  • Поле зрения
  • Экранные пиксели и/или субсэмплирующие подразделения

Каков фактический метод создания луча глаза для координат пикселя x/y для ратрайдера?

Чтобы уточнить: Я точно то, что я пытаюсь вычислить, я просто не очень разбираюсь в 3D-математике, чтобы вычислить его, и никакой код лучей, который я нахожу, кажется, код, который мне нужен, чтобы вычислить луч глаза для отдельного пикселя.

enter image description here

Ответ 1

enter image description here

INPUT: camera_position_vec, direction_vec, up_vec, screen_distance

right_vec = direction_vec x up_vec
for y from 0 to 1600:
    for x from 0 to 2560:
        # location of point in 3d space on screen rectangle
        P_3d = camera_position_vec + screen_distance*direction_vec
               + (y-800)*-up_vec
               + (x-1280)*right_vec

        ray = Ray(camera_position_vec, P_3d)
        yield "the eye-ray for `P_2d` is `ray`"

x означает поперечное произведение

изменить: Ответ предполагал, что direction_vec нормализуется, как и должно быть. right_vec находится на картинке (как бы там ни было слева), но right_vec не требуется, и, если он включен, всегда должен быть в том же направлении, что и -(up_vec x direction_vec). Кроме того, картина подразумевает, что x-координируется, когда один идет вправо, а y-координируется с уменьшением. Знаки были слегка изменены, чтобы отразить это. Увеличение может быть выполнено путем умножения х- и у-членов в уравнении или более эффективного умножения векторов и использования scaled_up_vec и scaled_right_vec. Масштаб, однако, эквивалентен (поскольку диафрагма не имеет значения, это идеальная камера с отверстиями), чтобы изменить поле зрения (FoV), которое намного лучше, чем для любого "масштабирования". Для получения информации о том, как реализовать FoV, см. Мой комментарий ниже.