Raytracing нормализующее пространство - PullRequest
0 голосов
/ 25 апреля 2019

Я нормализовал свои экранные координаты в диапазоне от -1 до +1.Затем я прослеживаю некоторые лучи, начиная с этих нормализованных координат, и вычисляю поле расстояния со знаком (sdf) с векторами начала и направления.

for (int i = 0; i < rterm::w; i++)
  for (int j = 0; j < rterm::h; j++) {
    float x = i / (rterm::w / 2.0f) - 1.0f;
    float y = j / (rterm::h / 2.0f) - 1.0f;

    glm::vec3 o = glm::vec3(x, y, -10.0f);
    glm::vec3 d = glm::vec3(0.0f, 0.0f, 1.0f);

    if (trace(o, d))
      rterm::ctx->buffer[i + j * rterm::w] = '#';
}

Файл sdf работает правильно, но в моем коде должна быть ошибка.Растеризованная сфера - это не сфера, это скорее так.

+---------------------------------+
|                                 |
|                                 |
|#########                        |
|#################                |
|#####################            |
|#######################          |
|#########################        |
|#########################        |
|#########################        |
|#########################        |
|#########################        |
|#######################          |
|#####################            |
|#################                |
|#########                        |
|                                 |
|                                 |
+---------------------------------+

sdf - это просто сфера.

float sphere(glm::vec3 p, float r) {
  return glm::length(p) - r;
}

float get(glm::vec3 p) {
  float ds = sphere(p, 0.8f);

  return ds;
}

А вот моя реализация трассировки.

bool trace(glm::vec3 o, glm::vec3 d) {
  float depth = 1.0f;

  for (int i = 0; i < MARCH_STEPS; i++) {
    float dist = sdf::get(o + d * depth);

    if (dist < EPSILON) return true;
    depth += dist;
    if (depth >= CLIP_FAR) return false;
  }

  return false;
}

1 Ответ

1 голос
/ 25 апреля 2019

Вы должны принять во внимание соотношение сторон вашего изображения, которое, как правило, не будет 1. Что вы в действительности делаете в данный момент, так это то, что вы определяете плоскость изображения как 2 единицы ширины и 2 единицы в высоту. Затем вы подразделяете эту плоскость изображения на сетку из rterm::w пикселей по x и rterm::h пикселей по y-измерению. Обратите внимание, что область, через которую вы излучаете лучи в мир, по-прежнему прямоугольная, вы просто подразделяете ее на разные интервалы вдоль осей x и y. Когда вы затем отображаете изображение с помощью какого-то стандартного механизма, который предполагает, что пиксели отбираются с одинаковым регулярным интервалом по обоим измерениям, изображение будет выглядеть искаженным.

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

float a = rterm::w * 1.0f / rterm::h;

Если, например, изображение шире, чем оно высокое, соотношение сторон будет больше 1. Если изображение выше, чем оно широко, соотношение сторон будет меньше единицы. Для неквадратного изображения, чтобы сделать расстояние между точками пикселей вдоль x и y одинаковыми, мы можем либо масштабировать координату x на a, либо масштабировать координату y на 1.0f / a. Например

float x = a * (i / (rterm::w / 2.0f) - 1.0f);
float y = j / (rterm::h / 2.0f) - 1.0f;

Примечание: * 1.0f в расчете соотношения сторон выше не является избыточным. Он там, чтобы заставить вычисление быть выполненным в float; в противном случае вы получите целочисленное деление (при условии, что ваше разрешение задается значениями целочисленного типа) & hellip;

...