yoshinoToylogic / bulletsharp

Automatically exported from code.google.com/p/bulletsharp
MIT License
0 stars 0 forks source link

ContactTest not working due to repeated ObjectTable::Add calls throwing on duplicate keys. (Called in BroadphaseProxy ctor) #38

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
I am simply trying to do a manual (on demand) collision test, using 
ContactTest.  (It is for a drag select / rubber banding, in case you're 
curious.)

(I am also looking at using a GhostObject/PairCachingGhostObject and adding it 
and removing it right away -- maybe that's better? Although I'm not sure if it 
is generating contacts as the Bullet wiki suggests.)

What steps will reproduce the problem?
1.

  class MyClass
  {
        MyContactResultCallback callback = new MyContactResultCallback();
        CollisionObject contactTestObject = new CollisionObject();

     public override IEnumerable<IEntity> GetEntitiesInBox(Vector3 p1, Vector3 p2, Predicate<IEntity> filter = null)
        {
            contactTestObject.CollisionShape = new BoxShape(
                System.Math.Abs(p2.x - p1.x),
                System.Math.Abs(p2.y - p1.y),
                System.Math.Abs(p2.z - p1.z)
                );

            contactTestObject.UserObject = new object();
            contactTestObject.WorldTransform.SetTrans((p1 + p2) / 2f);

            callback.Filter = filter;

            try
            {
                physicsWorld.World.ContactTest(contactTestObject, callback);

            }
            catch (Exception ex)
            {
                l.Error(ex.ToString());
            }
        }
   }

2. Invoke GetEntitiesInBox.  It works the first time.

3. Invoke GetEntitiesInBox again.  It fails subsequent times with this 
exception and stack trace:

ArgumentException - "An item with the same key has already been added."
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at BulletSharp.ObjectTable.Add(Object obj, Void* unmanagedPointer)
   at BulletSharp.BroadphaseProxy..ctor(btBroadphaseProxy* proxy)
   at BulletSharp.ContactResultCallbackWrapper.needsCollision(ContactResultCallbackWrapper* , btBroadphaseProxy* proxy0)
   at btCollisionWorld.contactTest(btCollisionWorld* , btCollisionObject* , ContactResultCallback* )
   at BulletSharp.CollisionWorld.ContactTest(CollisionObject colObj, ContactResultCallback resultCallback)
   at LionFire.Valor.Controllers.BulletPhysicsController`1.GetEntitiesInBox(Vector3 p1, Vector3 p2, Predicate`1 filter) in d:\Valor\Valor\Valor.Core\Physics\BulletPhysicsController.cs:line 415

What version of the product are you using? On what operating system?
Version: 2.80, Windows 7 x64

Additional info:

 public class MyContactResultCallback : BulletSharp.CollisionWorld.ContactResultCallback
     {
            public override bool NeedsCollision(BroadphaseProxy proxy0)
            {
                try
                {
                    return true;
                    //return base.NeedsCollision(proxy0);
                }
                catch (Exception ex)
                {
                    l.Error("EntityContactResultCallback: base.NeedsCollision threw exception: " +ex.ToString());
                    return true;
                }
            }

            // ...

            public override float AddSingleResult(ManifoldPoint cp, CollisionObject colObj0, int partId0, int index0, CollisionObject colObj1, int partId1, int index1) { ... }
     }

One idea for suggested fix:
 In ObjectTable::Add, do a check to see if item is in table, and if so, do nothing (unless the value in the table differs, then either replace it or throw an exception.)

Original issue reported on code.google.com by jared.ac...@thirsk.ca on 23 Mar 2012 at 12:27

GoogleCodeExporter commented 8 years ago
Note: The GhostObject approach (add it, check OverlappingPairs, remove it) 
seems to work fine so I'm going with that.

Original comment by jared.ac...@thirsk.ca on 23 Mar 2012 at 2:03

GoogleCodeExporter commented 8 years ago
Yep, I was calling the BroadphaseProxy constructor instead of looking from the 
object table first. I don't want to put this check into ObjectTable::Add, 
because there may be cases where it's already known that the object is not in 
the table. Dictionary::Add will throw an exception anyway, so it's okay.

Can you try out the latest trunk? Soon there should be a 2.80 SP1 release as 
well.

Thanks!

Original comment by andres.traks on 24 Mar 2012 at 10:51

GoogleCodeExporter commented 8 years ago
Looks good.  My build environment isn't set up so I haven't been able to verify 
the fix, but I'll definitely try a binary release (I'm using Mogre).

Original comment by jthi...@gmail.com on 29 Mar 2012 at 8:42