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

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

Страниц: 1 2 3 [4]   Вниз
  Печать  
Автор Тема: Использование QOpenGLBuffer  (Прочитано 28928 раз)
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



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

Да, а куда подевались все эти любители итераторов и.т.п.?  Улыбающийся
Берегут свои нервы.
« Последнее редактирование: Ноябрь 29, 2016, 07:05 от Old » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


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

Тогда что будет на копировании? Сейчас я шарю всю структуру m_geometry (что вполне логично), переходить на "почленное" как-то не резон. И вообще, стоит ли буферами засорять основные структуры (CGeometry и др)? Буфера используются только на рисовании - вот пусть рисование их и достает как шаред пойнтеры.


Всё тоже и будет, в моем примере m_geometry как и буфера копируются целиком чуть ли не дефолтным оператором копирования.
Вся сложность в сеттере уровня детализации и "своих" данных (надо вместо кэша сгенерить свои копии).
Ну не хотите засорять CGeometry, вынесите всё из неё в отдельную структуру и храните больше указателей. Делов-то.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #47 : Ноябрь 30, 2016, 15:51 »

Ну не хотите засорять CGeometry, вынесите всё из неё в отдельную структуру и храните больше указателей. Делов-то.
Если (какая-то) мапа неизбежна то почему бы и не хранить прямо в ней, зачем так щедро заводить новые члены? Вообще кто он такой этот буфер (зависимая козявка) чтобы стоять в одном ряду с капитальными данными? А так членов больше - ясности меньше, напр
Код:
  // если m_has_own_data == false то шарим все буффера из мапы m_buffers_cache
  // если m_has_own_data == true то храним два своих уникальных буфера, остальные шарим
  Buffers m_buffers;
Ну хорошо, допустим m_has_own_data стал false. Ладно, лезу в мапу m_buffers_cache, там weak на Buffers вроде живой. Но можно ли верить его 2 первым буферам, может их и не было? Или наоборот m_has_own_data стал true. Ну просчитал деталировку (про StencilTable пока и не заикаюсь) создал буфера в m_buffers. Так ведь поместить его в общую мапу как weak значение не могу, первые 2 буфера личные.

Думается неверен сам подход, мол, заведем вумный уазатель(и) - и он сам нам все сделает в лучшем виде. Как только расклад чуть сложнее (как в данном случае)  эта вумность быстро заканчивается.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #48 : Ноябрь 30, 2016, 18:17 »

Причем тут вообще умные указатели?
Цитировать
Но можно ли верить его 2 первым буферам, может их и не было?
Как напишите, так и будет. Хотите отложенную инициализацию - ок, создаем при первом обращении. Не хотим - создает когда записываем исходные данные.

Код:
Так ведь поместить его в общую мапу как weak значение не могу, первые 2 буфера личные.
Можете, я разрешаю. Нет серьезно, просто записываем в мапу а остальные 2 буффера отложенно инициализируем когда понадобятся. Ну только надо класть не наш Buffers, а его копию.

Или у вас при виде умных указателей отключается мозг и вы сразу забываете, что можно делать явный clone разделенного объекта?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #49 : Декабрь 01, 2016, 08:20 »

Можете, я разрешаю. Нет серьезно, просто записываем в мапу а остальные 2 буффера отложенно инициализируем когда понадобятся. Ну только надо класть не наш Buffers, а его копию.
Не понял. Вы писали
1) ну храните в мапе не структуру а weak_pointer на неё. В основной структуре будет шаред + 2 буфера придётся вынести отдельно.
Приведите структуру данных, трудно что-либо обсуждать имея ввиду это изменение. Вероятно говорим о разных вещах.

Заметим что все уже стало как-то безумно сложно, я плохо представляю что надо делать при том или ином действии юзера - а ведь в задачке ничего сложного нет, буфер - один из самых популярных/ходовых приемов. Что-то не так
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #50 : Декабрь 01, 2016, 13:06 »

Цитировать
Заметим что все уже стало как-то безумно сложно, я плохо представляю что надо делать при том или ином действии юзера - а ведь в задачке ничего сложного нет, буфер - один из самых популярных/ходовых приемов. Что-то не так

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

