Russian Qt Forum
Ноябрь 22, 2024, 19:24 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Рисование (общий случай)  (Прочитано 8979 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Октябрь 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;  // цвет фейса (не путать с цветом вертекса)
};
 
При рисовании указывается должны ли цвета фейсов использоваться или игнорироваться (рисовать всех одним цветом). Также модели относительно редко его имеют, хранится всегда но у всех одинаков. Схожая ситуация и с материалом, чаще всего один на всех. Но от того что оно редко - мне не легче, поддерживать обязан.

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

Спасибо
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #1 : Октябрь 29, 2016, 21:20 »

хм, а получится пробежаться по фейсам, выделить те, которые рисуются "одним" цветом, и отрисовать их как единое целое, а остальных "единоличников" уже по одному?
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Октябрь 30, 2016, 05:05 »

хм, а получится пробежаться по фейсам, выделить те, которые рисуются "одним" цветом, и отрисовать их как единое целое, а остальных "единоличников" уже по одному?
Как-то Вам удалось не влезть в этот OpenGL кал - матчасти совсем не знаете. Все API ф-ции рисования

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

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

Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Октябрь 30, 2016, 07:50 »

Так а что мешает для модели формировать несколько массивов вершин и рисовать ее в несколько этапов?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #4 : Октябрь 30, 2016, 14:27 »

Так а что мешает для модели формировать несколько массивов вершин и рисовать ее в несколько этапов?

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

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Октябрь 31, 2016, 07:57 »

По входным данным собираются временные массивы для отрисовки и отправляются на glDrawArrays.
Ну это вряд ли, наверное Вы имели ввиду glDrawElements, перемещать вертексы (а вместе с ними и нормали, цвета, UV(s)) себе дороже. По задаче индексы всегда есть, вот с ними и надо работать

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

Сообщений: 584


Просмотр профиля
« Ответ #6 : Октябрь 31, 2016, 08:27 »

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Октябрь 31, 2016, 09:44 »

...и отображаем их отдельным вызовами glMultiDrawElements.
Я обрадовался когда нашел этот вызов (по смыслу "само то"), но увы, во всяком случае "на моей карте" он не дает никакого "выйгрыша", т.е. скорость та же как вызвать glDrawElements много раз. Это меня удивило, т.к. "много" реальное - сотни, и даже тысячи, должно же быть быстрее хотя бы за счет сокращения числа вызовов. Перепроверил неск раз - нет, fps те же самые, у GPU свои законы  Плачущий

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

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

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

Сообщений: 584


Просмотр профиля
« Ответ #8 : Октябрь 31, 2016, 13:15 »

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Ноябрь 01, 2016, 04:53 »

Цитировать
Предварительно все примитивы преобразуем к виду GL_POINTS, GL_LINES или GL_TRIANGLES с помощью построения новых массивов индексов.
Эту работу можно переложить на GPU - реализовать переиндексацию налету в вершинном шейдере. У меня пока это только в планах.
Смелые у Вас планы, совершенно не вижу каким образом? Там ведь ни массивов, (ни кола ни двора) чем же это делать?
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #10 : Ноябрь 01, 2016, 09:33 »

Смелые у Вас планы, совершенно не вижу каким образом? Там ведь ни массивов, (ни кола ни двора) чем же это делать?

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Ноябрь 01, 2016, 16:28 »

Да, не вершинный, а геометрический шейдер нужно использовать.  Смеющийся
На днях (после фикса рабочих багов) тоже буду писать геометрический, пока изучаю матчасть. Ну данные придется в текстуру совать чтобы использовать texelFetch. Он даже атрибутов не видит, ну что-то можно подать из вертексного

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

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #12 : Ноябрь 01, 2016, 20:43 »

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

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

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.219 секунд. Запросов: 23.