Аналитические нормали к сфере, смещенной с помощью симплексного шума
Я хочу сделать планету сферой. Общая идея заключается в следующем:
- Создайте группу вершин единичной длины, которые составляют сферу.
- При визуализации сферы шейдер оценивает трехмерный симплексный шум в точке на единичной сфере.
- Результат используется как "высота" для смещения текущей вершины вдоль ее направления.
До сих пор все работает как надо.
Теперь я хочу добавить освещение и, следовательно, нужны нормали к поверхности.
При реализации частей, связанных с освещением, я быстро добавил метод оценки нормалей местности с использованием частных производных в фрагментном шейдере, например:
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 полностью верна.
Вычисление нормалей непосредственно из градиента возможно, как описано здесь.
И результат выглядит именно так, как я хотел, я счастлив;)