trimesh center of mass question

630 views
Skip to first unread message

Joshua Auerbach

unread,
Jun 7, 2012, 5:09:14 PM6/7/12
to ode-users
I have a question about trimesh center of masses. I thought I
understood this, but am no longer so sure.

I am creating movable trimesh bodies/geoms as follows:

obj[i].body = dBodyCreate (world);
dBodySetPosition (obj[i].body, 0,0,0);
dBodySetData (obj[i].body,(void*)(size_t)i);

dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSimple(new_tmdata, (dReal*) obj[i].Vertices,
obj[i].VertexCount, obj[i].Indices, obj[i].IndexCount);
obj[i].geom = dCreateTriMesh(space, new_tmdata, 0, 0, 0);

dGeomSetData(obj[i].geom, new_tmdata);
dMass m;
dMassSetTrimesh( &m, DENSITY, obj[i].geom );
dGeomSetPosition(obj[i].geom, -m.c[0], -m.c[1], -m.c[2]);
dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);

dGeomSetBody (obj[i].geom,obj[i].body);
dBodySetMass (obj[i].body,&m);

Now, typically my trimesh vertices are defined with the origin somewhere
on the bottom. If I later want to move the trimesh (wth
dBodySetPosition or dGeomSetPosition) it seems that those positions move
the trimesh so that the origin of my vertices is at the specified
location and not so that the center of mass is at that location. So,
then where is the center of mass?

I thought that when I do

dGeomSetPosition(obj[i].geom, -m.c[0], -m.c[1], -m.c[2]);
dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);

as is done in the demo (moving_trimesh), that this is moving the mass to
be centered at the origin of the body's reference frame, and moving the
geom to be at the origin of the global reference. But, this
dGeomSetPosition seems to have no impact since I am calling dGeomSetBody
later... am I missing something here?

Finally, I get different behavior if I translate all my vertices before
creating the trimesh geom vs creating the trimesh geom/body and then
translating it by the same amount. I take it that the center of mass is
in different locations in these two cases.

Any clarifications/explanations on this would be greatly appreciated.

Thanks!
Josh

Dimitris Papavasiliou

unread,
Jun 7, 2012, 6:45:25 PM6/7/12
to ode-...@googlegroups.com
Calling dGeomSetPosition to make up for the shift in the body's reference frame won't help much as geom and body will end up with the same reference frame anyway after they're bound to each other.  I believe you need to use dGeomSetOffsetPosition instead to define a constant offset in the frames of body and geom.

Dimitris

Joshua Auerbach

unread,
Jun 7, 2012, 10:32:28 PM6/7/12
to ode-...@googlegroups.com
So is the demo_moving_trimesh wrong, then?  Or does it not matter there, because that trimesh is created with the center of mass at the origin of the trimesh vertex coordinates?
--
You received this message because you are subscribed to the Google Groups "ode-users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/ode-users/-/pdSeWXsUSWIJ.
To post to this group, send email to ode-...@googlegroups.com.
To unsubscribe from this group, send email to ode-users+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/ode-users?hl=en.

Daniel K. O.

unread,
Jun 7, 2012, 10:43:59 PM6/7/12
to ode-...@googlegroups.com
On 06/07/2012 10:32 PM, Joshua Auerbach wrote:
> So is the demo_moving_trimesh wrong, then? Or does it not matter there,
> because that trimesh is created with the center of mass at the origin of
> the trimesh vertex coordinates?

That demo still uses the deprecated API, with geom transforms. The
recommended way to do it now is with offsets. A patch to update the demo
to offsets would be welcome.


--
Daniel K. O.

Joshua Auerbach

unread,
Jun 8, 2012, 9:50:32 AM6/8/12
to ode-...@googlegroups.com
As far as I can tell geom tranforms are only used there for the
composite objects. That is not what I was asking about. The geoms I am
dealing with are single enclosed trimeshes.

Joshua Auerbach

unread,
Jun 11, 2012, 3:04:57 PM6/11/12
to ode-...@googlegroups.com
Anyone know anything else about this? How should geom offsets be used
with trimeshes?

