Mirrel
> И насколько освободит графическую составляющую? )))
Есть ручной батчинг, по нему есть тесты на встроенной графике i5 11400.
Разрешение full hd
Карта 100x100 тайлов
Каждый тайл рисуется 2-мя треугольниками
Просто тупое рисование 80 fps
C батчингом 500 fps
Данный функционал я уберу под капот. И добавлю в API такое понятие как слои.
Разработчик будет вызывать draw а уже под капотом идёт объединение в батчи. Как осилю.
Сделаю батчинг текстур (когда идёт объединение текстур в одну)
Есть ПК pentium 4 1500 mhz и Geforce 6600 GT, интересно какой на нём fps. В любом случае это все равно жир. Надо бы потестировать на более слабом, намного интересней.
Имбирная Ведьмочка
> Можешь ещё поизучать материалы по кейворду "spatial hashing", оно как раз про
> это.
Ок. Уже нашел сатью, осталось найти время:)
Alprog
> Ты не понял. Ты хранишь тайлики не общим списком, а двумерным массивом.
> Тогда ты всегда знаешь, какой кусок массива у тебя попадает в камеру и рисуешь
> только его (внутри каждой ячейки у тебя список спрайтов, принадлежащих этой
> ячейке в разных слоях).
В случае тайлов это то, что нужно. И не зависит от кол-ва тайлов, а только о кол-ве тайлов на экране.
JordanCpp
> Карта 100x100 тайлов
> Каждый тайл рисуется 2-мя треугольниками
20.000 треугольников это ни о чём вообще. Зашей спрайты в один атлас, содержащий все варианты. И сгенерируй один меш для всего поля (правильный спрайт для каждого тайла передашь текстурными координатами внутри атласа). Дальше рисуешь всё за 1 drawcall. Будет быстрее, чем попытки отсекать лишнее, но рисовать по частям.
> Geforce 6600 GT
А какой GAPI? В те времена всё упиралось в drawcall'ы, так что по идее мой совет релевантный.
Alprog
> 20.000 треугольников это ни о чём вообще.
Это 500 fps * 20.000 = 10 млн треугольников в секунду
Alprog
> Зашей спрайты в один атлас, содержащий все варианты. И сгенерируй один меш для
> всего поля (правильный спрайт для каждого тайла передашь текстурными
> координатами внутри атласа). Дальше рисуешь всё за 1 drawcall. Будет быстрее,
> чем попытки отсекать лишнее, но рисовать по частям.
Ручной батчер у меня так и работает. Использую одну текстуру, vertex тоже единым массивом правда это я тестил для OpenGL 1.2 рисую одним вызовом glDrawArrays.
Подерживается OpenGl 3.3 но до батчера на нём руки не дошли. Там данные можно вообще на видеокарте хранить и не тратить на пересылку.
Alprog
> А какой GAPI? В те времена всё упиралось в drawcall'ы, так что по идее мой
> совет релевантный.
OpenGL 1.2 во фреймворке, видеокарта поддерживает OpenGL 2.0
JordanCpp
> Это 500 fps * 20.000 = 10 млн треугольников в секунду
А что это за показатель такой "треугольники в секунду"? На что он влияет?
Ну и да, 500 кадров в секунду рендерить не имеет смысла.
Alprog
> А что это за показатель "треугольники в секунду"? На что он влияет.
По нему меряю производительность. Что бы понять есть прирост или нет.
Alprog
> Ну и да, 500 кадров в секунду рендерить не имеет смысла.
Это я знаю. Во фреймворке стоит в FpsLimiter по умолчанию 60 fps. Что бы не греть бессмысленно процессор.
JordanCpp
> рисую одним вызовом glDrawArrays
Жесть. Насколько я помню это immediate mode рисование с пересылкой буфера. Такое годится только для дебага. Для продакшн-кода нужно юзать VBO.
> Подерживается OpenGl 3.3
> Там данные можно вообще на видеокарте хранить и не тратить на пересылку.
Да по-моему VBO можно было создавать и в более ранних версиях. Перепроверь, это же базовая вещь.
Мой поинт в том, что ты один раз создаёшь буфер на 20.000 треугольников, один раз отправляешь его на видеокарту и больше ничего не пересоздаёшь и не отправляешь. А просто отдаёшь на отрисовку.
А если нужно динамически обновлять спрайты, то лучше передавать индексы спрайтов константным буфером. Но для этого нужно шейдер написать, а я уже не помню в какой там версии появился программируемый пайплайн.
У меня единый 2D API для OpenGL, DirectDraw и софтверный рендеринг. И к примеру когда сделаю полную поддержку OpenGL 3.0 не понятно мне как обновлять данные на видеокарте. Каждый раз пересылать данные дорого, это лучше оставить для старых OpenGL.
Каким то образом понимать, что изменилось и пересылать только измененные данные.
void Draw(Texture* image, const Math::Vec2u& pos); void Draw( Texture* image, const Math::Vec2u& pos, const Math::Vec2u& size); void Draw( Texture* image, const Math::Vec2u& dstPos, const Math::Vec2u& srcPos, const Math::Vec2u& srcSize); void Draw( Texture* image, const Math::Vec2u& dstPos, const Math::Vec2u& dstSize, const Math::Vec2u& srcPos, const Math::Vec2u& srcSize); void Draw( Surface* image, const Math::Vec2u& pos); void Draw( Surface* image, const Math::Vec2u& pos, const Math::Vec2u& size); void Draw( Surface* image, const Math::Vec2u& dstPos, const Math::Vec2u& srcPos, const Math::Vec2u& srcSize); void Draw( Surface* image, const Math::Vec2u& dstPos, const Math::Vec2u& dstSize, const Math::Vec2u& srcPos, const Math::Vec2u& srcSize);
Каждый раз, кадр рисуется с нуля. Нужно явно, как то улучшить его не привнося сложность и оставив под капотом реализации над старыми графическими API.
Поэтому и хотел добавить универсальную сцену, где наполнение данных происходит один раз, а далее updat'ы данной сцены, с пересылкой обновленных данных на видеокарту.
К примеру сейчас тайловая карта, каждый раз рисуется циклом.
render.Begin(); render.Color( Color( 0, 162, 232)); render.Clear( ); for ( size_t rows = 0; rows < mapSize.x; rows++) { for ( size_t cols = 0; cols < mapSize.y; cols++) { size_t x = cols * tileSize.x / 2; size_t y = rows * tileSize.y; Vec2u pt = isometric.CartesianToIsometric( Vec2u( x, y)); render.Draw( &image, Vec2u( start.x + pt.x + dx, start.y + pt.y + dy)); } } render.End( );
Alprog
> Жесть. Насколько я помню это immediate mode рисование с пересылкой буфера.
> Такое годится только для дебага. Для продакшн-кода нужно юзать VBO.
Или очень старых API к примеру OpenGL 1.2 у меня убер фича фреймворка это поддержка в том числе и старого железа начиная с Windows 95 и Debian 3. Я понимаю, что странно это читать в 2023, но таков путь. И фреймворк написан на С++ 98 для совместимости со старыми компиляторами.
JordanCpp
> но таков путь
А зачем? Какая-то форма ностальгии?
Alprog
> А зачем? Какая-то форма ностальгии?
Не совсем.
Конечно в общих чертах, идея конечно безумная. С другой стороны OpenGL 1.2 это 1000 строк кода, не так уж и много кода нужно, что бы фреймворк заработал на старых видеокартах. Для Windows 9x версий, это примерно строк 10. Не сказал бы, что это сверх затраты по поддержке.
И лччно мне нравится, оптимизировать проект нативно на старом железе. Сразу видно, где, что тормозит. А если он летает на Pentium 166, то будет работать на всём.
JordanCpp
> void Draw(Surface* image, const Math::Vec2u& dstPos, const Math::Vec2u&
> dstSize, const Math::Vec2u& srcPos, const Math::Vec2u& srcSize);
Вы не боитесь, что такое огромное число аргументов приведёт к падению производительности?
iw4nna.rock
> Вы не боитесь, что такое огромное число аргументов приведёт к падению
> производительности?
Не думал об этом. Есть мысли как улучшить?