Оптимизация системы рендеринга камеры-обскуры - PullRequest
2 голосов
/ 07 декабря 2009

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

Vec3 ray_to_camera = (a_Point - plane_pos).Normalize();

Это дает мне вектор направления к камере. Затем я превращаю это направление в луч, помещая источник луча на камеру и выполняя пересечение плоскости луча с плоскостью, немного расположенной за камерой.

Vec3 plane_pos = m_Position + (m_Direction * m_ScreenDistance);

float dot = ray_to_camera.GetDotProduct(m_Direction);
if (dot < 0)
{
   float time = (-m_ScreenDistance - plane_pos.GetDotProduct(m_Direction)) / dot;

   // if time is smaller than 0 the ray is either parallel to the plane or misses it
   if (time >= 0)
   {
      // retrieving the actual intersection point
      a_Point -= (m_Direction * ((a_Point - plane_pos).GetDotProduct(m_Direction)));

      // subtracting the plane origin from the intersection point 
      // puts the point at world origin (0, 0, 0)
      Vec3 sub = a_Point - plane_pos;

      // the axes are calculated by saying the directional vector of the camera
      // is the new z axis
      projected.x = sub.GetDotProduct(m_Axis[0]);
      projected.y = sub.GetDotProduct(m_Axis[1]);
   }
}

Это прекрасно работает, но мне интересно: можно ли сделать алгоритм быстрее? Прямо сейчас, для каждого треугольника в сцене, я должен вычислить три нормали.

float length = 1 / sqrtf(GetSquaredLength());
x *= length;
y *= length;
z *= length;

Даже с быстрым приближением квадратного корня (1 / sqrt(x)) это будет очень требовательным.

Мои вопросы таковы:
Есть ли хороший способ приблизить три нормали?
Как называется эта техника рендеринга?
Можно ли аппроксимировать три точки вершины, используя нормаль центроида? ((v0 + v1 + v2) / 3)

Заранее спасибо.

P.S. «В течение следующих семи недель вы создадите полнофункциональный программный растеризатор с помощью эксперта в этой области. Начните». Я обожаю свое образование. :)

EDIT:

Vec2 projected;

// the plane is behind the camera
Vec3 plane_pos = m_Position + (m_Direction * m_ScreenDistance);

float scale = m_ScreenDistance / (m_Position - plane_pos).GetSquaredLength();

// times -100 because of the squared length instead of the length
// (which would involve a squared root)
projected.x = a_Point.GetDotProduct(m_Axis[0]).x * scale * -100;
projected.y = a_Point.GetDotProduct(m_Axis[1]).y * scale * -100;

return projected;

Возвращает правильные результаты, однако модель теперь не зависит от положения камеры. (

Хотя это намного короче и быстрее!

Ответы [ 4 ]

4 голосов
/ 07 декабря 2009

Это называется ray-tracer - довольно типичное задание для первого курса по компьютерной графике * - и вы можете найти много интересных деталей реализации классического учебника Фоли / Ван Дамма ( Принципы и практика компьютерной графики ). Я настоятельно рекомендую вам купить / взять этот учебник и внимательно его прочитать.

* Просто подождите, пока вы не начнете размышления и преломления ... Теперь самое интересное начинается!

3 голосов
/ 08 декабря 2009

Трудно понять, что именно делает ваш код, потому что он, похоже, выполняет много избыточных операций! Однако, если я понимаю, что вы говорите, что пытаетесь сделать, вы:

  • Нахождение вектора от точечного отверстия до точки
  • нормализует его
  • проецирование назад по нормализованному вектору в «плоскость изображения» (за точечным отверстием, естественно!)
  • нахождение вектора к этой точке из центральной точки на плоскости изображения
  • создание точечных произведений для результата с векторами «оси» для нахождения координат экрана x и y

Если приведенное выше описание отражает ваши намерения, то нормализация должна быть излишней - вам вообще не нужно это делать! Если удаление нормализации дает вам плохие результаты, вы, вероятно, делаете что-то немного отличное от вашего заявленного плана ... другими словами, вполне вероятно, что вы запутались вместе со мной, и что этап нормализации "исправляет" это в той степени, в которой он выглядит достаточно хорошо в ваших тестовых примерах, хотя, вероятно, он все еще не делает то, что вам нужно.

Общая проблема, я думаю, заключается в том, что ваш код сильно перегружен: вы пишете всю свою высокоуровневую векторную алгебру как код, который будет выполняться во внутреннем цикле. Способ оптимизировать это состоит в том, чтобы проработать всю вашу векторную алгебру на бумаге, найти простейшее возможное выражение для вашего внутреннего цикла и предварительно вычислить все необходимые константы для этого во время настройки камеры. Спецификации камеры-обскуры будут только входными данными для процедуры настройки камеры.

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

3 голосов
/ 08 декабря 2009

Ваш код немного неясен для меня (plane_pos?), Но кажется, что вы могли бы исключить некоторые ненужные вычисления.

Вместо того, чтобы нормализовать луч (масштабируя его до длины 1), почему бы не масштабировать его так, чтобы компонент z был равен расстоянию от камеры до плоскости - фактически, масштабируя x и y этим фактором, вы не нужно z.

float scale = distance_to_plane/z;
x *= scale;
y *= scale;

Это даст координаты x и y на плоскости, без sqrt (), без точечных произведений.

0 голосов
/ 08 декабря 2009

Ну, вы можете вычислять нормали для каждого треугольника при запуске вашей программы. Затем, когда вы на самом деле бежите, вы просто должны получить доступ к нормальным. Такого рода расчеты при запуске для экономии затрат, как правило, часто происходят в графике. Вот почему у нас во многих наших видеоиграх большие экраны загрузки!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...