Russian Qt Forum

Qt => OpenGL => Тема начата: Igors от Октябрь 29, 2016, 07:53



Название: Рисование (общий случай)
Отправлено: Igors от Октябрь 29, 2016, 07:53
Добрый день

В шейдеры и материал не лезем (полагаем что там все есть). Также считаем что все матрицы установили верно. И вот в конце-концов нужно "нарисовать" объект, что обычно сводится к вызову glDrawElements. И тут выясняется что это легко и просто только если мы делаем какие-то допущения, напр "а у меня модели только из тр-ков" и/или "одна модель - один материал" и.т.п. Но мне не повезло, должен отрабатывать все ситуации. Вот структуры данных (псевдокод)
Код
C++ (Qt)
struct Model {
QVector<QPoint3D> m_position;   // позиции вертексов
QVector<uint> m_indices;      // индексы вертексов
// еще данные вертесков (напр нормали, UV и др )
...                                        
QVector<Face> m_faces;   // полигоны (в общем случае фейсы)
};
 
И вот структура фейса
Код
C++ (Qt)
struct Face {
int m_count;   // число вертексов в этом фейсе (1, 2, 3 или 4)
int m_offset;  // смещение в контейнере m_indices
int m_material;  // индекс материала
uint color;  // цвет фейса (не путать с цветом вертекса)
};
 
При рисовании указывается должны ли цвета фейсов использоваться или игнорироваться (рисовать всех одним цветом). Также модели относительно редко его имеют, хранится всегда но у всех одинаков. Схожая ситуация и с материалом, чаще всего один на всех. Но от того что оно редко - мне не легче, поддерживать обязан.

Ну так как бум рисовать?

Спасибо


Название: Re: Рисование (общий случай)
Отправлено: Racheengel от Октябрь 29, 2016, 21:20
хм, а получится пробежаться по фейсам, выделить те, которые рисуются "одним" цветом, и отрисовать их как единое целое, а остальных "единоличников" уже по одному?


Название: Re: Рисование (общий случай)
Отправлено: Igors от Октябрь 30, 2016, 05:05
хм, а получится пробежаться по фейсам, выделить те, которые рисуются "одним" цветом, и отрисовать их как единое целое, а остальных "единоличников" уже по одному?
Как-то Вам удалось не влезть в этот OpenGL кал - матчасти совсем не знаете. Все API ф-ции рисования

- рисуют только примитивы одного типа (напр GL_LINE, GL_TRIANGLE и др.)
- требуют "линейных" данных (вектор или массив), поэтому нарисовать что-то "вразброс" не получится. Перестраивать порядок следования фейсов не имею права

Тюкать по одной фасетке можно (glBegin/glEnd) но это уже лет 10 deprecated и по скорости совсем кисло



Название: Re: Рисование (общий случай)
Отправлено: Old от Октябрь 30, 2016, 07:50
Так а что мешает для модели формировать несколько массивов вершин и рисовать ее в несколько этапов?


Название: Re: Рисование (общий случай)
Отправлено: Racheengel от Октябрь 30, 2016, 14:27
Так а что мешает для модели формировать несколько массивов вершин и рисовать ее в несколько этапов?

Собственно +1. У нас тоже подобное решение используется.
По входным данным собираются временные массивы для отрисовки и отправляются на glDrawArrays.


Название: Re: Рисование (общий случай)
Отправлено: Igors от Октябрь 31, 2016, 07:57
По входным данным собираются временные массивы для отрисовки и отправляются на glDrawArrays.
Ну это вряд ли, наверное Вы имели ввиду glDrawElements, перемещать вертексы (а вместе с ними и нормали, цвета, UV(s)) себе дороже. По задаче индексы всегда есть, вот с ними и надо работать

Напр бросается в глаза такой способ: берем фейс за фейсом и смотрим принадлежит ли он той же пачке что и предыдущий (ключ = материал + число вертексов + цвет фейса). Как только ключ не совпал - рисуем все пройденные фейсы одним вызовом и начинаем накапливать следующую "пачку". Сопливое конечно но все же решение, уже неплохо. Что есть получше?


Название: Re: Рисование (общий случай)
Отправлено: ssoft от Октябрь 31, 2016, 08:27
Мы группируем все элементы со схожими свойствами и отображаем их отдельным вызовами glMultiDrawElements. Предварительно все примитивы преобразуем к виду GL_POINTS, GL_LINES или GL_TRIANGLES с помощью построения новых массивов индексов. Всякого рода смешения с учетом z порядка приходится делать за счет нескольких циклов отображения (см. Ordered independent transparency алгоритмы). Обычно картинка формируется не более чем за ~10 вызовов glMultiDrawElements.

Есть еще более быстрый способ отображения, в котором можно изменять практически любые свойства в процессе единственного вызова NVIDIA Command list, но соответственно работает только для NVIDIA.


