crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

3 страниц V   1 2 3 >  
Ответить в данную темуНачать новую тему
> Оптимизация отрисовки QGraphicsEllipseItem
Petr0vi4
  опции профиля:
сообщение 14.7.2009, 13:27
Сообщение #1


Студент
*

Группа: Новичок
Сообщений: 11
Регистрация: 14.7.2009
Пользователь №: 907

Спасибо сказали: 0 раз(а)




Репутация:   0  


Пишу программу для симуляции движения частиц идеального газа в сосуде. У меня есть 4 стенки сосуда (QGraphicsRectItem) и 100 QGraphicsEllipsItem шариков размером 5*5 (типа молекулы).
Каждой молекуле на этапе создание присваивается вектор в виде координат 2х точек, а перемещение происходит по событию таймера вдоль этого вектора. Мне необходимо обработать столкновение между молекулами и стенами. Я все это реализовал, но дело в том, что все это жутко тормозит :(

Код обнаружения столкновений:
for(int i=0;i<Item->collidingItems().count();i++)
    {
        if(Item->collidingItems().at(i)->type() == 4) // столкновение с другой молекулой
        {
            // записываем новый вектор движения в буффер
        }
        else
        {
            if(Item->collidingItems().at(i)->type() == 3) // столкновение со стеной
            {
                // записываем новый вектор движения в буффер
            }
        }
    }

Таймер срабатывает с интервалом в 10 мс.
AllObjects - массив элементов класса Control.
Control - класс наследник QObject, в нем есть QGraphicsEllipsItem* Item (сама молекула) + переменные типа qreal для вектора движения.
Код в событии таймера:
for(int i=0;i<ObjNum;i++) // цикл по всем объектам
    AllObjects[i]->BallCollision(); //обрабатываем столкновения

// применяем координаты и двигаем шары
for(int i=0;i<ObjNum;i++)
{
    if(AllObjects[i]->Changed) // проверяем изменились ли координаты
    {
       AllObjects[i]->ReadFromBuffer(); // пишем из буфера в "рабочий" вектор
    }
    AllObjects[i]->MoveBall();//двигаем
}

Получается за 1 событие таймера я 2 раза выполняю цикл по всем объектам.
Класс для молекулы выбран с рассчетом на то, что в нем уже прописана обработка столкновений.
При количестве шариков 20-30 все работает идеально, при 50-100 уже тормозит :(
Можно ли как то ускорить обработку? Может кто-нибудь предложит какое-то альтернативное решение.
Причина редактирования: используй тэг code
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 14.7.2009, 14:00
Сообщение #2


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Petr0vi4 @ 14.7.2009, 17:27) *
Таймер срабатывает с интервалом в 10 мс.
зачем так часто?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Petr0vi4
  опции профиля:
сообщение 14.7.2009, 14:30
Сообщение #3


Студент
*

Группа: Новичок
Сообщений: 11
Регистрация: 14.7.2009
Пользователь №: 907

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Litkevich Yuriy @ 14.7.2009, 22:00) *
зачем так часто?

ну надо чтобы движение плавное было...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 14.7.2009, 14:53
Сообщение #4


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Цитата(Petr0vi4 @ 14.7.2009, 15:30) *
Цитата(Litkevich Yuriy @ 14.7.2009, 22:00) *
зачем так часто?

ну надо чтобы движение плавное было...

Это плавное движение равно 1000/10=100 fps, твой глаз не успеет заметить разницы. Выбирай 25-30 fps (50 мс).
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Petr0vi4
  опции профиля:
сообщение 14.7.2009, 15:17
Сообщение #5


Студент
*

Группа: Новичок
Сообщений: 11
Регистрация: 14.7.2009
Пользователь №: 907

Спасибо сказали: 0 раз(а)




Репутация:   0  


