Войти
ПрограммированиеФорум2D графика и изометрия

Порядок рендеринга слоев в 2д

Страницы: 1 2 Следующая »
#0
17:03, 7 мар. 2019

Игра 2D вид сбоку (аля террария), OpenGL 3.3.
Чет я так и не разобрался до конца с некоторыми моментами касающимися рендеринга.

Картинка рисуется в несколько слоев:
1. Задний фон.
2. Объекты неба (солнышко, луна, звезды, птички, тучки).
3. Карта и ее объекты.
4. Персонажи.
5. [Текст] Имена персонажей и другой текст (например нанесенный урон противнику).
6. Гуй (интерфейс, в том числе инвентарь). Может полностью или частично закрывать персонажей и все, что находится на предыдущих слоях.
7. [Текст] Надписи для интерфейса (например количество вещей в ячейке инвентаря).
8. Объекты которые перемещаются мышкой в инвентаре.
9. [Текст] Все остальные надписи.

Вопрос:
Как видно, один только текст надо рисовать в 3х разных слоях. Мне что каждый раз переключать текстуры и шейдер, что бы нарисовать текст в каждом последующем слое? Можно ли как-то весь текст за один вызов рисовать?

Как я понимаю, просто включив тест глубины и выводить текст по разным Z координатам не получится, потому что прозрачные объекты надо рисовать от дальней точки по направлению к зрителю...

Я может сильно загоняюсь из-за вещей над которыми и думать не стоит, но это уже чисто спортивный интерес. Короче, помогите, кто чем может)


#1
12:47, 11 мар. 2019

Dimm Smile
>Как видно, один только текст надо рисовать в 3х разных слоях. Мне что каждый раз переключать текстуры и шейдер, что бы нарисовать текст в каждом последующем слое? Можно ли как-то весь текст за один вызов рисовать?
3 переключения шейдеров для тебя слишком много, или в чем проблема?

#2
17:53, 11 мар. 2019

nes
> 3 переключения шейдеров для тебя слишком много, или в чем проблема?
Это только шейдер для вывода текста 3 раза переключаться будет. А есть еще шейдер для неосвещенных спрайтов, шейдер попиксельного освещения и т.д. У каждого свой набор текстур и свой набор объектов которые он рисует. Причем не всегда можно упаковывать все в текстурные атласы.
Получается на отрисовку простой двухмерной сцены, уже порядка нескольких десятков переключений состояния (текстуры, шейдеры, буферы) плюс еще вызовы на отрисовку ну и постоянное перезаполнение буферов для отрисовки нестатических объектов.
Но как я говорю, это больше спортивный интерес, чем ориентир на low-end железо. Просто интересно, может есть какие-то техники, где сложная сцена рисуется за пару вызовов :D

Вообще есть какая-то статистика или зависимость, какое железо сколько среднестатических (в вакууме) переключений состояния, заполнения буферов и вызовов на отрисовку тянет?

#3
0:12, 12 мар. 2019

Dimm Smile
> Как я понимаю, просто включив тест глубины и выводить текст по разным Z
> координатам не получится, потому что прозрачные объекты надо рисовать от
> дальней точки по направлению к зрителю...

Должно получаться.
Включение теста глубины даст очень хорошую прибавку к скорости.

Сначала рисуем непрозрачные объекты.
(начиная от тех что поближе (гуй > текст > персонажи) до тех что подальше (птички > звёзды > небо))

Потом рисуем объекты, у которых есть полу-прозрачность.
(но порядок нужен обратный)


И, если не ошибаюсь, спрайты с прозрачным фоном можно рисовать вместе с непрозрачными.
(им ведь не нужно смешивание)

#4
8:10, 12 мар. 2019

Dimm Smile
Какие пиксельные освещения, сперва рисуешь сцену, это отдельная сущность с ее слоями,
потом рисуешь гую.
Гуйне незачем знать о каких-то освещениях, имхо.

#5
15:50, 12 мар. 2019

Dimm Smile
> Можно ли как-то весь текст за один вызов рисовать?
нет, нельзя.

Как я понимаю, просто включив тест глубины и выводить текст по разным Z координатам не получится, потому что прозрачные объекты надо рисовать от дальней точки по направлению к зрителю...