Цитировать
Приведите структуру данных, трудно что-либо обсуждать имея ввиду это изменение. Вероятно говорим о разных вещах.

Код:
typedef QVector<QVector3D> TVerArray;  
typedef QVector<int> TIndArray;

struct Buffers
{
    QSharedPointer<QOpenGLBuffer> m_vertex_buffer;
    QSharedPointer<QOpenGLBuffer> m_color_buffer;
  // итд
};

enum class BufferTypes {
     VertexBuffer = 0x1;
     ColorBuffer = 0x2,
     AllBufers = 0xff
};

struct CRenderObject {
...
// данные рисования, могут шариться любым кол-вом CRenderObject
    QSharedPointer<CGeometry> m_geometry;
 
// уровень деталировки, 0 = исходная геометрия
    int m_detailLevel;       
 
// Если к объекту применены нелинейные преобразования
// то его "личные" вертексы и нормали должны использоваться
// (вместо тех же данных в m_geomretry)
     bool m_has_own_data;
    TVerArray m_vertex, m_normal;

    QSharedPointer<Buffers> m_buffers;

    QSharedPointer<Buffers> buffers() // можно и ссылку
    {
         if (!m_buffers) {
             if (!m_has_own_data) { // вместо булки можно заюзаьт пару Optional<TVerArray> для массивов вершин и нормалей (ходят они парой или нет, яхз)
                  // берем шаредную копию
                  m_buffers = m_geometry->buffers(m_detailLevel, BufferTypes::AllBuffers);
             } else {  // берем шаредную копию и модифицируем её своими буферами
                  // qMakeShared в Qt нет
                  // оптимизация - передаем флаги нужных буферов чтобы не создавать лишнего (можно не передавать, тогда будут лишние операции)
                  auto copy = qMakeShared<Buffers>(*m_geometry->buffers(m_detailLevel, BufferTypes::AllBuffers & BufferTypes::~VertexBuffer));
                  copy->m_vertex_buffer = createVertexBuffer(m_vertex);
                  m_buffers = copy;
             }
         }
         return m_buffers;
    }

    void setVerArray(TVerArray array)
    {
        m_buffers.reset(); // сбросили кешированное значение
        m_has_own_data = true;
        m_vertex = array;
    }
};

struct CGeometry {

     TVerArray m_vertex, m_normal, m_color, m_uv0, m_uv1;
     TIndArray m_indices, m_ver_per_face;
     QMap<int /*level*/, QWeakPointer<Buffers>> m_buffers_cache;

     QSharedPointer buffers(int level, BufferTypes types)
     {
          auto result = m_buffers_cache[level].lock();
          if (!result) {
              result = qMakeShared<Buffers>();
              m_buffers_cache[level] = result; // записали в кэш
          }

          // заполнили недостающие буфера
          if (types & BufferTypes::VertexBuffer)
             result->m_vertex_buffer = createVertexBuffer(m_vertex);
          ...

          return result;
     }

     void setVertex(TVerArray vertex)
     {
          m_vertex = vertex;
          for (auto item : m_buffers_cache) {
                if (item.second.m_vertex_buffer)
                    updateVertexBuffer(m_vertex, item.second.m_vertex_buffer); // обновляет буфер, не пересоздавая объект. Нужно чтобы те, кто хранит копии, обновили буфера
          }
     }
};

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

Сообщений: 2679


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


Просмотр профиля
« Ответ #51 : Декабрь 01, 2016, 18:14 »

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

Надо разделить действия на "модифицирующие" (редактирование модели) и "не модифицирующие" (перемещение, поворот и пр.).
В случае "редактирования" данные копировать, соответственно и буфера с ними.
В случае "перемещения" юзать шареный буфер.
Убили модель - уменьшили счетчик у буфера. Проверили, если счетчик стал 0, убили буфер.
Записан

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


Просмотр профиля
« Ответ #52 : Декабрь 02, 2016, 07:39 »

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

Код:
typedef QVector<QVector3D> TVerArray;  
typedef QVector<int> TIndArray;

struct Buffers
{
    QSharedPointer<QOpenGLBuffer> m_vertex_buffer;
    QSharedPointer<QOpenGLBuffer> m_color_buffer;
  // итд
};

