Войти
ПрограммированиеФорумГрафика

Методы расчета нормалей воды

Страницы: 1 2 3 4 Следующая »
#0
(Правка: 23:36) 22:08, 22 июля 2019

Добрый день,
Имеется вода с генерацией волн через FFT. (смещение вершин по XYZ)
По этой же текстуре FFT генерирую карту нормалей.
Так же использую алгоритм flow map (для которого как раз используется карта нормалей). 
Но у метода есть проблема, он поворачивает карту нормалей, и она уже не в worldspace.
Для костыльного решения я делаю блендинг между картой нормалей и производной нормалью (ddx/ddy derivatives normal)
Сейчас планирую добавить несколько доменов FFT что бы побороть тайлинг волн.
То есть для 4 доменов мне надо читать нормали 8 раз в вершинном шейдере, и столько же в пиксельном + расчеты производных. А ещё есть динамические волны, это ещё куча семплов.

Хотелось бы в пиксельном шейдере избежать кучи расчетов и юзать одну конструкцию:

worldNormal = normalize(cross(ddx(i.worldPos), ddy(i.worldPos)));
Но она даёт плоские границы нормалей.
Думал как сгладить границы, и не смог ничего придумать.
Возможно ли такое в принципе?

Читал статью по производным, но там всё равно используется текстура для чтения высоты и смещения.
http://www.rorydriscoll.com/2012/01/11/derivative-maps

Может у кого есть идеи как получить корректные нормали иначе, или сгладить производные нормали? 


#1
22:43, 22 июля 2019

Если без циклов обходишься.
Ты крут. И ты сказал пиксельный шойдер? Это фрагментный штоле?

#2
2:55, 23 июля 2019

я храню карту высот каждой гармоники и предрассчитанные нормали для неё в текстуре. далее когда делаю fft, то перевожу нормали из image space в world space, используя tbn каждой гармоники, который можно аналитически рассчитать. самое веселье начинается при расчёте криволинейных базисов вроде прибоя, который с разных сторон на остров падает.

#3
9:55, 23 июля 2019

Suslik
А как для гармоники нормаль предрасчитать, в 2Д пространсве вдоль кривой? А как потом понять в какую сторону эта гармоника была завернута при FFT? Просто нормаль в world space же должна учитывать окружающие вершины хотя бы в 4 стороны. Непонятно)

#4
10:41, 23 июля 2019

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

#5
(Правка: 11:38) 11:20, 23 июля 2019

Suslik
> предрассчитывается не нормаль, а градиент карты высот. градиент поля
> преобразуется транспонированной матрицей преобразования. по преобразованному в
> мировые координаты градиенту можно рассчитать нормаль.
Чё-то слишком сложно я не понимать
Я рассчитываю нормали отдельным проходом шейдера в текстуру

float3 right = tex2D(_DispTex, i.uv + float2(_DispTex_TexelSize.x, 0)).xyz;
float3 left = tex2D(_DispTex, i.uv + float2(-_DispTex_TexelSize.x, 0)).xyz;
float3 top = tex2D(_DispTex, i.uv+ float2(0, _DispTex_TexelSize.y)).xyz;
float3 down = tex2D(_DispTex, i.uv + float2(0, -_DispTex_TexelSize.y)).xyz;
float3 normal = normalize(cross(top - down, right - left));
Получается 2 текстуры (FFT и нормаль). Зачем какие-то преобразования?

Suslik
> самое веселье начинается при расчёте криволинейных базисов вроде прибоя,
> который с разных сторон на остров падает.
Да вроде тоже не так сложно и нормали корректные

//waveSin = sin(f) где f расстояние из distance field
//dir это нормаль предпросчитанная из distance field
float3 tangent = float3(1 - dir.x * dir.x * waveSin, dir.x * waveCos, -dir.x * dir.y * waveSin);
float3 binormal = float3(-dir.x * dir.y * waveSin, dir.y * waveCos, 1 - dir.y * dir.y * waveSin);
float3 normal = normalize(cross(binormal, tangent));
vertex.y += waveSin;
vertex.xz += waveCos * dir
#6
12:15, 23 июля 2019

Kripto289
> Получается 2 текстуры (FFT и нормаль). Зачем какие-то преобразования?
затем, что то же самое можно предрассчитать и интерполировать предрассчитанные нормали — это быстрее, чем 4 дополнительные выборки ради этого.

