Форум сайта python.su
В общем я использую 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()
Офлайн
а там ни где нельзя например точность расчетов загрубить или шаг по времени при просчете физики крупнее сделать?
Офлайн
Там - нельзя.
pyode хорош “на попробовать”.
Но в живую callback на столкновение при приемлимой производительности можно писать только на C/C++
Питон все же долго считает элементарную математику - а еще дольше переводит ее между самим питоном и С.
Впрочем, можно попробовать такое:
- ставим Cython (PyRex тоже подойдет, но Cython не в пример лучше). Нужен вдобавок C compiler. На линухе gcc должна быть, на винде VC 7.1 для python 2.5 и VC 9 для 2.6 - и выше.
- пишем критический код на нем
- компилируем и смотрим на производительность
Будет хуже, чем на чистом ode. Но, быть может, подойдет.
Офлайн
$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()
Андрей СветловСпасибо, буду пробовать. Я правда впервые слышу о Cython и PyRex, но буду разбираться :)
Впрочем, можно попробовать такое:
- ставим Cython (PyRex тоже подойдет, но Cython не в пример лучше). Нужен вдобавок C compiler. На линухе gcc должна быть, на винде VC 7.1 для python 2.5 и VC 9 для 2.6 - и выше.
- пишем критический код на нем
- компилируем и смотрим на производительность
Офлайн
Еще такой вопрос: а может можно както заставить pyode делать расчеты в 2-х измерениях?
Потому что в моем случае, хоть тела и движутся по плоскости, но ведь pyode всеравно приходится делать вычисления в 3D
#Это чтобы тело двигалось только в 2D
join2d = ode.Plane2DJoint(world)
join2d.attach(body, ode.environment)
Офлайн
luckmaster
еще можно не для всех объектов считать столкновения. Например только что столкнувшиеся, при низкой концентрации имеют малую вероятность столкнуться опять, их можно на некоторое время исключить.
Можно попробовать для каждого объекта хранить расстояние l до ближайшего соседа, которое обновлять каждые l/(2*v_средн) секунд, где v_средн средняя скорость объектов. Вместе с обновлением расстояния l можно пытаться просчитать для объекта столкновение.
Понятно, что этот метод будет давать ошибку, но интуитивно понятно, что энергия со временем должна равномерно распределиться между всеми объектами и можно будет пользоваться средними.
p.s. если у вас в задаче механика просчитывается решением диффуров, то можно использовать какой-нить продвинутый или сильно приближенный метод для их решения.
Отредактировано (Июль 23, 2009 01:15:59)
Офлайн
$m1t
Спасибо за хорошие идеи!
Мне правда было както лениво делать подобные расчеты самостоятельно, и я полез в документацию pyode в надежде найти там чтото подобное. И нашел у класса World 2 полезные функции :)
quickStep(stepsize)
Step the world.
setAutoDisableFlag(flag)
Set the default auto-disable flag for newly created bodies.
В общем получил увеличение скорости примерно на 700%, при том что качество симуляции практически не пострадало…
Офлайн
Построить сетку и контролировать наличие обьектов в одном квадрате и смежных. И соответственно запускать расчёт столкновения вручную для конкретных обьектов.
Плюс контроль критического расстояния, о чём говорилось выше.
Офлайн
GriffonЕще немного порылся в документации pyode и нашел похожий алгоритм, он уже реализован в самом движке, его просто надо было включить :)
Построить сетку и контролировать наличие обьектов в одном квадрате и смежных. И соответственно запускать расчёт столкновения вручную для конкретных обьектов.
Type SpaceBaseHashSpace - это оно.
…
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
Отредактировано (Июль 24, 2009 01:18:36)
Офлайн
luckmaster: Если не сложно, напиши, что получилось после всех оптимизаций, какая скорость?
Тоже думал разобраться с pyode, хотелось бы знать, стоит ли…
Офлайн