One test case I have been playing with: I have two trimeshes that are
identical, except in one the vertices all have 1.0 added to their z
coordinates. I was hoping that by using offsets the center of mass
would be translated to be in the correct position regardless of this
translation and so their behavior would be the same, but this is not the
case. I was not sure if I should then be setting the positions
differently (e.g. subtract 1 from the z-coord of the trimesh that has
been translated), but no matter what I do the behavior is different.

Is there any way to correct for translations in the trimesh vertices?

Any help/clarification about this stuff would be greatly appreciated.

Thanks!
Josh

Mikko Rasa

unread,
Jun 11, 2012, 3:40:59 PM6/11/12
to ode-...@googlegroups.com
Did you already try attaching the geom to the body and then setting its
offset position? i.e. call dGeomSetBody first, then dGeomSetOffsetPosition.

The trimesh demo is not wrong, it simply uses the (now deprecated) geom
transform API, which works differently.

Mikko

Joshua Auerbach

unread,
Jun 11, 2012, 3:54:52 PM6/11/12
to ode-...@googlegroups.com


On 06/11/2012 03:40 PM, Mikko Rasa wrote:
> Did you already try attaching the geom to the body and then setting
> its offset position? i.e. call dGeomSetBody first, then
> dGeomSetOffsetPosition.
Yes, that is what I tried. It doesn't work at all calling
dGeomSetOffsetPosition before the geom is attached to a body: ODE
crashes with "ODE INTERNAL ERROR 2: geom must be on a body in
dGeomSetOffsetPosition()"
>
> The trimesh demo is not wrong, it simply uses the (now deprecated)
> geom transform API, which works differently.
This transform API keeps getting brought up, but it only seems to be
used in that demo for composite objects not for trimeshes so, as far as
I can tell, is unrelated to what I am asking about.

Thanks!
Josh

Dimitris Papavasiliou

unread,
Jun 11, 2012, 6:25:51 PM6/11/12
to ode-...@googlegroups.com

This transform API keeps getting brought up, but it only seems to be
used in that demo for composite objects not for trimeshes so, as far as
I can tell, is unrelated to what I am asking about.

Correct me if my cursory glance at the demo source leads me to false conclusions but in the demo a trimesh is only used as the static environment geom which has no body and therefore nothing to do with centers of gravity and the like.  So either geom offsets or transform geoms are irrelevant in this context as you correctly point out.  Everybody keeps mentioning transform geoms because they're the predecessor to what you (allegedly) need to use.

One thing you might need to double-check is how you set the offset.  If you translate the body mass by a vector T in order to get it to line up with the body's center of gravity then to make up for this by using a *geom* offset I think you'd need to offset the geom by -T with respect with the body to correctly reflect the initial configuration of the body.  Of course I've never actually encountered this situation or used geom offsets and its way past 1 AM over here so I might be talking nonsense.

Dimitris

Dimitris Papavasiliou

unread,
Jun 11, 2012, 6:29:20 PM6/11/12
to ode-...@googlegroups.com

One thing you might need to double-check is how you set the offset.  If you translate the body mass by a vector T in order to get it to line up with the body's center of gravity then to make up for this by using a *geom* offset I think you'd need to offset the geom by -T with respect with the body to correctly reflect the initial configuration of the body.  Of course I've never actually encountered this situation or used geom offsets and its way past 1 AM over here so I might be talking nonsense.

Also note that in order to start from the same configuration you might also need to translate the initial position of the body/geom pair (with dBody/GeomSetPosition) by T to cancel out the geom offset.  Previous disclaimer applies.

Dimitris

Joshua Auerbach

unread,
Jun 11, 2012, 6:49:38 PM6/11/12
to ode-users
On 06/11/2012 06:25 PM, Dimitris Papavasiliou wrote:

This transform API keeps getting brought up, but it only seems to be
used in that demo for composite objects not for trimeshes so, as far as
I can tell, is unrelated to what I am asking about.