> Да вроде тоже не так сложно и нормали корректные
код, написанный таким образом, вообще не обязан работать правильно.

#7
(Правка: 13:22) 13:19, 23 июля 2019

Suslik
> затем, что то же самое можно предрассчитать и интерполировать предрассчитанные
> нормали — это быстрее, чем 4 дополнительные выборки ради этого.
А где происходит расчет нормали? В пиксельном шейдере воды?
Можно псевдокод как это происходит, потому что я не пойму почему у меня медленее.
У меня сейчас так:
1) генерация FFT по 3 координатам (например 512 на 512)
2) генерация нормали  (512 на 512)
3) расчет воды и чтение текстуры fft/normal
То есть расчет нормали в фазе расчета воды не может быть быстрее, так как экранное пространство может быть больше 512 на 512 пикселей. (разве что случай, когда кусок воды занимает малую часть экрана)
Suslik
>код, написанный таким образом, вообще не обязан работать правильно.
Почему?
Нормали волн всегда повернуты в мировом пространстве корректно, хотя фронт волны вокруг острова.

#8
(Правка: 13:27) 13:26, 23 июля 2019

Kripto289
> Почему?
потому что по коду ни черта не понятно, что он делает из-за покомопонентной записи и кучи минусов. операции должны быть все в матричном/векторном виде, иначе можно где угодно допустить ошибку и потом её искать до второго пришествия, а потом через месяц вернуться к коду и ещё потратить столько же времени, чтоб понять, что он делает.

#9
13:29, 23 июля 2019

Почему в этой вашей (нашей) графике ничего не работает нормально? Чтобы что-то заработало нужно вникать жоска, и писать хаки. Один PBR чего стоит. То он слишком темный, то яркий, то гамма, то спекуляры...

#10
14:02, 23 июля 2019

lookid

> Почему в этой вашей (нашей) графике ничего не работает нормально?
Raytracing если хватает на все мощностей идеально простой
#11
14:03, 23 июля 2019

Suslik
> предрассчитывается не нормаль, а градиент карты высот. градиент поля
> преобразуется транспонированной матрицей преобразования. по преобразованному в
> мировые координаты градиенту можно рассчитать нормаль.
Это круто, при таком раскалде можно и пару FFT посчитать для водички, чтобы тайлинг убрать.

#12
(Правка: 14:17) 14:10, 23 июля 2019

Suslik
> потому что по коду ни черта не понятно, что он делает из-за покомопонентной
> записи и кучи минусов. операции должны быть все в матричном/векторном виде,
> иначе можно где угодно допустить ошибку и потом её искать до второго
> пришествия, а потом через месяц вернуться к коду и ещё потратить столько же
> времени, чтоб понять, что он делает.
Дак я привёл пример из этой статьи https://catlikecoding.com/unity/tutorials/flow/waves/

tangent += float3(
        -d.x * d.x * (steepness * sin(f)),
        d.x * (steepness * cos(f)),
        -d.x * d.y * (steepness * sin(f))
      );
      binormal += float3(
        -d.x * d.y * (steepness * sin(f)),
        d.y * (steepness * cos(f)),
        -d.y * d.y * (steepness * sin(f))
      );
      return float3(
        d.x * (a * cos(f)),
        a * sin(f),
        d.y * (a * cos(f))
      );
Так что за рефакторингом не ко мне :)

ps И всё же этот код рабочий, даже несмотря на то, что с первого взгляда не совсем ясно что происходит.
А по поводу нормалей можешь рассказать как используешь в своём проекте?
ps ps когда в пое завезут реалистичный блум для эффектов? Я бы снова вернулся пофармить хардкор лигу тупо из-за эффектов красивых. Я как vfx artist люблю дро*ить на эффектики :)

#13
(Правка: 14:13) 14:12, 23 июля 2019

Osiris
> Это круто, при таком раскалде можно и пару FFT посчитать для водички, чтобы
> тайлинг убрать.
Что собственно в первом посте и было написано =/

lookid
> Почему в этой вашей (нашей) графике ничего не работает нормально? Чтобы что-то
> заработало нужно вникать жоска, и писать хаки. Один PBR чего стоит. То он
> слишком темный, то яркий, то гамма, то спекуляры...
И какой посыл этого сообщения?

#14
14:28, 23 июля 2019

Kripto289
Обсессивно-компульсивное расстройство

Страницы: 1 2 3 4 Следующая »
ПрограммированиеФорумГрафика