Я правильно понимаю что ты усекаешь фрустум и хочешь усечённый привести к стандартному фрустуму с квадратным основанием пирамиды?
GLoom
Если я скажу, что усекаю фрустум, то это будет не совсем правильно и вызовет путанницу.
Правильнее будет сказать - я строю фрустум по стенам, которые попадают во фрустум камеры.
GLoom
> хочешь усечённый привести к стандартному фрустуму с квадратным основанием
> пирамиды?
Да, но я не уверен, что он будет квадратным, параллелограмм в основании тоже бывает, основная цель - построить фрустум из 4 плоскостей, левая и правая плоскости всегда имеют по Z = 0 и с ними можно работать как с 2D и найти максимально возможный угол охвата видимых стен легко (пример с суммированием фрустума 1 и 2). Посути я ищу способ сделать тоже самое для верхней и нижней плоскости - найти максимум максимальный охват.
Максимальный охват видно после проецирования всех точек на экран, где можно выбрать нужные...ну и правда не знаю, можно ли найти такие точки в плоскости предметов а не в плоскости изображения на экране.
По идее проецирование в область экрана это просто умножение вектора на матрицу - даёт позицию в clip space. Ты хочешь избежать этого умножения или ты делаешь как то по другому?
Записал небольшое видео, может это немного поможет понять)))
Сначала я оставил только отрисовку двух плоскостей - левую и правую...по ним можно заметить, что они перпендикулярны полу, т.к. z = 0...потом я включил верхнюю и нижнюю плоскости для "рабочего" варианта.
Этот фрустум - это поле зрение портала, т.е. синий сектор будет определяться видимым только через этот фрустум.
GLoom
> Ты хочешь избежать этого умножения или ты делаешь как то по другому?
Да, хочу этого избежать, т.к. получается вопервых медленее, а во вторых, чтобы выполнить проверку необходимости увеличения фрустума, нужно проецировать все точки стен. А например расстояния от точки до камеры я уже знаю (при построении левой и правой плоскости)
Тем более при проецировании накладывается геморрой проверки и отсечения через near плоскость камеры, чтобы геометрию не выворачивало наизнанку
У меня сложилось мнение: OpenGL порты подобных игр умирают при отрисовке всей карты из-за того, что структура рендера оставлена, как в оригинале: т.е. отсортировать, стены рисовать от ближних к дальним, спрайты - от дальнизх к ближним.
Это работало на софтрендере и на всяких вуду (вспоминаю свой Voodoo2 с ностальгией, сожалею, что пролюбил), но с точки зрения современных (2006+) видеокарт - ересь, в корне неверный порядок подачи команд.
На практике это прочуствовал, бета-тестя некоторые карты Extermination Day под Zandronum: в брутал думе феерическая разрушаемость, всё рвётся на килотоны уникальных спрайтов. В результате относительно небольшая карта с парой улиц и перекрёстков просажтвала Gtx1060 ниже 18 фпс когда эти улицы оказывались засраны ошмётками демонов, пальм, кустов, мусорных баков и подбитых танков.
Вероятность, что два спрайта в списке попадут в один текстурный атлас стремится к нулю, видеокарта проводит почти всё время кадра в состоянии простоя конвейеров в ожидании, когда дорисуется очередной крошечный кусочек и можно будет переключить текстуру.
Вывод: нормальный OpenGL порт должен сортировать спрайты по текстурным атласам а не расстоянию для камеры, а буде понадобится прозрачность - только OIT (честный либо же стохастический). Иначе эта проблема не решаема.
То же со стенами. Сначала - z-only prepass, без текстур, от ближних к дальним, потом отекстуренные стены рисуются, отсортированные по текстурным атласам.
Правда, порталы при этом превращаются в попаболь - НО у подобных игр (дюк, GZDoom) на это уже были ограничения типа "за зеркалом обязано быть пустое пространство, достаточное для вмещения всего, что отражается в зеркале", при несоблюдении - глюки.
Дополнительный вариант: твой движок бьёт карту на группы соприкасающихся секторов. Когда соприкосновения нет - другие группы, кроме той, в которой камера, тупо не рисуются. А если группы связаны порталами - пристёгиваешь одну к другой согласно порталу и рендеришь обе, как единое целое. Поскольку пересечься они не должны, опять же согласно тому требованию.
Я в своем рендере не сортирую стены вообще, это просто не нужно (за исключением полупрозрачных, но у меня с этим проблем нет и поэтому сейчас они меня не интересуют)
Cheb
> Дополнительный вариант: твой движок бьёт карту на группы соприкасающихся
> секторов. Когда соприкосновения нет - другие группы, кроме той, в которой
> камера, тупо не рисуются. А если группы связаны порталами - пристёгиваешь одну
> к другой согласно порталу и рендеришь обе, как единое целое. Поскольку
> пересечься они не должны, опять же согласно тому требованию.
Именно так это у меня и работает. А вот в момент пристегивания одного портала к другому можно разобрать 3 варианта построения верхней и нижней плоскостей:
1 - построить плоскости по левой стене, тем самым откусить часть правой
2 - построить плоскости по правой стене - откусить левую стену
3 - либо построить по крайним точкам после проецирования - единственно правильный результат, который охватывает обе видимые стены и соответственно правильное "видение" геометрии за порталом.
И даже по этой картинке вроде как ближайшие точки - это ближайшие точки к камере, но оказалось что нет
Уточню - портал в моем понимании это область видения сектора, поэтому на картинке не два портала а один портал, который ведет в сектор с белыми стенами, и этот портал образуют две красных стены
И ещё раз: все эти страдания по оптимальному отсечению - из-за неправильного использования видеокарты, пытаясь с современным оборудованием работать, как с оборудованием 1990-х. При правильном использовании всё решается пошлым брутфорсом, даже какой-нибудь Intel HD тебе всю карту отрисует, не напрягаясь и лениво ковыряя в зубах.
1. Стены, z-only prepass без текстур от ближних к дальним.
2. Стены, отсортированные по текстурам
3. Спрайты (жёсткая альфа), отсортированные по текстурам
4. Всякая полупрозрачная хрень, от дальних к ближним. По возможности, тоже сгруппированная по текстурам.
Непонимание принципов работы железа - это боль и фрустрация, знаю по себе, мой 3d шутер 1998 года тормозил на 386-м, и даже на 486-м, и только на пентиуме 266 пошёл нормально - всё из-за непонимания мною такой простой вещи, как пропускная способность памяти по текселям, отсутствие даже намёка на mip-mapping и зверски неоптимальные размеры спрайтов.
Ну и еще одно уточнение, мой алгоритм на данный момент не зависит от размера сцены, его скорость зависит только от количества попадаемых в видимость секторов.
Рассчитываются видимые секторы в цикле от сектора в котором находится камера, алгоритм проходит по всем стенам сектора, определяет красные стены, строит порталы, при необходимости эти порталы объединяет в один. Портал попадает в очередь на обработку и усекается предыдущим порталом. Далее наступает очередь добавленных в список порталов, берется один из них, он также заглядывает в соседние сектора, строит порталы и обрезает их собой. Порталы строятся до тех пор пока не останется ничего видимого, из чего можно было бы построить портал.
Вот так выглядит одна из сцен из камеры
А вот вид сверху, более яркие стены - видимые
Расчет видимости занял 0.06мс
Сейчас мой алгоритм работает на проекциях - я проецирую стену на экран, строю AABB - назвал это viewport. Далее если нужно объединить две стены в один портал, я просто беру максимальные и минимальные точки двух AABB и получаю один большой. Далее я таким образом проецирую каждую стену, строю AABB и проверяю, пересекается ли AABB стены с текущим viewportом (т.е. AABB красной стены), если пересекаются, тогда стена видимая. Это пока самый удачный и безглючный алгоритм, который работает довольно быстро, но он очень неточный, если смотреть вверх или вниз, AABB получаются сильно большими и это мешает дальнейшей обработке
Cheb
То что ты описаешь, разве не occlusion query называется? Я что-то сомневаюсь, что GL2.0 способен отрисовать всю карту и после этого рассказать CPU что он отрисовал, а что нет. Я бы с удовольствием бы попробовал этот способ, но он какой то нереальный. Слишком уж много придется "рассказывать" CPU
Cheb
> 2. Стены, отсортированные по текстурам
> 3. Спрайты (жёсткая альфа), отсортированные по текстурам
> 4. Всякая полупрозрачная хрень, от дальних к ближним. По возможности, тоже
> сгруппированная по текстурам.
Все так и делают, не? Никто не вызывает рендер для каждой текстуры/спрайта в процессе обхода BSP (в случае doom). Всё раскладывается по разным спискам, сортируется, и отрисовывается так как ты описал.
Ну вот я попробовал вывести всю карту (самую большую) без текстур, но каждая стена по-прежнему отдельный drawcall
158fps, как то не впечатляет, особенно если учитывать, что после этого нужно сделать еще тоже самое + синхронизация с CPU, чтобы сообщить ему, какие из этих стен нужно рисовать.
И вот та же самая карта с текстурами и алгоритмом видимости, но только чтобы алгоритм видимости работал, нужно находится в секторе.
Я по прежнему считаю, что обработку проводить нужно...видюха, если что RTX2060, разрешение 1920х1024 (это домашний компьютер, я на нем не прогаю))
Добавление:
Отрисовал всю карту за один вызов - 1900fps, ну тоже мало, мои 3700 мне нравятся больше (тем более с текстурами)
Я пробовал уровни quake рендерить в Urho3D. Из BSP восстанавливал полигоны чтоб были покрупнее, разрезал уровень на крупные блоки примерно одинакового размера. В Urho3D есть Occlusion culling на CPU. Он довольно эффективно отсекал невидимые части уровня при таком подходе.
Просто как пример альтернативы порталам.
GLoom
BSP я не осилю :) Да и все пишут что BSP - только для статической геометрии, тут уже нужно будет писать ИИ, который поймет - какие стены статические, а какие нет или находу перестраивать BSP? Вроде читал что думовые уровни обрабатываются до 5 минут, пока сохраняются из редактора
>но каждая стена по-прежнему отдельный drawcall
Я ещё тот диванный эксперт - но мнится мне, львиная доля уходит на то, чтобы драйвер из этого составил список команд.
Если видеокарта расчитана рисовать дохреналион треугольников в кадре, а у тебя проседает на смешном количестве (а ретро-карты - реально смешное количество) - значит ты что-то делаешь не так.
Сравни с майнкрафтом.
Майнкрафт (усечённый) летает даже на Raspberry Pi 2 - а там треугольников в кадре в кадре намного, намного больше.
И дальше - боль изысканий "а как правильно".
Подсказать не могу, я сделал только первые шаги в эту сторону и увяз в рефакторинге движка.
Навскидку - буферы всякоразные, в которые это всё запихивается и скармливается ГЛю за один дроколл (или несколько, если не лезет в один буфер).
>разве не occlusion query называется?
Нет, тупой брутфорс.
Видеокарта сама должна уметь быстро отбрасывать фрагменты, не проходящие z тест. Не вызывая фрагментный шейдер и не обращаясь к текстуре. Ты ей тупо сливаешь всё, но так, как ей удобно - и тогда справится.
P.S. В качестве примера: intel HD 3000 моего старого ноута. На коей:
- подтормаживала OpenArena (клон третьего квейка) - ибо создатели драйвера поддерживают устаревший АПИ по принципу "работает - и то ладно".
- нормально шёл Spintires: Mudrunner (с шейдерами попроще, вестимо, без dof и блескучести) https://youtu.be/NaIgnnj8J5Y?t=230
Мнится мне, "один дроколл на полигон" - это типичный "ЧЯДНТ".
Тема в архиве.