enum class BufferTypes {
     VertexBuffer = 0x1;
     ColorBuffer = 0x2,
     AllBufers = 0xff
};

struct CRenderObject {
...
// данные рисования, могут шариться любым кол-вом CRenderObject
    QSharedPointer<CGeometry> m_geometry;
 
// уровень деталировки, 0 = исходная геометрия
    int m_detailLevel;      
 
// Если к объекту применены нелинейные преобразования
// то его "личные" вертексы и нормали должны использоваться
// (вместо тех же данных в m_geomretry)
     bool m_has_own_data;
    TVerArray m_vertex, m_normal;

    QSharedPointer<Buffers> m_buffers;

    QSharedPointer<Buffers> buffers() // можно и ссылку
    {
         if (!m_buffers) {
             if (!m_has_own_data) { // вместо булки можно заюзаьт пару Optional<TVerArray> для массивов вершин и нормалей (ходят они парой или нет, яхз)
                  // берем шаредную копию
                  m_buffers = m_geometry->buffers(m_detailLevel, BufferTypes::AllBuffers);
             } else {  // берем шаредную копию и модифицируем её своими буферами
                  // qMakeShared в Qt нет
                  // оптимизация - передаем флаги нужных буферов чтобы не создавать лишнего (можно не передавать, тогда будут лишние операции)
                  auto copy = qMakeShared<Buffers>(*m_geometry->buffers(m_detailLevel, BufferTypes::AllBuffers & BufferTypes::~VertexBuffer));
                  copy->m_vertex_buffer = createVertexBuffer(m_vertex);
                  m_buffers = copy;
             }
         }
         return m_buffers;
    }
CRenderObject имеет шаред пойнтер на Buffers все члены которого тоже шаред пойнтеры. Трудновато понять кто кого шарит. Ну ладно, может "так надо", попробуем вникнуть, если где ошибся - поправляйте

Думаю метод buffers() вызывается рисованием - нормально. Но тогда чего мы держим его как член класса (типа "бери") если получаем (весьма) активным геттером? Ладно, это вкусовщина, дальше. Значит если у объекта личных вертексов нет - пусть m_geometry разбирается, если надо - сделает деталировку и буфера заполнит. Хорошо, согласен. А если вертексы личные.. все равно зовем m_geometry и потом "дозаполняем"

Так это проходит только без деталировки (уровень 0). Вот тогда мы можем заливать исходный контейнер в буфер или нет, т.е. исходные данные для буферирования у нас есть. А операция "деталировка" получает на вход ВСЕ контейнеры и возвращает ВСЕ новые (которые надо куда-то девать). Так работает любой генератор модели меняющий топологию. См картинку первого поста - число полигонов явно другое, ну значит и все остальное тоже.

Данный генератор имеет возможность "досчитать" вертексы и нормали, т.е. если расчет был произведен для какого-то уровня деталировки, то его можно относительно быстро повторить для того же уровня и той же топологии но с другими вертексами. Но тогда нужно создать развесистую структуру StencilTable в памяти, и ее тоже надо как-то шарить. Да, вот здесь действительно "потихоньку появляются дополнительные требования" - поэтому давайте пока без нее.

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

1) Само собой - копирование и удаление CRenderObject(s). 2 и более копий должны использовать одну копию буферов которая должна убиться если ее не юзает никто. Сюда же - если объект пере-создан полностью (изменилась топология) - то для него заводятся все новые буфера

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

3) Вертексы объекта изменились (если он может их менять). Если объект имеет деталировку, то она должна быть пересчитана, новые вертексы и нормали слиты в буфера которые используются только данным CRenderObject и никем больше. Остальные буфера по-прежнему шарятся. StencilTable пока не трогаем

Вот собсно и все, скромный список  Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #53 : Декабрь 02, 2016, 13:30 »

Кажется, у меня не поддерживается только 3)
Чтобы его реализовать, надо "детачить" CGeometry у CRenderObject в момент, когда заполняются массивы.
Записан
Страниц: 1 2 3 [4]   Вверх
  Печать  
 
Перейти в:  


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