Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: Fregloin от Август 17, 2011, 14:43



Название: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 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 - но в этих режимах наблюдаю артефакты, зато скорость очень быстрая). Кто подскажет, как грамотно работать с этими двумя режимами?


Название: Re: Оптимизация отрисовки сцены
Отправлено: GreatSnake от Август 17, 2011, 15:09
BoundingRectViewportUpdate пробовал?
Зачем используешь DontAdjustForAntialiasing? Или в QGraphicsItem::boundingRect() сам увеличиваешь границы элемента? Если нет, то будут артефакты.

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

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

Нужно иметь ввиду что при отрисовке такой стрелки через всю сцену и особенно при масштабировании тормоза будут в любом случае.
Избежать их можно только отрисовкой стрелки поверх окна минуя QGraphicsScene, но сделать это не так-то просто.


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 17, 2011, 16:33
я уже думал, поверх одного view, расположить другой view с пустой сценой, на которой рисовать указатель буду. но тогда все события нужно будет как то перенаправлять на view, который находится ниже. и опять, не факт, что рисование указателя не вызовет отрисовку нижней сцены.


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 17, 2011, 16:40
вот прилагаю картину с артефактами (картина одинаковая в режимах minimal и bounding).


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 17, 2011, 16:41
при чем, когда я вожу указатель, он отрисовывается только в тех случаях, когда конечная точка находится ниже и правее начальной, иначе не рисуется вообще.


Название: Re: Оптимизация отрисовки сцены
Отправлено: GreatSnake от Август 17, 2011, 16:54
при чем, когда я вожу указатель, он отрисовывается только в тех случаях, когда конечная точка находится ниже и правее начальной, иначе не рисуется вообще.
Как реализована стрелка?


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 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();
    }
}



Название: Re: Оптимизация отрисовки сцены
Отправлено: GreatSnake от Август 17, 2011, 17:05
это QGraphicsItem, в котором есть массив точек (просчитываю в отдельной процедуре), в методе update рисую полигон по этим точкам.
для расчета нужна начальная и конечная точка (в координатах сцены), сам итем по сути покрывает всю сцену, и рисуется в позиции (0,0)
и какой boundingRect() у него?


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 17, 2011, 17:11
вот, я тупанул, исправил
Код:
QRectF          QRouteArrow::boundingRect() const
{
    return shape().boundingRect();
}
теперь рисуется нормально и быстро, но артефакты все же остались у некоторых итемов.


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


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 17, 2011, 17:17
добавить adjusted в rect?


Название: Re: Оптимизация отрисовки сцены
Отправлено: GreatSnake от Август 17, 2011, 17:20
добавить adjusted в rect?
Наверное)

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


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 17, 2011, 17:29
на счет adjust не уверен, что есть смысл его добавлять (по крайней мере пока ни на что не влияет, а линия у меня не интеркативный элемент - она только отображается).
на счёт fontadjusting - не помню, в самом начале выставил, когда только разбирался с view/scene. впрочем я его убрал, никакой разницы не заметил.
сейчас конечно работать стало на порядок быстрее, но будет ли корректно прорисовываться сцена при частой принудительной перерисовке отдельных итемов (вызовом update, сменить цвет например)?


Название: Re: Оптимизация отрисовки сцены
Отправлено: Igors от Август 18, 2011, 06:47
Если стрелка "поверх" всех айтемов, то и рисовать ее надо на отдельном слое/пиксмапе, а потом "собирать" (как здесь говорят). С такой мышачьей активностью без слоев все равно не обойтись.

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


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 18, 2011, 12:46
в принципе и так работает, но тут вылазит ньюанс, при движении стрелкой-указателем, мне при клике по сцене нужно отловить, на каком итеме я кликнул. и часто возникает ситуация, что itemAt() возвращает мне указатель на стрелку(так как она рисутеся поверх всех), а мне нужно узнать какой итем под ней. Как этого добиться?


Название: Re: Оптимизация отрисовки сцены
Отправлено: GreatSnake от Август 18, 2011, 12:49
Используй items() и игнорируй стрелку.


Название: Re: Оптимизация отрисовки сцены
Отправлено: mal от Август 23, 2011, 15:21
Динамику рисовать в drawForeground - намного быстрее выходит, чем использовать айтем, всобаченый на сцену. Это про вашу стрелку от места нажатия до текущего положения курсора.
Плюс QGLWidget.


Название: Re: Оптимизация отрисовки сцены
Отправлено: Fregloin от Август 23, 2011, 21:16
я так и подозревал, попробую на днях.
на счёт GL я создам новую тему и опишу некоторые трудности с его использованием.