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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Оптимизация отрисовки сцены  (Прочитано 10222 раз)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« : Август 17, 2011, 14:43 »

Народ, подскажите как грамотно оптимизировать скорость отрисовки сцены.
Имеется сцена, на которой порядка тысячи элементов, различной сложности, от примитивных кружков до довольно сложных полигонов, рисунки, виджеты (не много правда). Проблема в том, что:
-сцена будет отображаться на мониторах большого разрешения (даже на нескольких мониторах одновременно)
-на сцене по ходу перемещения мыши нужно будет рисовать стрелку от определенного места до текущей позиции курсора (реализовал через QGraphicsItem, в котором пересчитываю координаты точек и по ним рисую красивую стрелку-указатель)
-эта стрелка рисоваться должна поверх всех объектов, и поэтому когда курсор провожу через весь экран, затрагивается вся сцена
-многие элементы нужно обновлять (в зависимости от режима работы, от текущего состояния объекта).
Сейчас в моем view стоят такие флаги в конструкторе:
Код:
QEditorView::QEditorView(QWidget *parent) :
    QGraphicsView(parent)
{
    fproject = NULL;
    this->setUpdatesEnabled(false);
    ffieldColor = Qt::darkGray;
    frenderer = rdSoftware;
    fscene = new QEditorScene(this);
    setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing); //<<<
    setAlignment(Qt::AlignLeft | Qt::AlignTop);
    setScene(fscene);
    setSceneRect(0,0,1920,1080);
    setDragMode(QGraphicsView::RubberBandDrag);
    setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing); //<<<
    setContextMenuPolicy(Qt::DefaultContextMenu);
    fGlWidget = NULL;
    setViewportUpdateMode(QGraphicsView::FullViewportUpdate); //<<<!!!
    setCacheMode(QGraphicsView::CacheBackground);
    this->setUpdatesEnabled(true);
}
QGraphicsView::FullViewportUpdate - вызывает заметные тормоза, в то время когда остальные режимы оптимизации значительно быстрее работают, но к сожалению часто вызывают артефакты, например в событиях hover, нужно отрисовать в определенном месте итема прямоугольник, в этих режимах он рисуется обрезанным, иногда за мышью остаются артефакты прорисовки, стрелка-указатель при перемещении мыши не всегда отрисовывается.
Мне кажется, нужно копать в сторону update(x,y,...).
Раньше над оптимизацией не задумывался, так как стояла задача написать движок. Сейчас движок готов на 95%, и в целом функционален, но тормозит (при использовании FullViewportUpdate). Заманчивым выглядит MinimalViewportUpdate, SmartViewportUpdate - но в этих режимах наблюдаю артефакты, зато скорость очень быстрая). Кто подскажет, как грамотно работать с этими двумя режимами?
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #1 : Август 17, 2011, 15:09 »

BoundingRectViewportUpdate пробовал?
Зачем используешь DontAdjustForAntialiasing? Или в QGraphicsItem::boundingRect() сам увеличиваешь границы элемента? Если нет, то будут артефакты.

Цитировать
иногда за мышью остаются артефакты прорисовки, стрелка-указатель при перемещении мыши не всегда отрисовывается.
Проверь boundingRect() элемента стрелки.

Цитировать
setCacheMode(QGraphicsView::CacheBackground);
Как рисуешь подложку? Кеширование может даже очень сильно тормозить.

Нужно иметь ввиду что при отрисовке такой стрелки через всю сцену и особенно при масштабировании тормоза будут в любом случае.
Избежать их можно только отрисовкой стрелки поверх окна минуя QGraphicsScene, но сделать это не так-то просто.
« Последнее редактирование: Август 17, 2011, 15:12 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #2 : Август 17, 2011, 16:33 »

я уже думал, поверх одного view, расположить другой view с пустой сценой, на которой рисовать указатель буду. но тогда все события нужно будет как то перенаправлять на view, который находится ниже. и опять, не факт, что рисование указателя не вызовет отрисовку нижней сцены.
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #3 : Август 17, 2011, 16:40 »

вот прилагаю картину с артефактами (картина одинаковая в режимах minimal и bounding).
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #4 : Август 17, 2011, 16:41 »

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

Сообщений: 2921



Просмотр профиля
« Ответ #5 : Август 17, 2011, 16:54 »

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

Qt 5.11/4.8.7 (X11/Win)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #6 : Август 17, 2011, 17:01 »

это QGraphicsItem, в котором есть массив точек (просчитываю в отдельной процедуре), в методе update рисую полигон по этим точкам.
для расчета нужна начальная и конечная точка (в координатах сцены), сам итем по сути покрывает всю сцену, и рисуется в позиции (0,0)

Код:
class QRouteArrow : public QRailItem
{
Q_OBJECT

    QPointF       fpoints[2]; //начальная и конечная точки стрелки
    qreal           fwidth;
    qreal           fheight;
    qreal           fwidth2;