На 50 мс слишком медленно движутся почему-то :( Увеличиваю скорость и все равно не то.
Вот код движения, может что не так.
Module(int) - это я беру модуль числа.
Вектор движения это 2 точки: (x1;y1) и (x2;y2).
dx = х2-х1, dy = у2-у1, speed - скорость движения.
Одну координату я увеличиваю на величину скорости, вторую высчитываю по формуле прямая через 2 точки.
if(Module(dx) < Module(dy)) // смотрим по какой координате делать приращение (для равномерного движения)
    {
        if(y2!=y1)
        {
            qreal y = Item->pos().y();
            if(y1<y2) // смотрим в какую сторону двигать
                y = y+speed;
            else
                y = y-speed;
            Item->setPos((((y-y1)*(x2-x1)/(y2-y1))+x1),y);
        }
    }
    else
    {
        if(x2!=x1)
        {
            qreal x = Item->pos().x();
            if(x1<x2) // смотрим в какую сторону двигать
                x = x+speed;
            else
                x = x-speed;
            Item->setPos(x,(((x-x1)*(y2-y1)/(x2-x1))+y1));
        }
    }
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 14.7.2009, 17:24
Сообщение #6


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Ну, что я могу сказать?
Взял пример examples\graphicsview\collidingmice

Задал кол-во мышей = 40 (вместо 7 исходных)
Всё работает с тойже с коростью, что и раньше. НО стоило развернуть окно на весь экран, как они, мыши, стали ползать как улитки.

Т.е. дело в видимой части представления, как я понимаю.

А вот при кол-ве 100 шт. они уже и при нормальном размере окна еле ползают.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 14.7.2009, 17:27
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Возможно есть смысл сделать кэш. Например просчитать коллизию на несколько секунд вперед и только менять координаты объектов.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Kagami
  опции профиля:
сообщение 14.7.2009, 17:30
Сообщение #8


Старейший участник
****

Группа: Участник
Сообщений: 601
Регистрация: 2.2.2009
Пользователь №: 523

Спасибо сказали: 101 раз(а)




Репутация:   9  


Все дело в процедуре обнаружения столкновений. Это и есть узкое место. Для молекул ее можно упростить. Так как они являются идеальными шарами то столкновения между ними можно определять следующим образом: если расстояние между центрами меньше или равно сумме их радиусов, то они сталкиваются. со стенами еще проще. Смотрим расстояние от центра молекулы до стены, если оно меньше или равно ее радиусу, они сталкиваются. Так как стены перпендекулярны осям, найти это расстояние не будет очень сложно.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 14.7.2009, 17:57
Сообщение #9


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Вообще на мой взгляд пример "сталкивающиеся мыши" не рационален.

Т.к. событие таймера генерится для каждой мышки, в каждом таком событии она перерисовывается. А надо генерить событие для сцены и по нему перерисовывать.
Ещё можно в событии таймера для мыши можно её не рисовать а готовить только её положени (поворот и координаты).


П.С. Закоментировал такую строку:
//view.setRenderHint(QPainter::Antialiasing);
скорость почти в двое возрасла без зглаживания.

Добавил в конструктор класса Mouse такую строку:
setCacheMode(QGraphicsItem::ItemCoordinateCache);
сразу всё зашевелилось шустрее.


Проверил, наличе сглаживания в представлении не влияет на скорость, если включен кэш у графического элемента
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Petr0vi4
  опции профиля:
сообщение 14.7.2009, 18:13
Сообщение #10


Студент
*

Группа: Новичок
Сообщений: 11
Регистрация: 14.7.2009
Пользователь №: 907

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата
Kagami

Здесь другая сторона медали - мне придется обрабатывать цикл в цикле. Проверять для каждой частицы, сталкивается ли она с остальными девяность девятью! Я думаю это тоже не есть хорошо...

Цитата
SABROG

Кэш с событием collidingItems() не получится, оно ведь срабатывает только при столкновении которое есть сейчас (при данных координатах объектов) :(

Цитата
Litkevich Yuriy

На счет сглаживания спасибо! В конструктор молекулы добавил
setCacheMode(QGraphicsItem::ItemCoordinateCache);

В main функцию
view.setRenderHint(QPainter::Antialiasing);

Стало красиво, но тупит как и раньше.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

3 страниц V   1 2 3 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 28.3.2024, 14:22