да, не получится.

Dimm Smile
> Я может сильно загоняюсь из-за вещей над которыми и думать не стоит, но это уже
> чисто спортивный интерес. Короче, помогите, кто чем может)
ну, чисто технически, ты можешь запихать элементы UI и символы текста в один атлас, и рисовать все одним шейдером за один вызов. Шейдер понятное дело придется усложнить, чтобы он понимал как рисовать каждый пиксель - как спрайт, или там как текст с SDF.
Будет ли это работать за один вызов? - Да.
Будет ли это быстрее - Не факт.
Та схема - которую ты привел - идеальна по скорости, удобству написания и удобству подготовки контента. Если ты хочешь ее испортить ради спортивного интереса - то чтож, хозяин-барин.

>Вообще есть какая-то статистика или зависимость, какое железо сколько среднестатических (в вакууме) переключений состояния, заполнения буферов и вызовов на отрисовку тянет?
для ПК:
Изображение

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

#6
16:33, 12 мар. 2019

Касательно текста - как правило на элементах интерфейса он почти всегда статичен и меняется не так часто,
т.о. можно запечь его заранее в текстуры каким-нибудь freetype-ом.

#7
16:56, 12 мар. 2019

ELena_Shloemovich
> Сначала рисуем непрозрачные объекты.
> (начиная от тех что поближе (гуй > текст > персонажи) до тех что подальше
> (птички > звёзды > небо))
>
> Потом рисуем объекты, у которых есть полу-прозрачность.
> (но порядок нужен обратный)
Не плохая идея, спасибо, в принципе попробовать можно, если уж совсем захочется поспортивничать)

nes
> Какие пиксельные освещения, сперва рисуешь сцену, это отдельная сущность с ее
> слоями,
> потом рисуешь гую.
> Гуйне незачем знать о каких-то освещениях, имхо.
Это все понятно и само собой разумеется))

nes
> Касательно текста - как правило на элементах интерфейса он почти всегда
> статичен и меняется не так часто,
Кстати ведь правда. А если и меняется этот текст, то крайне редко. Даже тот же показатель количества предметов в ячейке. Его можно просто в редкоизменяемый буфер сгенерировать и пусть он там лежит. Правда это не отменяет того, что все равно для текста придется несколько раз переключать шейдер...

HolyDel
> ну, чисто технически, ты можешь запихать элементы UI и символы текста в один
> атлас, и рисовать все одним шейдером за один вызов. Шейдер понятное дело
> придется усложнить, чтобы он понимал как рисовать каждый пиксель - как спрайт,
> или там как текст с SDF.
> Будет ли это работать за один вызов? - Да.
> Будет ли это быстрее - Не факт.
> Та схема - которую ты привел - идеальна по скорости, удобству написания и
> удобству подготовки контента. Если ты хочешь ее испортить ради спортивного
> интереса - то чтож, хозяин-барин.
Вот после этого ответа у меня как камень с плеч упал. На счет удобства схема реально очень удобная для использования. Ну и если ты говоришь, что по скорости тоже норм, то вообще хорошо))

Все же не стоит этот спортивный интерес затраченных на него усилий.
А за картинку отдельное спасибо.

#8
19:49, 12 мар. 2019

Dimm Smile
>Правда это не отменяет того, что все равно для текста придется несколько раз переключать шейдер...
Откуда тут несколько раз?
Переключать придется только текстуры, а это копейки для рендерера.
Псевдокод:

function DrawUI()
{
  // Установили шейдер
  SetCurrentRenderer(UIRenderer);

  // добавляем батчи на отрисовку
  foreach (UIElement e in allUIElements)
  {
    UIRenderer.AddBatch(e.texture, e.bounds);
  }

  // Рисуем все батчи
  UIRenderer.RasterizeBatches();
}
#9
20:13, 12 мар. 2019

nes
> Откуда тут несколько раз?
> Переключать придется только текстуры, а это копейки для рендерера.
Блин, а ведь и правда! Если все ещё грамотно разложить по буферам и без надобности не обновлять, то будут вообще огонь!

#10
8:17, 14 мар. 2019

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

