EPhysics: improve convex shapes

Center of these shapes were wrong, now it's much better.
But collision still seems a bit inaccurate.



SVN revision: 75572
This commit is contained in:
Bruno Dilly 2012-08-22 20:05:25 +00:00
parent 3627234fb8
commit eae54a26ee
5 changed files with 103 additions and 59 deletions

View File

@ -9,68 +9,51 @@ _world_populate(Test_Data *test_data)
{
EPhysics_Shape *pentagon_shape, *hexagon_shape;
EPhysics_Body *pentagon_body, *hexagon_body;
EPhysics_Constraint *constraint;
Evas_Object *pentagon, *hexagon;
pentagon = elm_image_add(test_data->win);
elm_image_file_set(
pentagon, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "pentagon");
evas_object_move(pentagon, WIDTH / 3, HEIGHT / 2 - 30);
evas_object_resize(pentagon, 70, 66);
evas_object_resize(pentagon, 70, 68);
evas_object_show(pentagon);
test_data->evas_objs = eina_list_append(test_data->evas_objs, pentagon);
pentagon_shape = ephysics_shape_new();
ephysics_shape_point_add(pentagon_shape, 0/70., 24/66.);
ephysics_shape_point_add(pentagon_shape, 35/70., 0/66.);
ephysics_shape_point_add(pentagon_shape, 70/70., 24/66.);
ephysics_shape_point_add(pentagon_shape, 56/70., 66/66.);
ephysics_shape_point_add(pentagon_shape, 14/70., 66/66.);
ephysics_shape_point_add(pentagon_shape, -1, -9/33.);
ephysics_shape_point_add(pentagon_shape, 0, -1);
ephysics_shape_point_add(pentagon_shape, 1, -9/33.);
ephysics_shape_point_add(pentagon_shape, -21/35., 1);
ephysics_shape_point_add(pentagon_shape, 21/35., 1);
pentagon_body = ephysics_body_shape_add(test_data->world, pentagon_shape);
ephysics_body_evas_object_set(pentagon_body, pentagon, EINA_TRUE);
ephysics_body_restitution_set(pentagon_body, 1);
ephysics_body_friction_set(pentagon_body, 0);
test_data->bodies = eina_list_append(test_data->bodies, pentagon_body);
hexagon = elm_image_add(test_data->win);
elm_image_file_set(
hexagon, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "hexagon");
evas_object_move(hexagon, WIDTH / 3 + 80, HEIGHT / 2 - 30 + 35);
evas_object_move(hexagon, WIDTH / 3 + 80, HEIGHT / 2 - 30);
evas_object_resize(hexagon, 70, 60);
evas_object_show(hexagon);
test_data->evas_objs = eina_list_append(test_data->evas_objs, hexagon);
hexagon_shape = ephysics_shape_new();
ephysics_shape_point_add(hexagon_shape, 0, 0.5);
ephysics_shape_point_add(hexagon_shape, 18/70., 0);
ephysics_shape_point_add(hexagon_shape, 52/70., 0);
ephysics_shape_point_add(hexagon_shape, 1, 0.5);
ephysics_shape_point_add(hexagon_shape, 52/70., 1);
ephysics_shape_point_add(hexagon_shape, 18/70., 1);
ephysics_shape_point_add(hexagon_shape, 0, 30);
ephysics_shape_point_add(hexagon_shape, 18, 0);
ephysics_shape_point_add(hexagon_shape, 52, 0);
ephysics_shape_point_add(hexagon_shape, 70, 30);
ephysics_shape_point_add(hexagon_shape, 52, 60);
ephysics_shape_point_add(hexagon_shape, 18, 60);
hexagon_body = ephysics_body_shape_add(test_data->world, hexagon_shape);
ephysics_body_mass_set(hexagon_body, 5);
ephysics_body_evas_object_set(hexagon_body, hexagon, EINA_TRUE);
ephysics_body_restitution_set(hexagon_body, 1);
ephysics_body_friction_set(hexagon_body, 0);
test_data->bodies = eina_list_append(test_data->bodies, hexagon_body);
constraint = ephysics_constraint_p2p_add(pentagon_body, NULL, 8, 0,
0, 0);
test_data->constraints = eina_list_append(test_data->constraints,
constraint);
constraint = ephysics_constraint_p2p_add(hexagon_body, NULL, 0, 0, 0, 0);
test_data->constraints = eina_list_append(test_data->constraints,
constraint);
ephysics_body_torque_impulse_apply(pentagon_body, 2);
ephysics_shape_del(pentagon_shape);
ephysics_shape_del(hexagon_shape);
ephysics_world_serialize(test_data->world, "/tmp/test.bullet");
}
static void
@ -86,6 +69,7 @@ _restart(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED_
void
test_shapes(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
{
EPhysics_Body *boundary;
EPhysics_World *world;
Test_Data *test_data;
@ -102,5 +86,12 @@ test_shapes(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
ephysics_world_render_geometry_set(world, 50, 40, WIDTH - 100, FLOOR_Y - 40);
test_data->world = world;
boundary = ephysics_body_bottom_boundary_add(test_data->world);
ephysics_body_restitution_set(boundary, 0.65);
ephysics_body_top_boundary_add(test_data->world);
ephysics_body_left_boundary_add(test_data->world);
ephysics_body_right_boundary_add(test_data->world);
_world_populate(test_data);
}

View File

@ -205,6 +205,9 @@ EAPI void ephysics_shape_del(EPhysics_Shape *shape);
* geometric shapes. The final shape will be constructed in such a way
* it will have all the added points and will be convex.
*
* The center of mass will be the centroid, or geometric center of the
* shape.
*
* The order of points doesn't matter.
*
* For example, to create a pentagon:
@ -212,11 +215,11 @@ EAPI void ephysics_shape_del(EPhysics_Shape *shape);
* @code
* EPhysics_Shape *shape = ephysics_shape_new();
*
* ephysics_shape_point_add(shape, 0/70., 24/66.);
* ephysics_shape_point_add(shape, 35/70., 0/66.);
* ephysics_shape_point_add(shape, 70/70., 24/66.);
* ephysics_shape_point_add(shape, 56/70., 66/66.);
* ephysics_shape_point_add(shape, 14/70., 66/66.);
* ephysics_shape_point_add(shape, 0, 24);
* ephysics_shape_point_add(shape, 35, 0);
* ephysics_shape_point_add(shape, 70, 24);
* ephysics_shape_point_add(shape, 56, 66);
* ephysics_shape_point_add(shape, 14, 66);
*
* ephysics_body_shape_add(world, shape);
*
@ -224,8 +227,8 @@ EAPI void ephysics_shape_del(EPhysics_Shape *shape);
* @endcode
*
* @param shape The shape to be modified.
* @param x Point position at x axis. Should be a value between 0 and 1.
* @param y Point position at y axis. Should be a value between 0 and 1.
* @param x Point position at x axis.
* @param y Point position at y axis.
* @return @c EINA_TRUE on success or EINA_FALSE on error.
*
* @see ephysics_shape_new().

View File

@ -193,7 +193,7 @@ ephysics_body_collision_group_list_get(const EPhysics_Body *body)
}
static EPhysics_Body *
_ephysics_body_add(EPhysics_World *world, btCollisionShape *collision_shape, const char *type)
_ephysics_body_add(EPhysics_World *world, btCollisionShape *collision_shape, const char *type, double cm_x, double cm_y)
{
btRigidBody::btRigidBodyConstructionInfo *rigid_body_ci;
btDefaultMotionState *motion_state;
@ -244,6 +244,8 @@ _ephysics_body_add(EPhysics_World *world, btCollisionShape *collision_shape, con
body->rigid_body = rigid_body;
body->mass = mass;
body->world = world;
body->cm.x = cm_x;
body->cm.y = cm_y;
body->rigid_body->setUserPointer(body);
body->rigid_body->setLinearFactor(btVector3(1, 1, 0));
body->rigid_body->setAngularFactor(btVector3(0, 0, 1));
@ -353,8 +355,8 @@ _ephysics_body_move(EPhysics_Body *body, Evas_Coord x, Evas_Coord y)
ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, &height);
height += wy;
mx = (x + body->w / 2) / rate;
my = (height - (y + body->h / 2)) / rate;
mx = (x + body->w * body->cm.x) / rate;
my = (height - (y + body->h * body->cm.y)) / rate;
body->rigid_body->getMotionState()->getWorldTransform(trans);
trans.setOrigin(btVector3(mx, my, 0));
@ -377,8 +379,8 @@ _ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Eva
ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, &height);
height += wy;
mx = (x + w / 2) / rate;
my = (height - (y + h / 2)) / rate;
mx = (x + w * body->cm.x) / rate;
my = (height - (y + h * body->cm.y)) / rate;
sx = w / rate;
sy = h / rate;
@ -513,8 +515,8 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body)
evas_object_geometry_get(body->evas_obj, NULL, NULL, &w, &h);
rate = ephysics_world_rate_get(body->world);
x = (int) (trans.getOrigin().getX() * rate) - w / 2 - cx;
y = wh + wy - (int) (trans.getOrigin().getY() * rate) - h / 2 - cy;
x = (int) (trans.getOrigin().getX() * rate) - w * body->cm.x - cx;
y = wh + wy - (int) (trans.getOrigin().getY() * rate) - h * body->cm.y - cy;
evas_object_move(body->evas_obj, x, y);
@ -534,7 +536,8 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body)
if (body->soft_body)
_ephysics_body_soft_body_deform(body, rate, map);
evas_map_util_rotate(map, rot, x + (w / 2), y + (h / 2));
evas_map_util_rotate(map, rot, x + (w * body->cm.x), y +
(h * body->cm.y));
evas_object_map_set(body->evas_obj, map);
evas_object_map_enable_set(body->evas_obj, EINA_TRUE);
evas_map_free(map);
@ -690,7 +693,7 @@ _ephysics_body_soft_add(EPhysics_World *world, btCollisionShape *collision_shape
btSoftBody::AJoint::Specs angular_joint;
btSoftBody::LJoint::Specs linear_joint;
body = _ephysics_body_add(world, collision_shape, "soft box");
body = _ephysics_body_add(world, collision_shape, "soft box", 0.5, 0.5);
if (!body)
{
ephysics_body_del(body);
@ -702,7 +705,7 @@ _ephysics_body_soft_add(EPhysics_World *world, btCollisionShape *collision_shape
body->soft_body->getCollisionShape()->setMargin(0.22);
soft_body->m_materials[0]->m_kLST = 0.35;
soft_body->m_materials[0]->m_kLST = 0.35;
soft_body->setPose(true, false);
body->soft_body->m_cfg.collisions += btSoftBody::fCollision::SDF_RS;
@ -806,7 +809,7 @@ ephysics_body_circle_add(EPhysics_World *world)
return NULL;
}
return _ephysics_body_add(world, collision_shape, "circle");
return _ephysics_body_add(world, collision_shape, "circle", 0.5, 0.5);
}
EAPI EPhysics_Body *
@ -883,13 +886,14 @@ ephysics_body_box_add(EPhysics_World *world)
collision_shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
return _ephysics_body_add(world, collision_shape, "box");
return _ephysics_body_add(world, collision_shape, "box", 0.5, 0.5);
}
EAPI EPhysics_Body *
ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
{
btConvexHullShape *full_shape, *simplified_shape;
double max_x, max_y, min_x, min_y, cm_x, cm_y, range_x, range_y;
const Eina_Inlist *points;
EPhysics_Point *point;
btShapeHull *hull;
@ -908,6 +912,13 @@ ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
return NULL;
}
points = ephysics_shape_points_get(shape);
if (eina_inlist_count(points) < 3)
{
ERR("At least 3 points are required to add a shape");
return NULL;
}
full_shape = new btConvexHullShape();
if (!full_shape)
{
@ -915,24 +926,65 @@ ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
return NULL;
}
points = ephysics_shape_points_get(shape);
point = EINA_INLIST_CONTAINER_GET(points, EPhysics_Point);
max_x = min_x = point->x;
max_y = min_y = point->y;
cm_x = cm_y = 0;
/* FIXME : only vertices should be used to calculate the center of mass */
EINA_INLIST_FOREACH(points, point)
{
if (point->x > max_x) max_x = point->x;
if (point->x < min_x) min_x = point->x;
if (point->y > max_y) max_y = point->y;
if (point->y < min_y) min_y = point->y;
cm_x += point->x;
cm_y += point->y;
}
cm_x /= eina_inlist_count(points);
cm_y /= eina_inlist_count(points);
range_x = max_x - min_x;
range_y = max_y - min_y;
EINA_INLIST_FOREACH(points, point)
{
point3d = btVector3(point->x, point->y, 0);
double x, y;
x = (point->x - cm_x) / range_x;
y = - (point->y - cm_y) / range_y;
point3d = btVector3(x, y, -0.5);
full_shape->addPoint(point3d);
point3d = btVector3(point->x, point->y, 0.5);
point3d = btVector3(x, y, 0.5);
full_shape->addPoint(point3d);
}
hull = new btShapeHull(full_shape);
if (!hull)
{
delete full_shape;
ERR("Couldn't create a shape hull.");
return NULL;
}
margin = full_shape->getMargin();
hull->buildHull(margin);
simplified_shape = new btConvexHullShape(&(hull->getVertexPointer()->getX()),
hull->numVertices());
delete hull;
delete full_shape;
if (!simplified_shape)
{
ERR("Couldn't create a simplified shape.");
return NULL;
}
return _ephysics_body_add(world, (btCollisionShape *)simplified_shape,
"generic");
"generic", (cm_x - min_x) / range_x,
1 - (cm_y - min_y) / range_y);
}
void

View File

@ -85,6 +85,10 @@ struct _EPhysics_Body {
double y;
double torque;
} force;
struct {
double x;
double y;
} cm;
Eina_Bool active:1;
Eina_Bool deleted:1;
double distances[4][3];

View File

@ -80,12 +80,6 @@ ephysics_shape_point_add(EPhysics_Shape *shape, double x, double y)
return EINA_FALSE;;
}
if ((x < 0) || (x > 1) || (y < 0) || (y > 1))
{
ERR("Points should be between 0 and 1.");
return EINA_FALSE;
}
point = _ephysics_shape_point_new();
if (!point)
return EINA_FALSE;;