Correct me if my cursory glance at the demo source leads me to false conclusions but in the demo a trimesh is only used as the static environment geom which has no body and therefore nothing to do with centers of gravity and the like.  So either geom offsets or transform geoms are irrelevant in this context as you correctly point out.  Everybody keeps mentioning transform geoms because they're the predecessor to what you (allegedly) need to use.
They are not just used as static geoms.  You can also drop dynamic trimeshes by pressing 'm'.  In my tests I have stripped out everything except for this dynamic trimesh and have removed the randomization on its position and rotation.


One thing you might need to double-check is how you set the offset.  If you translate the body mass by a vector T in order to get it to line up with the body's center of gravity then to make up for this by using a *geom* offset I think you'd need to offset the geom by -T with respect with the body to correctly reflect the initial configuration of the body.  Of course I've never actually encountered this situation or used geom offsets and its way past 1 AM over here so I might be talking nonsense.
In the code the mass is translated by -m.c as follows

dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);

If I don't do that, or call dMassTranslate with some other value then it will crash with "ODE INTERNAL ERROR 2: The centre of mass must be at the origin. in dBodySetMass()"

You are saying I should use a geom offset of m.c and not -m.c?

What the code in the demo does is translate the geom itself:

dGeomSetPosition(obj[i].geom, -m.c[0], -m.c[1], -m.c[2]);

but, as I said in my previous email I believe this line does not do anything since later on the geom is attached to a body and takes its position.

Josh

Dimitris Papavasiliou

unread,
Jun 12, 2012, 4:57:47 AM6/12/12
to ode-...@googlegroups.com

They are not just used as static geoms.  You can also drop dynamic trimeshes by pressing 'm'.  In my tests I have stripped out everything except for this dynamic trimesh and have removed the randomization on its position and rotation.

Ah, yes, I was in fact looking at demo_trimesh.cpp.
 
In the code the mass is translated by -m.c as follows
dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);

If I don't do that, or call dMassTranslate with some other value then it will crash with "ODE INTERNAL ERROR 2: The centre of mass must be at the origin. in dBodySetMass()"

Yes, ODE can't handle masses where the center of mass doesn't coincide with the origin.
 
You are saying I should use a geom offset of m.c and not -m.c?

Well I'm not particularly good with theoretical reasoning but if forced I'd reason thus: since the origin of the body has been translated to -m.c then the origin of the old reference frame is at point m.c in the new reference frame.  So if the geom was to develop a contact at its origin it would need to exert a force on the body at m.c so you need an offset of m.c.  As I said I'm not very good at thinking about transformations so I only suggest it as something worth trying out to see if it works.
 
What the code in the demo does is translate the geom itself:
dGeomSetPosition(obj[i].geom, -m.c[0], -m.c[1], -m.c[2]);

but, as I said in my previous email I believe this line does not do anything since later on the geom is attached to a body and takes its position.

I believe so too.  In fact I think that the demo is physically inaccurate but since we do not get to see many gigantic bunnies of uniform density in the real world it's hard to recognize by inspection.

Dimitris

Joshua Auerbach

unread,
Jun 12, 2012, 5:18:30 PM6/12/12
to ode-...@googlegroups.com
On 06/12/2012 04:57 AM, Dimitris Papavasiliou wrote:
> I believe so too. In fact I think that the demo is physically
> inaccurate but since we do not get to see many gigantic bunnies of
> uniform density in the real world it's hard to recognize by inspection.
>
I think we wouldn't notice much difference here, because the bunny has
been designed so that it's center of mass is very close to the origin of
it's vertices.

I've been playing with this quite a bit, and think I (may) have
something figured out... if anyone else cares to comment:

I take the bunny and find the vertex with min Z coord, call this point
M. I can now place the body at (-M.x, -M.y, -M.z) so that it is resting
on the ground with that point M at the origin. If I do nothing else (no
geom offsets) it basically just rests there. However, if I first
translate all the vertices by say +5 in the y-direction and do the same
thing it starts in the same position but it falls towards -y. I take it
this is because I am now placing the body (and therefore it's center of
mass) with y-coordinate moved by -5 from the first case and it only
starts in the same position because the vertices are translated by that
amount.