    QPointF         fbegA,fbegB;    //точки в начале
    QPointF         fendA1,fendA2;  //точки в конце (1 - ближе к центру, 2-дальше от центра)
    QPointF         fendB1,fendB2;  //тоже но с другой стороны от линии
    QPointF         fendC;          //точка отсутпа от конечной на которой будет рисоваться стрелка
    QPolygonF       fpolygon;

protected:

    QPainterPath    shape() const;
    void            paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    QRectF          boundingRect() const;
    QRectF          outlineRect() const;
    void            recalculate();

public:
    QRouteArrow(bool Init = true, QGraphicsItem *parent = 0);
    void            setBegin(QPointF    pos);
    void            setEnd(QPointF  pos);
};

и вот часть реализации
Код:
QRouteArrow::QRouteArrow(bool Init, QGraphicsItem *parent):
        QRailItem(Init,parent)
{
    fStrokeColor = Qt::white;
    fColor = Qt::transparent;
    fwidth = 2;
    fwidth2 = 6;
    fheight = 15;
    if(Init)
    {
        fpoints[0].setX(0);
        fpoints[0].setY(0);
        fpoints[1].setX(50);
        fpoints[1].setY(50);
        prepareGeometryChange();
        recalculate();
    }
    else
    {
        qMemSet(fpoints,0,sizeof(fpoints));
    }
}

QPainterPath    QRouteArrow::shape() const
{
    QPainterPath    path;
    path.addPolygon(fpolygon);
    return  path;
}

void            QRouteArrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * /* widget */)
{
    painter->setPen(fStrokeColor);
    painter->setBrush(fColor);
    painter->drawPolygon(fpolygon);
}

QRectF          QRouteArrow::boundingRect() const
{
    return  QRectF(fpoints[0],fpoints[1]);
}

QRectF          QRouteArrow::outlineRect() const
{
    return  boundingRect().adjusted(-fwidth,-fwidth,fwidth,fwidth);
}

void    QRouteArrow::setBegin(QPointF    pos)
{
    if(fpoints[0]!=pos)
    {
        fpoints[0]=pos;
        prepareGeometryChange();
        recalculate();
    }
}

void    QRouteArrow::setEnd(QPointF  pos)
{
    if(fpoints[1]!=pos)
    {
        fpoints[1]=pos;
        prepareGeometryChange();
        recalculate();
    }
}

« Последнее редактирование: Август 17, 2011, 17:11 от Fregloin » Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #7 : Август 17, 2011, 17:05 »

это QGraphicsItem, в котором есть массив точек (просчитываю в отдельной процедуре), в методе update рисую полигон по этим точкам.
для расчета нужна начальная и конечная точка (в координатах сцены), сам итем по сути покрывает всю сцену, и рисуется в позиции (0,0)
и какой boundingRect() у него?
Записан

Qt 5.11/4.8.7 (X11/Win)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #8 : Август 17, 2011, 17:11 »

вот, я тупанул, исправил
Код:
QRectF          QRouteArrow::boundingRect() const
{
    return shape().boundingRect();
}
теперь рисуется нормально и быстро, но артефакты все же остались у некоторых итемов.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #9 : Август 17, 2011, 17:14 »

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

Qt 5.11/4.8.7 (X11/Win)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #10 : Август 17, 2011, 17:17 »

добавить adjusted в rect?
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #11 : Август 17, 2011, 17:20 »

добавить adjusted в rect?
Наверное)

Зачем используешь DontAdjustForAntialiasing? Или в QGraphicsItem::boundingRect() сам увеличиваешь границы элемента? Если нет, то будут артефакты.
Не ответил на вопрос.
Записан

Qt 5.11/4.8.7 (X11/Win)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #12 : Август 17, 2011, 17:29 »

на счет adjust не уверен, что есть смысл его добавлять (по крайней мере пока ни на что не влияет, а линия у меня не интеркативный элемент - она только отображается).
на счёт fontadjusting - не помню, в самом начале выставил, когда только разбирался с view/scene. впрочем я его убрал, никакой разницы не заметил.
сейчас конечно работать стало на порядок быстрее, но будет ли корректно прорисовываться сцена при частой принудительной перерисовке отдельных итемов (вызовом update, сменить цвет например)?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Август 18, 2011, 06:47 »

Если стрелка "поверх" всех айтемов, то и рисовать ее надо на отдельном слое/пиксмапе, а потом "собирать" (как здесь говорят). С такой мышачьей активностью без слоев все равно не обойтись.

Избежать их можно только отрисовкой стрелки поверх окна минуя QGraphicsScene, но сделать это не так-то просто.
Завести еще одну QGraphicsScene, в ней рисовать только мышиные айтемы, рендерить и результат класть на первую
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #14 : Август 18, 2011, 12:46 »

в принципе и так работает, но тут вылазит ньюанс, при движении стрелкой-указателем, мне при клике по сцене нужно отловить, на каком итеме я кликнул. и часто возникает ситуация, что itemAt() возвращает мне указатель на стрелку(так как она рисутеся поверх всех), а мне нужно узнать какой итем под ней. Как этого добиться?
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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