Добрый день.
Сделал каустику воды с помощью высокополигональной меш-сетки в экранном пространстве. Предположим что сетка состоит из 1920*1080 вершин (для удобства вершина в каждом пикселе)
Параметры шейдера zTest Always / ZWrite Off / blend additive
Теперь алгоритм вкратце:
1) получаю буфер глубины сцены
2) преобразую глубину в мировые координаты
3) проецирую вершины по этим координатам. Получаем высокополигональную сетку натянутую на объекты в сцене.
4) анимация меша воды использует displacement карту XYZ, и читается как-то так waterVertex.xyz = tex2Dlod(DisplacementMap, float4(waterWorldPos.xz, 0, 1));
Теперь я просто читаю эту же карту но для декали.
decalVertex.xz = tex2Dlod(DisplacementMap, float4(decalWorldPos.xz, 0, 1)).xz * 5;
Замечу что для каустики достаточно усилить XZ смещение из displacement текстуры. В моём случае усиление зависит от глубины между водой и дном (если смотреть сверху).
Вот как выглядит результат:
http://kripto289.com/Shared/gamedev/causticTest.webm
Но есть проблема, смещение вершин выходит за границы объектов. Видно на стволах пальм.
Думал что смогу прочитать глубину из новой позиции вершины и отбросить её в случае, если глубина превышает старую глубину + небольшое смещение. Это хотя бы избавило бы от части артефактов, но не полностью.
Но скрин спейс uv/глубина после смещения выглядит неправильно.
Как можно побороть такие артефакты, если это вообще возможно?
Когда приглушенно, то норм выглядит. Немного на стволах отражается, в реале тоже должно немного отражаться.
Kripto289
> Как можно побороть такие артефакты
Что-то мне кажется, что никак. Да и сам метод очень тяжёлый.
Ещё недостаток - каустика попадает на участки, нормали которых направлены вверх, от воды.
Mikle
>Да и сам метод очень тяжёлый.
В сравнении с чем?
В гифке используется всего 256к полигонов.
Так же я могу рендерить меш в рендер таргет (например 512x512). Я думаю ещё более быстрого способа рендерить каустику в несколько строк кода в вершинном шейдере не существует.
Mikle
> Ещё недостаток - каустика попадает на участки, нормали которых направлены
> вверх, от воды.
Тут что-то на эльфийском и я не понимаю что тут написано. Как нормали поверхности могут быть направлены вверх от воды?
Если имеется ввиду отсечение выше поверхности, то это не проблема. У меня есть глубина сцены + отдельная глубина поверхности воды + маска водного объёма, поэтому могу сделать каустику только внутри водного объема. (хотя в реальности каустика выходит из воды)
Если что-то другое, например каустика на пузе у акулы, то можно подсчитать ddx/ddy нормаль из буфера глубины и отсекать нужное направление каким-нибудь френелем.
Или тут о другом речь?
Kripto289
> в реальности каустика выходит из воды
Естественно. У тебя по картинке не понятно, я думал, что это и нарисовано - стволы пальм торчат из воды.
А на стволах над поверхностью воды вижу каустику вне зависимости от того, в какую сторону направлены нормали.
Теперь понял, что это всё у тебя под водой, ты бы ещё кактусы там изобразил, чтобы совсем понятно было :)
Я делаю более простым, но чуть менее качественным путём.
Считаю проекцию по буферу глубины в вершинном шейдере, но вершины не смещаю, передаю результат как varying в фрагментный шейдер.
Вывожу каустику белым по черному.
В финальном рендере, перевожу координаты пикселя в координаты каустики и прибавляю цвет.
И каустика ложится прям ровно.
https://shielded-basin-29578.herokuapp.com/
Во вкладке Quality поставить Water resolution на максимум (512 сегментов)
Во вкладке Water меняем scale - получаем больше/меньше каустики.
Mikle
> Естественно. У тебя по картинке не понятно, я думал, что это и нарисовано -
> стволы пальм торчат из воды.
> А на стволах над поверхностью воды вижу каустику вне зависимости от того, в
> какую сторону направлены нормали.
> Теперь понял, что это всё у тебя под водой, ты бы ещё кактусы там изобразил,
> чтобы совсем понятно было :)
Я и забыл про это. Меш воды выглядел как-то так
Для меня то очевидно было где вода :)
Каустика на скрине сделана иным способом если что.
IIIarp
> Я делаю более простым, но чуть менее качественным путём.
> Считаю проекцию по буферу глубины в вершинном шейдере, но вершины не смещаю,
> передаю результат как varying в фрагментный шейдер.
> Вывожу каустику белым по черному.
> В финальном рендере, перевожу координаты пикселя в координаты каустики и
> прибавляю цвет.
> И каустика ложится прям ровно.
Я не совсем понял алгоритм. Я как альтернативный алгоритм использую меш со сдвигом но с видом сверху, а затем результат натягиваю как скрин-спейс декаль. Но в таком случае мне приходиться делать каскады, так как минусы метода как у каскадных теней.
У тебя примерно так?
Kripto289
Что-то в этом духе)
Что-бы мы точно были уверенны что мы говорим об одном и том же, опишу более детально.
Орто камера, которая находится в центре меша воды и смотри на дно, по left, right, bottom, top по размеру меша.
Один pass на захват карты глубины дна, второй этой же камерой на проекцию меша по глубине, НО я проекцию не делаю, хотя в принципе может зря я и не делаю)))
Я передаю точку проекции в фрагмент, а там считаю производные.
В результате у меня квад остается квадом на экране, без лишних смещений и скручиваний плоскости.
А фрагментный все равно использует растеризированное значение из varying.
В финальном pass'е я просто беру позицию пикселя в мире, перевожу в координаты ортокамеры и из текстуры беру пиксель моей каустики.
Качество с глубиной не изменно.
Но, качество становится хуже(возможно не верный термин) с разницей угла между нормалью в текущем пикселе и направлением ортокамеры.
Т.е. на дно, где нормаль смотрит прямиком на плоскость воды каустика будет шикарной и в весь обьем.
А для ствола пальмы например, где практически весь ствол смотрит перпендикулярно, будет сходится в практически одну и туже точку в текстуре каустики, т.к. ствол меняется по Y, но по X, Z остается почти не изменным, что по большей и есть координатой пикселя в текстуре каустики.
В этом случае по столбу пальмы каустика пойдет более в виде линии (скрин прилагается)
IIIarp
> Орто камера, которая находится в центре меша воды и смотри на дно, по left,
> right, bottom, top по размеру меша.
Да, у меня сделано так же, правда у меня океан и я беру меш произвольного размера.
IIIarp
> Один pass на захват карты глубины дна, второй этой же камерой на проекцию меша
> по глубине, НО я проекцию не делаю, хотя в принципе может зря я и не делаю)))
> Я передаю точку проекции в фрагмент, а там считаю производные.
Тут я меняю силу xz смещение меша в зависимости от глубины, и потом считаю производные.
float oldArea = length(ddx(i.oldPos.xyz)) * length(ddy(i.oldPos.xyz)); float newArea = length(ddx(i.newPos.xyz)) * length(ddy(i.newPos.xyz)); float color = oldArea / newArea * 0.1;
IIIarp
> В результате у меня квад остается квадом на экране, без лишних смещений и
> скручиваний плоскости.
> А фрагментный все равно использует растеризированное значение из varying.
Но если сам меш воды имеет огромные смещения (как у океанских волн), то они всё равно будут ?
IIIarp
> В финальном pass'е я просто беру позицию пикселя в мире, перевожу в координаты
> ортокамеры и из текстуры беру пиксель моей каустики.
Именно от этого момента я и хочу избавиться. У меня океан, а значит и текстура ортокамеры должна быть огромной, что бы охватить огромную дистанцию. Что бы покрыть хотя бы 100 метров дистанции воды, мне надо считать 4 каскада с текстурой 1024x1024. А если смотреть на океан не под водой, то дистанция каустики должна быть сотни метров.
Наглядно. Вот каустика с дистанцией 100 метров, хотя этого уже не хватает.
А вот как видно качество с 4 каскадами по 1024 и 256 пикселей на каскад.
IIIarp
> Но, качество становится хуже(возможно не верный термин) с разницей угла между
> нормалью в текущем пикселе и направлением ортокамеры.
> Т.е. на дно, где нормаль смотрит прямиком на плоскость воды каустика будет
> шикарной и в весь обьем.
> А для ствола пальмы например, где практически весь ствол смотрит
> перпендикулярно, будет сходится в практически одну и туже точку в текстуре
> каустики, т.к. ствол меняется по Y, но по X, Z остается почти не изменным, что
> по большей и есть координатой пикселя в текстуре каустики.
> В этом случае по столбу пальмы каустика пойдет более в виде линии (скрин
> прилагается)
Как раз таки это так и должно быть. Если представить луч лазера и светить им со стороны солнца, то луч будет размазываться по пальме в виде огромной полосы.
Как тут:
Kripto289
> Но если сам меш воды имеет огромные смещения (как у океанских волн), то они всё
> равно будут ?
В моем случае все немного проще, у меня у волн нет смещений по XZ, волна и так со временем двигается по XZ, а вот смещение по Y для ортокамеры никакого значения не несет.
Теоретически, если разбить океан на каскады с реальной геометрией, то на стыках каскадов из-за проекции/смещения плоскости для каустики, сама каустика на стыках может перекрыватся соседями и будет ее переизбыток.
Я об этом задумался на этапе планирования задачи, правда не пойми зачем, если у меня всего стаканчик отрендерить нужно, по этому пошел путем прямой проекции с верху в низ, таким путем.
Плюс, моя проблема была в том, что мне нужно было минимальными усилиями отрендерить каустику во внутреннюю часть стакана, а реальная геометрия при проецировании выходила за его пределы или выперала из самых неожиданных мест.
Плюс, т.к. стакан должен в продакшене работать на мобилках в AR, то я много где качество подрезал и методы решения некоторых задач, это так-же повлияло на выбранный мной метод каустики.
По этому я не претендую на вручение премии за идеальное решение в плане качества/правильности каустики :)
Но, что могу сказать на счет ваших затей, каустику в итоге без проекции не построить правильным образом.
Самым безпорядочно хитрым способом будет генерить ее в 1 текстурку и просто мапить по всему оканскому дну))
Но эт не честно, но какой никакой эффект будет.
В остальном без проекций HD меша судя по всему никак(это чисто мое мнение).
Еще, что-бы я попробовал, использовать то, что есть у вас сейчас, только более хитрым способом.
Уменьшать разрешение сетки на отдалении от плоскости воды, что-то по типу octree.
Тогда получатся своеобразные LOD'ы в каустике да и для самой плоскоти океана на дальних расстояниях.
Ведь все равно на дальних расстояниях вся размерность воды и каустики не поместится в доступные пиксели экрана, и разницы не будет от HD и на производительности сэкономите.
В таком случае, на дальних лодах, тексутрка 128x128 уже будет идеальная, а на самых дальних каскадах 32х32, ну вы поняли :)