Название: Re: Рисование (общий случай)
Отправлено: Igors от Октябрь 31, 2016, 09:44
...и отображаем их отдельным вызовами glMultiDrawElements.
Я обрадовался когда нашел этот вызов (по смыслу "само то"), но увы, во всяком случае "на моей карте" он не дает никакого "выйгрыша", т.е. скорость та же как вызвать glDrawElements много раз. Это меня удивило, т.к. "много" реальное - сотни, и даже тысячи, должно же быть быстрее хотя бы за счет сокращения числа вызовов. Перепроверил неск раз - нет, fps те же самые, у GPU свои законы  :'(

Предварительно все примитивы преобразуем к виду GL_POINTS, GL_LINES или GL_TRIANGLES с помощью построения новых массивов индексов.
Да, это работает, в том же самом случае что выше я получаю прирост не менее чем вдвое при перестройке индексов. Но это хорошо для "статики", когда можно скопировать индексы, оптимизировать их и засунуть в VBO. Но в "динамике" (новая геометрия на каждом фрейме) это заметный тормоз, операция-то совсем не дешевая. Что посоветуете?

Всякого рода смешения с учетом z порядка приходится делать за счет нескольких циклов отображения (см. Ordered independent transparency алгоритмы). Обычно картинка формируется не более чем за ~10 вызовов glMultiDrawElements.
Это тоже интересно, но за рамками данной темы

Уже не первый раз возникает подобная ситуация. Вот тот же glMultiDrawElements на моей карте ничего не дает. Но очень может быть что на картах поприличнее очень даже дает. Можно ли как-то узнать это в runtime? Как минимум можно выполнить тест(ы) - но это довольно много писать. Есть ли еще возможности как-то прощупать эту гниду GPU?  Спасибо


Название: Re: Рисование (общий случай)
Отправлено: ssoft от Октябрь 31, 2016, 13:15
По сути glMultiDrawElements это тот же самый цикл glDrawElements только внутри видеоадаптера. Весь смысл его - сокращение количество обращений к видеоадаптеру, каждое из которых может иметь свои накладные расходы. На практике разницы между glMultiDrawElements и циклом glDrawElements не замерял, но использую glMultiDrawElements по принципу, что не зря придуман, может проявит себя в определенных условиях, например, при конкурентном вызове из разных контекстов.

Цитировать
Предварительно все примитивы преобразуем к виду GL_POINTS, GL_LINES или GL_TRIANGLES с помощью построения новых массивов индексов.
Эту работу можно переложить на GPU - реализовать переиндексацию налету в вершинном шейдере. У меня пока это только в планах.


Название: Re: Рисование (общий случай)
Отправлено: Igors от Ноябрь 01, 2016, 04:53
Цитировать
Предварительно все примитивы преобразуем к виду GL_POINTS, GL_LINES или GL_TRIANGLES с помощью построения новых массивов индексов.
Эту работу можно переложить на GPU - реализовать переиндексацию налету в вершинном шейдере. У меня пока это только в планах.
Смелые у Вас планы, совершенно не вижу каким образом? Там ведь ни массивов, (ни кола ни двора) чем же это делать?


Название: Re: Рисование (общий случай)
Отправлено: ssoft от Ноябрь 01, 2016, 09:33
Смелые у Вас планы, совершенно не вижу каким образом? Там ведь ни массивов, (ни кола ни двора) чем же это делать?

Да, не вершинный, а геометрический шейдер нужно использовать.  ;D

Цитировать
Геометрический шейдер - шейдер, способный обработать не только одну вершину, но и целый примитив. Он может либо отбросить (от обработки) примитивы, либо создать новые, то есть геометрический шейдер способен генерировать примитивы. А также способен изменять тип входных примитивов (геометрический шейдер полностью вошел в OpenGL в версии 3.2).


Название: Re: Рисование (общий случай)
Отправлено: Igors от Ноябрь 01, 2016, 16:28
Да, не вершинный, а геометрический шейдер нужно использовать.  ;D
На днях (после фикса рабочих багов) тоже буду писать геометрический, пока изучаю матчасть. Ну данные придется в текстуру совать чтобы использовать texelFetch. Он даже атрибутов не видит, ну что-то можно подать из вертексного

[off]Вообще конечно термины у них - весь ппц! Геометрический... шейдер. Во блин, а я думал что шейдинг - это вычисление цвета (суб)пикселя, причем тут геометрия? А это странное слово "вершинный" (если не сказать больше). Ну в 3D семье не без урода... 
[/off]


Название: Re: Рисование (общий случай)
Отправлено: Racheengel от Ноябрь 01, 2016, 20:43
По сути glMultiDrawElements это тот же самый цикл glDrawElements только внутри видеоадаптера. Весь смысл его - сокращение количество обращений к видеоадаптеру, каждое из которых может иметь свои накладные расходы. На практике разницы между glMultiDrawElements и циклом glDrawElements не замерял, но использую glMultiDrawElements по принципу, что не зря придуман, может проявит себя в определенных условиях, например, при конкурентном вызове из разных контекстов.

Мы как-то меряли. Разницы никакой не было. По сути задача у нас была похожая - "собрать" из множества входных данных серии треугольников и отрендерить их минимальным кол-вом вызовов. Но узкое место был не рендеринг, а собственно "сбор" массивов для передачи их на карту, плюс расчет нормалей и все такое. Вот там пришлось поизвращаться. А отрисовка сама по себе - довольно быстрая.