To correct for this I can add that +5 back to where I am placing the
body and set the offset position of the geom to be -5. In this way I
believe I am keeping the center of mass in its original position and
offsetting the geom so it is also in its original position. If I try to
log positions or something I won't get exactly the same values but I am
chalking this up to floating point issues.

The problem still is that what defines the behavior in my first test is
the assumption that the center of mass of the trimesh is at it's origin
(which isn't quite right with the bunny), but if I don't know where the
center of mass is (my original issue) I have to do something a little
different. Call the vector we translate the mass by to get it to play
nice -T. I believe what I want to do is place the body at -M + T, and
set the geom offset to be -T. In this way the center of mass is being
determined by the mass object, I am offsetting the geom to line up with
this and then moving the body to be where I want it to be. I just need
to remember that if I want to get the position of a vertex in world
coordinates at a later time, I first have to translate it by the offset
before calling dBodyGetRelPointPos.

Does this all make sense?

-Josh

Daniel K. O.

unread,
Jun 13, 2012, 1:39:32 AM6/13/12
to ode-...@googlegroups.com
On 06/08/2012 09:50 AM, Joshua Auerbach wrote:
> As far as I can tell geom tranforms are only used there for the
> composite objects. That is not what I was asking about. The geoms I
> am dealing with are single enclosed trimeshes.
>

Indeed, I got confused by the bad indentation in the code; that whole
block with geom transforms is part of the composite body creation, even
though it looks like common code after all the creation code. Gotta get
rid of those tabs.

The demo is wrong; it's either missing the parent geom transform sothe
dGeomSetPosition would make sense, or needs it to be replaced by
dGeomSetOffsetPosition.

And to respond to another question in this thread, if you offset the
mass by x, it means the object was translated by x (as in ODE the
"position" of a body is its center of mass); so the geoms have to be
translated too, by the same amount. If the center of mass is 10 units to
the right, you have to move it 10 units to the left to bring it to the
origin; if at 10 units to the right you had a sphere, it now has to be
translated 10 units to the left too, to match the position of the center
of mass. So the proper way to do it is:

dGeomSetOffsetPosition(geom, -mass.c[0], -mass.c[1], -mass.c[2]);
dMassTranslate(&mass, -mass.c[0], -mass.c[1], -mass.c[2]);



--
Daniel K. O.


Dimitris Papavasiliou

unread,
Jun 13, 2012, 6:47:26 AM6/13/12
to ode-...@googlegroups.com


The problem still is that what defines the behavior in my first test is
the assumption that the center of mass of the trimesh is at it's origin
(which isn't quite right with the bunny), but if I don't know where the
center of mass is (my original issue) I have to do something a little
different.  Call the vector we translate the mass by to get it to play
nice -T.  I believe what I want to do is place the body at -M + T, and
set the geom offset to be -T.  In this way the center of mass is being
determined by the mass object, I am offsetting the geom to line up with
this and then moving the body to be where I want it to be.  I just need
to remember that if I want to get the position of a vertex in world
coordinates at a later time, I first have to translate it by the offset
before calling dBodyGetRelPointPos.

Does this all make sense?

Perhaps you're already well aware of this but I'll mention it nevertheless.  The position of the body is not really important with regards to its dynamics with the exception of collisions.  if you do something to a body at some point P the body will respond in the same manner as if you had done it at Q.  The results, for instance the trajectory of the body, should only be translated by P-Q but otherwise the same.   This is in the absence of collisions of course.  If the difference between the two points would lead the body to collide with some other body in one case but not in the other, or if they collide differently due to the translation like at a different angle say, then the results will differ of course.

So when you translate the mass it's the same body really "only a little to the right" and with a different origin, so when you apply forces in local coordinates for example you have to take that into account, but otherwise it should be the same.  That's why you have to move the geom by the same translation vector (and not the reverse as I suggested before and as Daniel corrected), so that the forces applied to the body during a collision are applied with respect to the correct frame.  If you do that then you should end up with the same body/geom pair you would have if ODE supported non-origin centers of mass and you created the body and geom in the usual way and without mass translations or geom offsets.  But it would again be "a little to the right" (or left or whatever and assuming of course that you correctly draw the bunny model at the geom's offset position).  So if you'd want to get the exact same results in both cases (disregarding floating-point errors) you'd have to re-place the body "a little to the left".

Dimitris

Joshua Auerbach

unread,
Jun 13, 2012, 10:44:45 AM6/13/12
to ode-...@googlegroups.com
On 06/13/2012 06:47 AM, Dimitris Papavasiliou wrote:
> Perhaps you're already well aware of this but I'll mention it
> nevertheless. The position of the body is not really important with
> regards to its dynamics with the exception of collisions. if you do
> something to a body at some point P the body will respond in the same
> manner as if you had done it at Q. The results, for instance the
> trajectory of the body, should only be translated by P-Q but otherwise
> the same. This is in the absence of collisions of course. If the
> difference between the two points would lead the body to collide with
> some other body in one case but not in the other, or if they collide
> differently due to the translation like at a different angle say, then
> the results will differ of course.
Yes, I am aware of this, thanks.
>
> So when you translate the mass it's the same body really "only a
> little to the right" and with a different origin, so when you apply
> forces in local coordinates for example you have to take that into
> account, but otherwise it should be the same. That's why you have to
> move the geom by the same translation vector (and not the reverse as I
> suggested before and as Daniel corrected), so that the forces applied
> to the body during a collision are applied with respect to the correct
> frame. If you do that then you should end up with the same body/geom
> pair you would have if ODE supported non-origin centers of mass and
> you created the body and geom in the usual way and without mass
> translations or geom offsets. But it would again be "a little to the
> right" (or left or whatever and assuming of course that you correctly
> draw the bunny model at the geom's offset position). So if you'd want
> to get the exact same results in both cases (disregarding
> floating-point errors) you'd have to re-place the body "a little to
> the left".
So I think we are in agreement for the most part, but your statement
about drawing the bunny at the geom's offset position made me unsure if
I had this correct. I was just using the position from dGeomGetPosition
for my dsDrawTriangle calls, and this appears to be correct i.e. if I
drop a sphere it appears to interact with the bunny where I have it placed.

I am unsure of why this is the case though. As I said previously, in
order to get the correct position of a vertex in global coordinates
(using dBodyGetRelPointPos) I need to first apply the offset. So why do
I not need to apply the offset when drawing the triangles? What is the
difference between these two?

-Josh

Joshua Auerbach

unread,
Jun 13, 2012, 10:58:30 AM6/13/12
to ode-...@googlegroups.com
On 06/13/2012 01:39 AM, Daniel K. O. wrote:
> So the proper way to do it is:
>
> dGeomSetOffsetPosition(geom, -mass.c[0], -mass.c[1], -mass.c[2]);
> dMassTranslate(&mass, -mass.c[0], -mass.c[1], -mass.c[2]);
>
OK, good, this is what I have. I will note though that in order for
this to work dGeomSetBody has to be called before
dGeomSetOffsetPosition, while dBodySetMass has to be called after
dMassTranslate.

So it should be

geom = dCreateTrimesh(space, tmdata, 0, 0, 0);
dMassSetTrimesh(&mass, DENSITY, geom);
dGeomSetBody(geom, body);
dGeomSetOffsetPosition(geom, -mass.c[0], -mass.c[1], -mass.c[2]);
dMassTranslate(&mass, -mass.c[0], -mass.c[1], -mass.c[2]);
dBodySetMass(body,&mass);

It would be nice to get a proper version of this demo in svn (and fix
the indentation so it's not so confusing). What would I need to do to
submit these changes or do you want to take care of it?

-Josh

Dimitris Papavasiliou

unread,
Jun 13, 2012, 11:04:23 AM6/13/12
to ode-...@googlegroups.com

So I think we are in agreement for the most part, but your statement
about drawing the bunny at the geom's offset position made me unsure if
I had this correct.  I was just using the position from dGeomGetPosition
for my dsDrawTriangle calls, and this appears to be correct i.e. if I
drop a sphere it appears to interact with the bunny where I have it placed.

I am unsure of why this is the case though.  As I said previously, in
order to get the correct position of a vertex in global coordinates
(using dBodyGetRelPointPos) I need to first apply the offset.  So why do
I not need to apply the offset when drawing the triangles?  What is the
difference between these two?

I haven't used offsets so you better double-check but I would guess that if geom offsets are in effect then dGeomGetPosition returns the (correctly offset) geom position and dBodyGetPosition would return the (non-offset as offset apply to the geom only) body's position which should differ by the precvious exactly by the offset.  On the other hand dBodyGetRelPointPos, being related to the body calculates the point relative to the body's (non-offset) reference frame so you have to add the offset manually.  Again, I would consider this behavior a reasonable explanation of what you observe and the "obvious thing to do" but check with your actual code to make sure.

Dimitris

Joshua Auerbach

unread,
Jun 13, 2012, 11:12:18 AM6/13/12
to ode-...@googlegroups.com
On 06/13/2012 11:04 AM, Dimitris Papavasiliou wrote:

So I think we are in agreement for the most part, but your statement
about drawing the bunny at the geom's offset position made me unsure if
I had this correct.  I was just using the position from dGeomGetPosition
for my dsDrawTriangle calls, and this appears to be correct i.e. if I
drop a sphere it appears to interact with the bunny where I have it placed.

I am unsure of why this is the case though.  As I said previously, in
order to get the correct position of a vertex in global coordinates
(using dBodyGetRelPointPos) I need to first apply the offset.  So why do
I not need to apply the offset when drawing the triangles?  What is the
difference between these two?

I haven't used offsets so you better double-check but I would guess that if geom offsets are in effect then dGeomGetPosition returns the (correctly offset) geom position and dBodyGetPosition would return the (non-offset as offset apply to the geom only) body's position which should differ by the precvious exactly by the offset.  On the other hand dBodyGetRelPointPos, being related to the body calculates the point relative to the body's (non-offset) reference frame so you have to add the offset manually.  Again, I would consider this behavior a reasonable explanation of what you observe and the "obvious thing to do" but check with your actual code to make sure.

Dimitris

Ah, yes... thanks.  This seems to be correct.  dGeomGetPosition = dBodyGetPosition + dGeomGetOffsetPosition

The manual is wrong though, because it says for dGeomGetPosition "If the geom is attached to a body, the body's position / rotation pointers will be returned, i.e. the result will be identical to calling dBodyGetPosition or dBodyGetRotation."


Joshua Auerbach

unread,
Jun 13, 2012, 11:37:31 AM6/13/12
to ode-...@googlegroups.com
One last question on this stuff. I think it is all clear now in regards
to translations, but wondering if/when I would also need to be calling
dMassRotate?

Would this only be if I have some offset rotation (which I don't think I
will ever)? E.g. if I rotate the body does that get applied to the
mass, and does it matter if I rotate the body before/after I call
dBodySetMass?

Thanks!
Josh

Mikko Rasa

unread,
Jun 13, 2012, 12:04:15 PM6/13/12
to ode-...@googlegroups.com
The mass is defined in the body's local frame of reference. Rotating
the body means that its local frame rotates with respect to the global
frame. So yes, dMassRotate is only needed if you want the mass to match
a rotated geom.

Furthermore, the mass functions are able to initialize the mass aligned
to any major axis, while the geoms are always aligned to a particular
axis, so in certain special cases you might not need dMassRotate with a
rotated geom (e.g. a cylinder aligned to X or Y axis).

--
Mikko

Joshua Auerbach

unread,
Jun 13, 2012, 2:27:52 PM6/13/12
to ode-...@googlegroups.com
On 06/13/2012 12:04 PM, Mikko Rasa wrote:
> The mass is defined in the body's local frame of reference. Rotating
> the body means that its local frame rotates with respect to the global
> frame. So yes, dMassRotate is only needed if you want the mass to
> match a rotated geom.
>
> Furthermore, the mass functions are able to initialize the mass
> aligned to any major axis, while the geoms are always aligned to a
> particular axis, so in certain special cases you might not need
> dMassRotate with a rotated geom (e.g. a cylinder aligned to X or Y axis).
OK, great. Thanks.

Reply all
Reply to author
Forward
0 new messages