Всем доброго времени суток.
После реализации DS пытаюсь разобраться с HBAO.
Результат получается какой-то совсем некорректный.
В первой версии делаю без шума и без затухания.
Буду благодарен если кто посмотрит и подскажет где я ошибся.
Текущий результат выглядит вот так:
Заранее благодарю.
KaronatoR
базовый HBAO примерно так и выглядит.
Suslik
Вопрос немного не по теме. Как ты оптимизировал lsao? Я заметил, что от размера стека очень сильно зависит скорость. При размере стека 4к выдаёт примерно 50мс, а при 1к - 20мс. Я пробовал заменить его на общий для всех ssbo, но скорость так и осталась на 20-30мс. Параметры такие же, как на превьюхе статьи. Там без всяких репроекций и интерливинга выдаёт 5мс.
АкронимЛета
> Вопрос немного не по теме. Как ты оптимизировал lsao? Я заметил, что от размера
> стека очень сильно зависит скорость. При размере стека 4к выдаёт примерно 50мс,
> а при 1к - 20мс. Я пробовал заменить его на общий для всех ssbo, но скорость
> так и осталась на 20-30мс. Параметры такие же, как на превьюхе статьи. Там без
> всяких репроекций и интерливинга выдаёт 5мс.
если ты написал свой lsao и хочешь обсудить, создай отдельную тему
Suslik
Привет, спасибо за ответ.
Не мне с тобой спорить, но всё же спрошу.
Я почитал всё что мог про HBAO на форуме и там говорится, что есть несколько простых способов проверить корректность алгоритма:
1. Прямая плоскость должна быть абсолютно белой.
Это у меня выполняется.
2. Не должно быть резких, ломаных переходов.
У меня в углу творится какая-то жесть:
3. Картинка очень яркая, а в советах, которые я нашел, говорится что в прямом углу значение должно быть 0.5 (или это я должен подобрать опытным путём?)
4. Что за мясо вокруг кубиков? Так точно должно быть?
У меня ощущение что я где-то налажал, но я этот шейдер уже наизусть знаю, да и писал стараясь понимать, никак не найду в чем же дело. Сначала думал, что дело в отсутствии затухания, но в доке нвидии утверждается что и без затухания результат должен быть приемлемым.
Если в конце шейдера усилить occlusion, возведя не во вторую, а в седьмую степень, то получится вот такое:
KaronatoR
> 1. Прямая плоскость должна быть абсолютно белой.
> Это у меня выполняется.
учти, что плоскость должна быть абсолютно белой в смысле яркость = 1.0 (не больше и не меньше).
KaronatoR
> Не должно быть резких, ломаных переходов.
> У меня в углу творится какая-то жесть:
переходы вполне могут быть. например, если у тебя есть маленькое тонкое отверстие в геометрии, в нём будет околонулевая освещённость. переходы освещённости могут быть и на гранях, потому что хоть падающие лучи в них и меняются плавно, косинус при них меняется скачкообразно, поэтому на изломах может быть излом результирующей освещённости.
KaronatoR
> 3. Картинка очень яркая, а в советах, которые я нашел, говорится что в прямом
> углу значение должно быть 0.5 (или это я должен подобрать опытным путём?)
прямой двугранный угол должен иметь освещённость ровно 0.5, потому что в него попадают лучи из ровно половины полупространства. аналогично в углу куба освещённость должна быть равна в точности 0.25, так как туда попадает половина света двугранного угла.
> 4. Что за мясо вокруг кубиков? Так точно должно быть?
это не мясо, это false occlusion. на самом деле вокруг кубов горизонт должен проходить "под" ними, в скринспейсе об этом нет инфорации, поэтому значение горизонта переоценивается и получается слишком сильный окклюжен. отстой в том, что у этой проблемы нет идеального решения. есть много способов, но ни один из них не работает на 100% удовлетворительно всегда. я бы тебе рекомендовал почитать про GTAO (ground truth ao), пейпер был от близзард, кажется. это расширение HBAO на немного более общий случай с немного более правильным семплированием и они предоставляют похожий вариант разрешения false occlusion'а, к которому я в итоге пришёл.
> У меня ощущение что я где-то налажал
на самом деле основная проблема, которую я вижу у тебя — это просто мелкий радиус семплирования, поэтому AO выглядит очень локально. попробуй для верификации маршировать хотя бы через половину экрана. ясное дело, производительность HBAO при этом упадёт, но чтобы это посчитать за нормальное время, нужен уже LSAO, который реализуется на порядок сложнее.
я не могу сказать более конкретно, правильные у тебя синусы и арккосинусы, потому что не использую сам HBAO в чистом виде, он является промежуточным этапом между совсем фейковым crysis'овым SSAO и уже нормальным GTAO.
> Если в конце шейдера усилить occlusion, возведя не во вторую, а в седьмую степень, то получится вот такое:
так делать точно не надо
KaronatoR
> if (gamma > oldAngle) {
> float value = sin(gamma) - sin(oldAngle);
> occlusion += value;
> oldAngle = gamma;
> }
Заменяешь на oldAngle = max(gamma, oldAngle);
В конце первого цикла считаешь:
occlusion += sin(oldAngle);
KaronatoR
> occlusion = 1.0 - occlusion / float(directionsCount * stepsCount);
> occlusion = clamp(pow(occlusion, 2.2), 0.0, 1.0);
На:
occlusion = 1.0 - occlusion / float(directionsCount);
Огромное спасибо за ответ!
1. Про яркость 1.0 понял, сейчас в шейдере вставлю проверку и посмотрю что получится.
2. Ты абсолютно прав, уверен что дело в этом. Мой кубик это 5 отдельных плоскостей, вполне вероятно что между ними может быть микрощель.
3. Вот тут у меня беда. По идее, меняя параметры должно меняться только качество алгоритма, верно же? А у меня меняется (сильно) яркость итогового результата.
Вот пример:
const float radiusSS = 512.0 / 1024.0; float radiusWS = 1.0; const int directionsCount = 32; const int stepsCount = 16; occlusion = clamp(pow(occlusion, 2.0), 0.0, 1.0);
Результат:
Про остальное - понял, огромное спасибо за советы. Сейчас доведу до ума это (не могу оставить не разобравшись где ошибка) и буду двигаться в сторону GTAO.
KaronatoR
> Сейчас доведу до ума это (не могу оставить не разобравшись где ошибка) и буду
> двигаться в сторону GTAO.
это правильно
> Мой кубик это 5 отдельных плоскостей, вполне вероятно что между ними может быть микрощель.
микрощель сама может быть микротёмной, то она не может повлиять на освещённость объектов вокруг себя. вот если бы это была не щель, а торчащий треугольник, тогда да, мог бы. но это не твой случай.
> По идее, меняя параметры должно меняться только качество алгоритма, верно же?
от количества шагов и направлений яркость не должна меняться, это точно. скорее всего, баг как минимум здесь, где указал L (?):
> [b]АкронимЛета[/b]
> > occlusion = 1.0 - occlusion / float(directionsCount * stepsCount);
> > occlusion = clamp(pow(occlusion, 2.2), 0.0, 1.0);
> На:
> occlusion = 1.0 - occlusion / float(directionsCount);
ещё я бы тебе советовал не делать clamp(pow(occlusion, 2.2), 0.0, 1.0) при отладке, потому что неудобно верифицировать значения вроде 0.5, 0.25, итп. а когда отладишь, это делается через sRGB-рендертаргет, а не вручную в степень возводить.
АкронимЛета
Ох, сделал, но или сделал не то или я даже не знаю...
Код:
... if (gamma > oldAngle) { occlusion += sin(oldAngle); oldAngle = max(gamma, oldAngle); } } } occlusion = 1.0 - occlusion / float(directionsCount);
KaronatoR
Я выделил какие куски заменить, а не строчки из этих кусков)
KaronatoR
> occlusion += sin(oldAngle);
суммирование надо сделать один раз после цикла:
АкронимЛета
> В конце первого цикла считаешь:
> occlusion += sin(oldAngle);
этот момент у тебя на самом деле изначально правильный(вроде) был, просто синус можно один раз считать после цикла, а не на каждой итерации. математически это то же самое должно быть.
но вообще такие вещи отлаживать очень полезно учиться. я отлаживаю так:
- вместо цикла по куче направлений фиксирую одно направление
- вывожу цветом угол горизонта по этому направлению / (0.5 * pi) — там по контурам объектов эта величина должна быть ровно 1, на плоскостях, повёрнутых к камере, она должна быть ровно 0.
- как это работает правильно, убеждаюсь, что при использовании большого количества шагов по лучу результат становится только точнее
- перевожу угол горизонта в освещённость (через 1 - sin(angle))
- от одного луча перехожу к многим
- profit
Учёл все советы, написал вот так:
... if (gamma > oldAngle) { oldAngle = max(gamma, oldAngle); } } occlusion += sin(oldAngle); } occlusion = 1.0 - occlusion / float(directionsCount); return float4(occlusion, occlusion, occlusion, 1.0); }
Получилось вот так:
UPD: правку учесть не успел, сейчас сделаю.
KaronatoR
> Получилось вот так:
такое чувство, что ты за экраном семплишь (где глубина 0)? попробуй поотлаживай сам, как я описал выше
Тема в архиве.