Closed jagoly closed 9 years ago
I think it is OK because we do not want to prevent only division by exactly zero but we also want to avoid division by very small numbers that cannot be represented by a float which will cause the result of the division to be +/- infinity.
You can take a look at this thread for instance : http://stackoverflow.com/questions/12825471/division-by-zero-prevention-checking-the-divisors-expression-doesnt-result-in
Perhaps, but if so, something is definitely still wrong. In my tests, I'm getting many different crashes from this. Surely it'd be more reasonable to just do a !=0.0 or inf test at each stage of the calculations? After all, as it is assertions are failing when they definitely should not - these small values are not getting into the engine directly from the user, but the engine itself is generating them.
I'm pretty sure that the test with 0.0 would be wrong. We need to use some epsilon here to avoid division by a very small number. However, maybe using the assert is not a really good idea. I think I will remove the assert and return a zero length vector if the length is very small.
This is what is done in Box2D for instance. Take a look at the b2Vec2::Normalize() method here.
Somewhat related I suppose, but another assert that is getting raised quite a lot for me is the on line 51 of https://github.com/DanielChappuis/reactphysics3d/blob/testbed/src/constraint/ContactPoint.cpp
About this assert in ContactPoint.cpp, do you have a full stack trace ? I would like to know where in the code a contact point with negative penetration depth is created.
Ok, I think this is what you wanted (sorry, never posted a stack trace before)
Edit: Hang on, this one doesn't look very useful, I'll try and get a better one
Thread 1 (Thread 0x7ffff7fbd900 (LWP 5740)):
#0 0x00007ffff6938cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
resultvar = 0
pid = 5740
selftid = 5740
#1 0x00007ffff693c0d8 in __GI_abort () at abort.c:89
save_stage = 2
act = {__sigaction_handler = {sa_handler = 0x7fffffffe81e, sa_sigaction = 0x7fffffffe81e}, sa_mask = {__val = {140737331588380, 6974784, 50, 4294967295, 140737330230499, 4294967296, 140737488346288, 51539598672, 140737488346704, 17674348, 0, 0, 0, 21474836480, 140737354072064, 140737331603504}}, sa_flags = 6974868, sa_restorer = 0x6a6e00 <reactphysics3d::ContactPoint::ContactPoint(reactphysics3d::ContactPointInfo const&)::__PRETTY_FUNCTION__>}
sigs = {__val = {32, 0 <repeats 15 times>}}
#2 0x00007ffff6931b86 in __assert_fail_base (fmt=0x7ffff6a82830 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x6a6d94 "mPenetrationDepth > 0.0", file=file@entry=0x6a6d40 "/home/jagoly/Projects/reactphysics3d/src/reactphysics3d/constraint/ContactPoint.cpp", line=line@entry=50, function=function@entry=0x6a6e00 <reactphysics3d::ContactPoint::ContactPoint(reactphysics3d::ContactPointInfo const&)::__PRETTY_FUNCTION__> "reactphysics3d::ContactPoint::ContactPoint(const reactphysics3d::ContactPointInfo&)") at assert.c:92
str = 0x14588dd0 "\260\242\036\001"
total = 4096
#3 0x00007ffff6931c32 in __GI___assert_fail (assertion=0x6a6d94 "mPenetrationDepth > 0.0", file=0x6a6d40 "/home/jagoly/Projects/reactphysics3d/src/reactphysics3d/constraint/ContactPoint.cpp", line=50, function=0x6a6e00 <reactphysics3d::ContactPoint::ContactPoint(reactphysics3d::ContactPointInfo const&)::__PRETTY_FUNCTION__> "reactphysics3d::ContactPoint::ContactPoint(const reactphysics3d::ContactPointInfo&)") at assert.c:101
No locals.
#4 0x0000000000642d92 in reactphysics3d::ContactPoint::ContactPoint (this=0x16aa8f28, contactInfo=...) at /home/jagoly/Projects/reactphysics3d/src/reactphysics3d/constraint/ContactPoint.cpp:50
No locals.
#5 0x000000000063dcee in reactphysics3d::CollisionDetection::createContact (this=0xccc6b8, overlappingPair=0x147cc138, contactInfo=0x10db040) at /home/jagoly/Projects/reactphysics3d/src/reactphysics3d/collision/CollisionDetection.cpp:406
contact = 0x147cc148
__PRETTY_FUNCTION__ = "void reactphysics3d::CollisionDetection::createContact(reactphysics3d::OverlappingPair*, const reactphysics3d::ContactPointInfo*)"
#6 0x000000000063d13d in reactphysics3d::CollisionDetection::computeNarrowPhase (this=0xccc6b8) at /home/jagoly/Projects/reactphysics3d/src/reactphysics3d/collision/CollisionDetection.cpp:229
contactInfo = 0x10db040
shape2 = 0x907e1c0
body2 = 0xa486660
isBody2Active = true
bodiesIndex = {first = 141, second = 156}
pair = 0x147cc138
narrowPhaseAlgorithm = @0xccc768: {_vptr.NarrowPhaseAlgorithm = 0x8f7d30 <vtable for reactphysics3d::SphereVsSphereAlgorithm+16>, mMemoryAllocator = @0xccc818, mCurrentOverlappingPair = 0x147cc138}
shape1 = 0x907dc98
body1 = 0xa485490
isBody1Active = true
it = {_M_node = 0x1268c10}
__PRETTY_FUNCTION__ = "void reactphysics3d::CollisionDetection::computeNarrowPhase()"
#7 0x000000000063c70a in reactphysics3d::CollisionDetection::computeCollisionDetection (this=0xccc6b8) at /home/jagoly/Projects/reactphysics3d/src/reactphysics3d/collision/CollisionDetection.cpp:63
No locals.
#8 0x0000000000659235 in reactphysics3d::DynamicsWorld::update (this=0xccc6b0, timeStep=0.0416666679) at /home/jagoly/Projects/reactphysics3d/src/reactphysics3d/engine/DynamicsWorld.cpp:117
No locals.
The scene that is causing this is fairly simple:
Each of these defines a Rigid Body: http://hastebin.com/banifoxelo.hs http://hastebin.com/desemovoka.hs http://hastebin.com/azikeranid.hs
I create one bigbox object at (0,0,0), and then 111 of the balls at (-3.f, 0.f, 1.f+num0.4f), and 111 of the dice at (3.f, 0.f, 1.f+num0.4f). I run the simulation at (1.f/24.f), have gravity set to (0,0,-1), velocity iterations set to 18 and position iterations set to 10. I use Z as my world space up axis.
Edit: if the problem doesn't show up, which it doesn't every time, then you can set the number of balls/dice to a higher number say 250, and eventually the problem will occur.
I've had lots of other scenes that eventually cause this to happen, but this is just one specific one that I've got right now. Not sure how I can really post a minimal example of this, as there is a lot involved, and my code base is quite large. You should be able to build a scene that demonstrates the issue from the above description though, if you need to.
Also, here is the program state when it crashes, hopefully it will be somewhat useful.
contactInfo @0x10db040 reactphysics3d::ContactPointInfo &
localPoint1 @0x10db060 reactphysics3d::Vector3
x 0.0835847855 reactphysics3d::decimal
y 0.0315114185 reactphysics3d::decimal
z 0.120501518 reactphysics3d::decimal
localPoint2 @0x10db06c reactphysics3d::Vector3
x -0.05452298 reactphysics3d::decimal
y -0.0761594623 reactphysics3d::decimal
z 0.117162205 reactphysics3d::decimal
normal @0x10db050 reactphysics3d::Vector3
x -0.972410023 reactphysics3d::decimal
y 0.233278275 reactphysics3d::decimal
z 2.88089109e-06 reactphysics3d::decimal
penetrationDepth 0 reactphysics3d::decimal
shape1 @0x907dc98 reactphysics3d::ProxyShape
mBody @0xa485490 reactphysics3d::RigidBody
[reactphysics3d::CollisionB...] @0xa485490 reactphysics3d::CollisionBody
[reactphysics3d::Body] @0xa485490 reactphysics3d::Body
[vptr] 0x8f7910 <vtable for reactphysics3d::RigidBody+16>
mID 141 reactphysics3d::bodyindex
mIsActive true bool
mIsAllowedToSleep true bool
mIsAlreadyInIsland true bool
mIsSleeping false bool
mSleepTime 0 reactphysics3d::decimal
mUserData 0x0 void *
mContactManifoldsList @0x11f8250 reactphysics3d::ContactManifoldListElement
contactManifold @0x11c0878 reactphysics3d::ContactManifold
mContactPoints @0x11c0888 reactphysics3d::ContactPoint *[4]
[0] @0x16aabfe8 reactphysics3d::ContactPoint
mBody1 @0x90818b0 reactphysics3d::RigidBody
[reactphysics3d::CollisionB...] @0x90818b0 reactphysics3d::CollisionBody
[reactphysics3d::Body] @0x90818b0 reactphysics3d::Body
[vptr] 0x8f7910 <vtable for reactphysics3d::RigidBody+16>
mID 0 reactphysics3d::bodyindex
mIsActive true bool
mIsAllowedToSleep true bool
mIsAlreadyInIsland false bool
mIsSleeping false bool
mSleepTime 0 reactphysics3d::decimal
mUserData 0x0 void *
mContactManifoldsList @0x11f8740 reactphysics3d::ContactManifoldListElement
mNbCollisionShapes 5 reactphysics3d::uint
mProxyCollisionShapes @0x907ac20 reactphysics3d::ProxyShape
mTransform @0x90818d4 reactphysics3d::Transform
mType reactphysics3d::STATIC (0) reactphysics3d::BodyType
mWorld @0xccc6b0 reactphysics3d::DynamicsWorld &
mAngularDamping 0 reactphysics3d::decimal
mAngularVelocity @0x9081938 reactphysics3d::Vector3
mCenterOfMassLocal @0x9081914 reactphysics3d::Vector3
mCenterOfMassWorld @0x9081920 reactphysics3d::Vector3
mExternalForce @0x9081944 reactphysics3d::Vector3
mExternalTorque @0x9081950 reactphysics3d::Vector3
mInertiaTensorLocal @0x9081960 reactphysics3d::Matrix3x3
mInertiaTensorLocalInverse @0x9081990 reactphysics3d::Matrix3x3
mInitMass 0 reactphysics3d::decimal
mIsGravityEnabled true bool
mJointsList 0x0 reactphysics3d::JointListElement *
mLinearDamping 0 reactphysics3d::decimal
mLinearVelocity @0x908192c reactphysics3d::Vector3
mMassInverse 0 reactphysics3d::decimal
mMaterial @0x90819c8 reactphysics3d::Material
mBody2 @0xa485490 reactphysics3d::RigidBody
mFrictionImpulse1 0 reactphysics3d::decimal
mFrictionImpulse2 0 reactphysics3d::decimal
mFrictionVectors @0x16aac03c reactphysics3d::Vector3 [2]
mIsRestingContact true bool
mLocalPointOnBody1 @0x16aac008 reactphysics3d::Vector3
mLocalPointOnBody2 @0x16aac014 reactphysics3d::Vector3
mNormal @0x16aabff8 reactphysics3d::Vector3
mPenetrationDepth 0.00653360737 reactphysics3d::decimal
mPenetrationImpulse 0 reactphysics3d::decimal
mWorldPointOnBody1 @0x16aac020 reactphysics3d::Vector3
mWorldPointOnBody2 @0x16aac02c reactphysics3d::Vector3
[1] @0x16a7eb90 reactphysics3d::ContactPoint
[2] @0x16a7eb90 reactphysics3d::ContactPoint
[3] @0x730 reactphysics3d::ContactPoint
mFrictionImpulse1 0.00110250153 reactphysics3d::decimal
mFrictionImpulse2 -8.15459558e-08 reactphysics3d::decimal
mFrictionTwistImpulse 3.59582386e-09 reactphysics3d::decimal
mFrictionVector1 @0x11c08ac reactphysics3d::Vector3
mFrictionVector2 @0x11c08b8 reactphysics3d::Vector3
mIsAlreadyInIsland true bool
mMemoryAllocator @0xccc818 reactphysics3d::MemoryAllocator &
mNbContactPoints 2 reactphysics3d::uint
mShape1 @0x907aac0 reactphysics3d::ProxyShape
mShape2 @0x907dc98 reactphysics3d::ProxyShape
next 0x0 reactphysics3d::ContactManifoldListElement *
mNbCollisionShapes 1 reactphysics3d::uint
mProxyCollisionShapes @0x907dc98 reactphysics3d::ProxyShape
mTransform @0xa4854b4 reactphysics3d::Transform
mType reactphysics3d::DYNAMIC (2) reactphysics3d::BodyType
mWorld @0xccc6b0 reactphysics3d::DynamicsWorld &
mAngularDamping 0.899999976 reactphysics3d::decimal
mAngularVelocity @0xa485518 reactphysics3d::Vector3
mCenterOfMassLocal @0xa4854f4 reactphysics3d::Vector3
mCenterOfMassWorld @0xa485500 reactphysics3d::Vector3
mExternalForce @0xa485524 reactphysics3d::Vector3
mExternalTorque @0xa485530 reactphysics3d::Vector3
mInertiaTensorLocal @0xa485540 reactphysics3d::Matrix3x3
mInertiaTensorLocalInverse @0xa485570 reactphysics3d::Matrix3x3
mInitMass 0.600000024 reactphysics3d::decimal
mIsGravityEnabled true bool
mJointsList 0x0 reactphysics3d::JointListElement *
mLinearDamping 0.300000012 reactphysics3d::decimal
mLinearVelocity @0xa48550c reactphysics3d::Vector3
mMassInverse 1.66666663 reactphysics3d::decimal
mMaterial @0xa4855a8 reactphysics3d::Material
mBroadPhaseID 289 int
mCachedCollisionData 0x0 void *
mCollideWithMaskBits 65535 unsigned short
mCollisionCategoryBits 1 unsigned short
mCollisionShape @0xcb23d90 reactphysics3d::SphereShape
mLocalToBodyTransform @0x907dca8 reactphysics3d::Transform
mMass 0.600000024 reactphysics3d::decimal
mNext 0x0 reactphysics3d::ProxyShape *
mUserData 0x0 void *
shape2 @0x907e1c0 reactphysics3d::ProxyShape
this @0x16aa8f28 reactphysics3d::ContactPoint
mBody1 @0xa485490 reactphysics3d::RigidBody
[reactphysics3d::CollisionB...] @0xa485490 reactphysics3d::CollisionBody
mAngularDamping 0.899999976 reactphysics3d::decimal
mAngularVelocity @0xa485518 reactphysics3d::Vector3
mCenterOfMassLocal @0xa4854f4 reactphysics3d::Vector3
mCenterOfMassWorld @0xa485500 reactphysics3d::Vector3
mExternalForce @0xa485524 reactphysics3d::Vector3
mExternalTorque @0xa485530 reactphysics3d::Vector3
mInertiaTensorLocal @0xa485540 reactphysics3d::Matrix3x3
mInertiaTensorLocalInverse @0xa485570 reactphysics3d::Matrix3x3
mInitMass 0.600000024 reactphysics3d::decimal
mIsGravityEnabled true bool
mJointsList 0x0 reactphysics3d::JointListElement *
mLinearDamping 0.300000012 reactphysics3d::decimal
mLinearVelocity @0xa48550c reactphysics3d::Vector3
mMassInverse 1.66666663 reactphysics3d::decimal
mMaterial @0xa4855a8 reactphysics3d::Material
mBody2 @0xa486660 reactphysics3d::RigidBody
mFrictionImpulse1 0 reactphysics3d::decimal
mFrictionImpulse2 0 reactphysics3d::decimal
mFrictionVectors @0x16aa8f7c reactphysics3d::Vector3 [2]
[0] @0x16aa8f7c reactphysics3d::Vector3
x 0 reactphysics3d::decimal
y 0 reactphysics3d::decimal
z 0 reactphysics3d::decimal
[1] @0x16aa8f88 reactphysics3d::Vector3
x 0 reactphysics3d::decimal
y 0 reactphysics3d::decimal
z 0 reactphysics3d::decimal
mIsRestingContact false bool
mLocalPointOnBody1 @0x16aa8f48 reactphysics3d::Vector3
mLocalPointOnBody2 @0x16aa8f54 reactphysics3d::Vector3
mNormal @0x16aa8f38 reactphysics3d::Vector3
mPenetrationDepth 0 reactphysics3d::decimal
mPenetrationImpulse 0 reactphysics3d::decimal
mWorldPointOnBody1 @0x16aa8f60 reactphysics3d::Vector3
mWorldPointOnBody2 @0x16aa8f6c reactphysics3d::Vector3
Does the crash happen at the beginning of the simulation or after some time ? Are you sure that your bodies does not collide in their initial positions at the beginning ?
Probably not related to this issue but if you are working on a real-time application, you should probably use 1/60.0f for your timestep. It will result in a more precise simulation. By doing this, you might need to reduce the number of velocity iterations to something around 10 and position iterations to something around 5 if your application is running too slow.
1: No, always after some time, but not always the same amount of some. Sometimes it doesn't happen at all. Related to this, is RP3D designed to always get the same results given the same input? As in, if you run a simulation multiple times, each one should run exactly the same? It does seem to do that most of the time, but occasionally, the sim will run completely differently.
2: I run it at 1/24.f because that is the same speed that I run all of my other logic at, so it fits in nicely with the rest of my engine. As it is, I don't seem to be having any accuracy issues. Also to note is that I have tried running the sim slower (1/60 up to 1/300) and all of the issues I've brought up occur then as well.
Did you change the default collision margin of the shapes ?
Your scene looks like the one in the "CollisionShapes" example of ReactPhysics3D. Maybe you can compare your code with this example to see what are the differences ?
no, I've not changed the collision margins at all. The settings I listed are the only ones changed, everything else is default.
I have made modifications in getUnit() and normalize() methods of Vector2 and Vector3 classes to handle division by zero in a better way. I have also removed the assert tests here because we simply do not want a zero vector to be normalized at all instead of getting an assert error.
This change has been made in commit 8a26d8a0ca72ab2f1211902f7c5551adedb8ff16 in the develop branch. This will be available in the next release of the library.
As one example, see the getUnit method of Vector3. It has the line
assert(lengthVector > MACHINE_EPSILON)
. This causes an error when the length is less than that value, which does not seem like what we want. Instead, it should just test that the length is non-zero, as zero can be represented exactly by all floating point numbers.