Но у меня вопрос - кто то пользуется техникой, когда к шейдеру подключается несколько текстур (glActiveTexture(...))? Например в нулевой слот гуй, в первый слот предметы инвентаря, во второй слот текстуру шрифта и т.д. Вроде минимум на любом железе должно до 16 таких текстур поддерживаться. Кто-нибудь вкурсе, так делают вообще?

#11
9:41, 14 мар. 2019

Dimm Smile
>А вот везде говорят - типа собирайте текстуры в атласы, так можно будет реже переключать состояния. Это все понятно.
Можно заморочиться, но имхо овчинка не стоит выделки.
Ну разве что для шрифтов.

>Но у меня вопрос - кто то пользуется техникой, когда к шейдеру подключается несколько текстур (glActiveTexture(...))?
Врятли кто-то делает мегашейдер на все возможные случаи и запекает в текстурных слоях принципиально разные в плане логики работы сущности.
Но никто и не запрещает так делать.

#12
10:12, 14 мар. 2019

nes
> Но никто и не запрещает так делать.
Я просто попробовал так и мне понравилось.
Например взять тот же GUI. Я к шейдеру сразу подключаю и текстуру самого гуя, и текстуру с отображением предметов для инвентаря, и текстуру с шрифтом. И это мне позволяет все данные для отрисовки гуя хранить в одном буфере и рисовать весь гуй за 1 вызов. При этом буфер обновляется только тогда, когда что-то изменяется в инвентаре/интерфейсе, а не каждый кадр, как для динамических объектов, которые все время перемещаются (например персонажи).

Единственное пришлось прибегнуть к маленькой хитрости. Что бы шейдер мог понять, какие текстурные координаты для какой текстуры использовать, я просто для каждой текстуры задаю свое смещение для uv координат. Например для текстуры c индексом 1 добавляю для всех uv координат 1.0f. Для текстуры с индексом 2 добавляю 2.0f и т.д. И потом во фрагментном шейдере (кстати можно делать эту проверку в вершинном шейдере) просто смотрю, если uv-координаты >= 2.0, значит это текстура с индексом 2 и т.д.

Не знаю, на сколько красивым считается такой велосипед, вроде как ветвление в шейдерах не очень хорошо, но оно и не такое то страшное по сути. А в плане удобства, прям очень удобно)

#13
(Правка: 13:10) 13:09, 14 мар. 2019

Dimm Smile
> Не знаю, на сколько красивым считается такой велосипед
Ты сэкономил десяток батчей, но добавил по ветвлению на каждый пиксель. А возможно, и по дополнительному чтению из текстуры.
с высокой долей вероятности этот велосипед будет ехать медленнее, чем прошлый (но надо замерять). А красота - красота понятие субъективное.

я так понимаю у тебя что-то вроде такого:

vec4 color = 0;
int a = int(uv.x);
if(a == 0) color = texture(tex1,uv);
if(a == 1) color = texture(tex2,uv);
if(a == 2) color = texture(tex3,uv);
if(a == 3) color = texture(tex4,uv);
я не знаю как сейчас на мобильных GPU, но когда-то давно, это бы вылилось в 3 лишних чтения из текстуры.

Упаковывать все текстуры в атлас, или использовать texture array - мне понятно ( и то, не в твоем кейсе, когда смен шейдеров не наберется и сотню на кадр).
использовать multitexturing (glActiveTexture) для совмещения нескольких текстур в одном шейдере, когда каждый пиксель закрашивается только одной из них (а читаться данные, с большой долей вероятности будут из всех) - это как то странно и стремно.

#14
13:26, 14 мар. 2019

HolyDel
> Упаковывать все текстуры в атлас, или использовать texture array - мне понятно
> ( и то, не в твоем кейсе, когда смен шейдеров не наберется и сотню на кадр).
> использовать multitexturing (glActiveTexture) для совмещения нескольких текстур
> в одном шейдере, когда каждый пиксель закрашивается только одной из них (а
> читаться данные, с большой долей вероятности будут из всех) - это как то
> странно и стремно.
Интересная информация, спасибо, будет теперь над чем поразмыслить.

Я так понимаю 100 смен шейдеров за кадр это нормальная практика? Пользователи со слабыми карточками на такой множественной смене шейдеров не отвалятся из-за низкого фпс?

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