ODE.net - collision detection: strange error message

Post your questions, suggestions and experiences regarding game design, integration of external libraries here. For irrEdit, irrXML and irrKlang, see the
ambiera forums
Post Reply
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

ODE.net - collision detection: strange error message

Post by Tanuva »

Ive integrated the code from the ODE.NET-Collision-Detection howto with my irrlicht-setup. Atm I only have two boxes (CubeSceneNodes), one of them with geom and body so that its affected by gravity. the other is supposed to be a static object, so it only got a geom to do collisions with. But with the collision-code from the howto (which is only for collision of body-having objects, afaik), Tao.ODE says its getting invalid parameters for dAreConnectedExcluding right on the first calculated timestep, although the objects shouldnt intersect then - complete failure information here: http://pastebin.kubuntu-de.org/5331

Ive also tried with the bleeding edge odedotnet code from the svn repository, but it doesnt change anything. :(

My collision code: http://pastebin.kubuntu-de.org/5336
The OnCollision method is the same as in the howto.

May someone give a hint?
Tanuva
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

ConnectedToExcluding needs two bodies, as you only have one body it will fail. So do something like this:

Code: Select all

if(b1 == null || b2 == null)
{
	u.print("b1 oder b2 == null", true);
}
else
{
	if(b1.ConnectedToExcluding(b2, JointType.Contact))
		return;
}
ConnectedToExcluding is then only called when there are two bodies.
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

I have modified my code like you said, but it still produces the error... Another idea? :(

[Updated the pasted OnCollision method to match the changes.]
Tanuva
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

Hmm

If it really is the exact same error as before then remove ConnectedToExcluding and see if it works...

Also, is this valid?

Code: Select all

ContactGeom[] contactgeoms = e.Geom1.Collide(e.Geom2, 13);
Contact[] contact = new Contact[contactgeoms.Length];
I haven't actually used C# but if there are no contacts then wouldn't contactgeoms.Length be zero? In which case is it valid to create a new Contact array of zero size? :?:
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

Yes, its the same error.
Honestly, I don't really know what that code does, I've transcripted it from the ode.net-collision-detection-example and hoped it works out of the box. But I'm sure now the problem is caused by the supposed-to-be static object. The collision code wants to compare two bodies, but since the second object only has a geom, thats impossible. But what I dont understand then is why my "if(b1 == null || b2 == null)" isnt triggered... If I remove the static object, the code works - at least ode doesnt throw errors. So its somehow caused by the bodyless object. Having removed the code you mentioned, ode gives me this error message: http://pastebin.kubuntu-de.org/5468 - which leads me to the staticness once again as it seems to be thrown at line 16.
I basically know how collisions theoretically work in ode, but how may I get it working for such a static object, which is essential for having f.e. a ground to walk on top of...?
Tanuva
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

I just downloaded the ODE.net source.

It *seems* that when for example you call

Body b1 = e.Geom1.Body;

This actually creates a Body object, so it will *never* be null.

So instead, this body object has an attribute Handle of type IntPtr. Which perhaps you can test,

e.g.

if (b1.Handle == 0 || b2.Handle == 0)

(I'm not sure how C# actually uses pointers or what IntPtr actually is though... So maybe you don't compare to 0 or you use some method or something... Who knows.)

Look in Body.cs and BaseOdeResource.cs

(It's also possible I don't know what the hell I'm talking about, not ever having used C#. Be warned :evil: )

EDIT: Seems to check the pointers is
if (b1.Handle == IntPtr.Zero || b2.Handle == IntPtr.Zero)
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

Hey, you're genious! The body.Handle is what they had mentioned about the "ID" of a body in the original ODE FAQ, I just couldnt find such a property for the .net-body. I have completely moved the body-to-body collision code into the else-thing which already contains the b1.ConnectedToExcluding(...) thing, so that its only called if the handle of one of the bodies is != IntPtr.Zero. Runs perfectly smooth now and afaik until now, I just have to modify the code for the body-to-geom collisions so that it creates joints between the body and the surrounding space (what did they call it in the faq, cant remember the english expression...) instead of another (in this case non-existent) body.

Here's the actual code: http://pastebin.kubuntu-de.org/5489

Edit: Okay, simply changing the c.Attach(...) in line 35 from (b1, b2) to (b1, null) to have it being attached to the surrounding space didnt help much - now ode tells me about a failed assertion in dCollideBoxBox (the two objects have a box-shaped geom). At least I see that ode isnt that clearly arranged as I got the impression from the first examples... How do I get the "dynamic" object to collide with the "static" object properly?
[Why isnt there some documentation of odedotnet anywhere? The c++ one doesnt help at all...]
Tanuva
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

Edit: Okay, simply changing the c.Attach(...) in line 35 from (b1, b2) to (b1, null)
I don't think you need this. Just use c.Attach(b1, b2); as before. Bodies with IntPtr.zero handles are the same as the surrounding space...

This is the structure of my (c++) code:

Code: Select all

    dBodyID b1 = dGeomGetBody(o1);
    dBodyID b2 = dGeomGetBody(o2);
    
    // don't generate contacts if both are bodiless.
    // this is mainly to prevent intersecting static geoms (e.g. scenery) from hogging resources.
    // however in some cases this would be undesirable (e.g. you have non physically simulated objects
    // that you still want to detect collisions with... Ghosts maybe?)
    if ( !(b1 || b2) ) return;
    
    // If both geoms have bodies, which are joined by a non contact joint, then return.
    // e.g. could be useful for a ragdoll, if limbs overlap.
    if (b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact)) return;
    
    // array of available contact points
    const int MAX_CONTACTS = 12;
    dContact contact[MAX_CONTACTS];
    
    int numc = dCollide(o1, o2, MAX_CONTACTS, &contact[0].geom, sizeof(dContact));
    
    // No contacts
    if (numc == 0) return;
    
    // ignore ray collisions
    if ( (dGeomGetClass(o1) == dRayClass) || (dGeomGetClass(o2) == dRayClass))
    {
        return;
    }
    
    // for each contact, create an actual contact joint between two bodies
    // these will be removed after simulation stepping
    for (int i = 0; i < numc; i++)
    {
        contact[i].surface.mode =  dContactBounce | dContactSoftCFM;
        contact[i].surface.mu = 100;
        contact[i].surface.bounce = 0;
        contact[i].surface.bounce_vel = 0;
        contact[i].surface.soft_cfm = 0;
        
        dJointID c = dJointCreateContact(dWorld, dPerStepContactJointGroup, contact+i);
        dJointAttach(c, b1, b2);
    }
You should be able to do similar in C# of course with all that IntPtr.Zero stuff.
Cardinal4
Posts: 97
Joined: Sun Jun 11, 2006 1:20 am
Location: SG
Contact:

Post by Cardinal4 »

ODE dot net [Tao.ODE version] appears to be really outdated though - it's using ODE 0.5.

ODE.NET [ODE version], available from ode.org's sourceforge download page, is more up-to-date using ODE 0.8, though it has some stuff that's incomplete (like joint type params).
Sketches of a rambling mind
Still a long way on learning Irrlicht...
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

Ha! That must be the cause of the errors. Im using odedotnet with the tao.ode binaries that came with it, but with ode 0.8 from cvs. Likely they changed the API since 0.5... Gonna have a look at ODE.net, thanks for the tip!

Im rewriting the relevant code parts to match the original ode.net structure. Itsa pity that it doesnt have such a nice OO-architecture, but one cant have it all. :)
Tanuva
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

Now, here I come again.

First, the code: http://pastebin.kubuntu-de.org/5922

I've ported all of it to ode.net and after some trying (and unsuccessful searching for documentation or examples...), its running - except collision detection. There are various tutorials on that on the net, but they're all cpp and I have tried to port it to c#, with limited success. I cant really figure out what d.Collide expects as parameters. Because nearly everything is an IntPtr now, theres no data type checking anymore and I have to stick to ODE's error messages, which are (what have you expected?) not that helpful.
This is the actual error, referring to line 26 of my code:
ODE INTERNAL ERROR 1: assertion "skip >= (int)sizeof(dContactGeom)" failed in dCollideBoxBox()
I know that in the cpp-version the last parameter of dCollide is sizeof(*contactgeomarray*). Now I tried to imitate this value by using contactgeomarray.Length, but that doesnt do the job.
In the syntax-completion-help it says d.Collide wants these parameters:
IntPtr o1,
IntPtr o2,
int flags,
d.ContactGeom[] contact,
int skip
As you can see, I have filled an array of ContactGeoms with the ones of the contact-array and it at least doesnt provoke an error... Or is it supposed to be something else?
And what should I use for skip?

Very confused (but wishing for the final enlightenment),
Tanuva
Cardinal4
Posts: 97
Joined: Sun Jun 11, 2006 1:20 am
Location: SG
Contact:

Post by Cardinal4 »

I translated one of the box stack demos in the ode source, and this was how I did my collision testing, maybe it'll help you out:

Code: Select all

static void near(IntPtr space, IntPtr g1, IntPtr g2)
{
    IntPtr b1 = d.GeomGetBody(g1);
    IntPtr b2 = d.GeomGetBody(g2);
    if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
        return;
    int count = d.Collide(g1, g2, MAX_CONTACTS, contacts, d.ContactGeom.SizeOf);
    for (int i = 0; i < count; ++i)
    {
        contact.geom = contacts[i];
        IntPtr joint = d.JointCreateContact(world, contactgroup, ref contact);
        d.JointAttach(joint, b1, b2);
    }
}
MAX_CONTACTS is a int constant, contacts is a d.ContactGeom[], and contact is a d.Contact for the contact joint params. Your parameters should be correct.
Here's the complete translated demo source btw. I'm still trying to learn ODE by translating more C++ demos but I'm waiting for the next release of ODE.NET first; there's a [well, some] missing feature.
Sketches of a rambling mind
Still a long way on learning Irrlicht...
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

YEAH!
Finally, I found what was wrong:

Code: Select all

contact[i].geom = geoms[i];
(where geoms[] is the contactgeom[])
Was missing in the second for-loop, where the joints are created. Now the blocks collide with each other. Not that nice yet, but Im working on it.
Thanks you two! :)
Tanuva
Post Reply