Аналитические нормали к сфере, смещенной с помощью симплексного шума

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

  • Создайте группу вершин единичной длины, которые составляют сферу.
  • При визуализации сферы шейдер оценивает трехмерный симплексный шум в точке на единичной сфере.
  • Результат используется как "высота" для смещения текущей вершины вдоль ее направления.

До сих пор все работает как надо.

Теперь я хочу добавить освещение и, следовательно, нужны нормали к поверхности.

При реализации частей, связанных с освещением, я быстро добавил метод оценки нормалей местности с использованием частных производных в фрагментном шейдере, например:

vec3 X = dFdx(ins.position);
vec3 Y = dFdy(ins.position);
vec3 normal = normalize(cross(X,Y));

где ins.position это интерполированная мировая позиция.

Хотя это работает, это выглядит не очень хорошо, потому что это, по сути, приводит к индивидуальным нормам.

Плохое нормальное приближение

Теперь к актуальным вопросам:

  • Вычисление нормалей для каждой вершины приведет к сглаживанию нормалей, в отличие от рисунка, верно?
  • Одно из преимуществ Simplex Noise по сравнению с Perlin Noise заключается в том, что он обладает "четко определенным и непрерывным градиентом везде, который можно вычислить довольно дешево" (чтобы привести превосходный демистифицированный Simplex Noise), и с помощью градиента нужно уметь вычислять нормально, правильно?

Если вопрос "да", у меня есть две проблемы:

  • Алгоритм симплексного шума был взят из популярного источника, который, к сожалению, не включает вычисление градиента. Я опубликую свою попытку добавления ниже, но я не знаю, правильно ли это.
  • Даже если бы у меня был градиент, я застрял на получении нормального значения оттуда.

Любая помощь очень ценится!

Мой выстрел в реализации градиента (заменил последние несколько строк шума):

float snoise(vec3 v, out vec3 grad)
{
    ......

    // Mix final noise value
    vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
    vec4 m2 = m * m;
    vec4 m4 = m2 * m2;

    vec4 pdotx = vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3));

    vec4 temp = m2 * m * pdotx;
    grad = -8.0 * (temp.x * x0 + temp.y * x1 + temp.z * x2 + temp.w * x3);
    grad += m4.x * p0 + m4.y * p1 + m4.z * p2 + m4.w * p3;
    grad *= 42.0;

    return 42.0 * dot(m4, pdotx);
}

ОБНОВИТЬ:

На вопрос о расчете нормали поверхности по градиенту здесь дан ответ: нормали поверхности к точке на смещенной сфере.

Остается вопрос, как реализовать вычисление градиента в GLSL-версии 3D Simplex Noise, потому что у моей реализации, похоже, есть проблемы.

ОБНОВЛЕНИЕ 2:

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

1 ответ

Решение

Хорошо, оказывается, моя проблема была почти чисто математической.

Если кому-то интересно:
Реализация расчета градиента, представленная в вопросе, в GLSL полностью верна.
Вычисление нормалей непосредственно из градиента возможно, как описано здесь.

И результат выглядит именно так, как я хотел, я счастлив;)

Гладкие нормали для каждой вершины

Другие вопросы по тегам