Найти - Пользователи
Полная версия: Как эффективно использовать pyode?
Начало » Python для новичков » Как эффективно использовать pyode?
1 2
luckmaster
В общем я использую pyode для расчета физики в 2D.
Все мне в нем нравится, но вот есть небольшая проблема - както медленно он работает. Например если свалить в кучу 30 объектов, то получаю около 15-30 fps, а если 40 объектов в кучу, то уже около 5-10 fps. Если разложить эти 40 объектов так чтобы они НЕ соприкасались друг с другом, то скорость значительно возрастает, но ведь мне то нужно чтобы они сталкивались :) Программу запускаю на машине - Athlon X2 2.2 GHz, RAM 2 GB.

И вот мне интиресно:
-такая сорость - это нормально для pyode?
-на сколько быстрее ode чем pyode?
-может надо знать какието премудрости чтобы эффективнее использовать pyode?


Вот привожу некоторые фрагменты кода, которые касаются pyode:

world = ode.World()
world.setGravity((0, -9.81, 0))
space = ode.Space()
#Вот таким образом создаю объекты
body = ode.Body(world)
m = ode.Mass()
m.setBox(density, lengths[0], lengths[1], lengths[2])
body.setMass(m)
geom = ode.GeomBox(space, (lengths[0], lengths[1], lengths[2]))
geom.setBody(body)
body.setPosition((x, y, 0))

#Это чтобы тело двигалось только в 2D
join2d = ode.Plane2DJoint(world)
join2d.attach(body, ode.environment)
#Эту функцию взял из туториала по pyode
def near_callback(args, geom1, geom2):
'''Callback function for the collide() method.

This function checks if the given geoms do collide and
creates contact joints if they do.
'''

# Check if the objects do collide
contacts = ode.collide(geom1, geom2)

# Create contact joints
world,contactgroup = args
for c in contacts:
c.setBounce(0.2)
c.setMu(5000)
j = ode.ContactJoint(world, contactgroup, c)
j.attach(geom1.getBody(), geom2.getBody())
#Этот блок каждый раз вызывается в главном цикле программы
contactgroup = ode.JointGroup()
n = 2
for i in range(n):
space.collide((world, contactgroup), near_callback)
world.step(dt / n)
contactgroup.empty()
$m1t
а там ни где нельзя например точность расчетов загрубить или шаг по времени при просчете физики крупнее сделать?
Андрей Светлов
Там - нельзя.
pyode хорош “на попробовать”.
Но в живую callback на столкновение при приемлимой производительности можно писать только на C/C++
Питон все же долго считает элементарную математику - а еще дольше переводит ее между самим питоном и С.

Впрочем, можно попробовать такое:
- ставим Cython (PyRex тоже подойдет, но Cython не в пример лучше). Нужен вдобавок C compiler. На линухе gcc должна быть, на винде VC 7.1 для python 2.5 и VC 9 для 2.6 - и выше.
- пишем критический код на нем
- компилируем и смотрим на производительность

Будет хуже, чем на чистом ode. Но, быть может, подойдет.
luckmaster
$m1t
а там ни где нельзя например точность расчетов загрубить или шаг по времени при просчете физики крупнее сделать?
Ну вобще можно вот здесь увеличить dt и уменьшить n
#Этот блок каждый раз вызывается в главном цикле программы
contactgroup = ode.JointGroup()
n = 2
for i in range(n):
space.collide((world, contactgroup), near_callback)
world.step(dt / n)
contactgroup.empty()
Но я сейчас использую
dt = 1.0 / 30.0
n = 2
И всеравно так довольно медленно работает. А если еще больше упростить, то качество расчетов будет совсем уж низкое.

Андрей Светлов
Впрочем, можно попробовать такое:
- ставим Cython (PyRex тоже подойдет, но Cython не в пример лучше). Нужен вдобавок C compiler. На линухе gcc должна быть, на винде VC 7.1 для python 2.5 и VC 9 для 2.6 - и выше.
- пишем критический код на нем
- компилируем и смотрим на производительность
Спасибо, буду пробовать. Я правда впервые слышу о Cython и PyRex, но буду разбираться :)
luckmaster
Еще такой вопрос: а может можно както заставить pyode делать расчеты в 2-х измерениях?

Потому что в моем случае, хоть тела и движутся по плоскости, но ведь pyode всеравно приходится делать вычисления в 3D
#Это чтобы тело двигалось только в 2D
join2d = ode.Plane2DJoint(world)
join2d.attach(body, ode.environment)
А если откинуть одно измерение, то расчеты должны сильно упроститься и сорость возрастет…

Или может посоветуете какой-нибудь другой движек - более подходящий именно для 2D.
$m1t
luckmaster
еще можно не для всех объектов считать столкновения. Например только что столкнувшиеся, при низкой концентрации имеют малую вероятность столкнуться опять, их можно на некоторое время исключить.

Можно попробовать для каждого объекта хранить расстояние l до ближайшего соседа, которое обновлять каждые l/(2*v_средн) секунд, где v_средн средняя скорость объектов. Вместе с обновлением расстояния l можно пытаться просчитать для объекта столкновение.

Понятно, что этот метод будет давать ошибку, но интуитивно понятно, что энергия со временем должна равномерно распределиться между всеми объектами и можно будет пользоваться средними.

p.s. если у вас в задаче механика просчитывается решением диффуров, то можно использовать какой-нить продвинутый или сильно приближенный метод для их решения.
luckmaster
$m1t
Спасибо за хорошие идеи!
Мне правда было както лениво делать подобные расчеты самостоятельно, и я полез в документацию pyode в надежде найти там чтото подобное. И нашел у класса World 2 полезные функции :)

quickStep(stepsize)
Step the world.

setAutoDisableFlag(flag)
Set the default auto-disable flag for newly created bodies.

В общем получил увеличение скорости примерно на 700%, при том что качество симуляции практически не пострадало…
Griffon
Построить сетку и контролировать наличие обьектов в одном квадрате и смежных. И соответственно запускать расчёт столкновения вручную для конкретных обьектов.
Плюс контроль критического расстояния, о чём говорилось выше.
luckmaster
Griffon
Построить сетку и контролировать наличие обьектов в одном квадрате и смежных. И соответственно запускать расчёт столкновения вручную для конкретных обьектов.
Еще немного порылся в документации pyode и нашел похожий алгоритм, он уже реализован в самом движке, его просто надо было включить :)

Type SpaceBase

This Space class can be used for both, a SimpleSpace and a HashSpace (see ODE documentation).
>>> space = Space(type=0) # Create a SimpleSpace
>>> space = Space(type=1) # Create a HashSpace
HashSpace - это оно.

P.S. Я вобще документацию к ode посмотрел, и почти на все свои вопросы там ответ нашел…
Striver
luckmaster: Если не сложно, напиши, что получилось после всех оптимизаций, какая скорость?

Тоже думал разобраться с pyode, хотелось бы знать, стоит ли…
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB