public virtual void ProcessTriangle(ObjectArray<Vector3> triangle, int partId, int triangleIndex) { TriangleShape triangleShape = new TriangleShape(triangle[0], triangle[1], triangle[2]); triangleShape.Margin = m_triangleCollisionMargin; VoronoiSimplexSolver simplexSolver = new VoronoiSimplexSolver(); GjkEpaPenetrationDepthSolver gjkEpaPenetrationSolver = new GjkEpaPenetrationDepthSolver(); //#define USE_SUBSIMPLEX_CONVEX_CAST 1 //if you reenable USE_SUBSIMPLEX_CONVEX_CAST see commented ref code below #if USE_SUBSIMPLEX_CONVEX_CAST SubsimplexConvexCast convexCaster = new SubsimplexConvexCast(m_convexShape, triangleShape, simplexSolver); #else //btGjkConvexCast convexCaster(m_convexShape,&triangleShape,&simplexSolver); ContinuousConvexCollision convexCaster = new ContinuousConvexCollision(m_convexShape,triangleShape,simplexSolver,gjkEpaPenetrationSolver); #endif //#USE_SUBSIMPLEX_CONVEX_CAST CastResult castResult = new CastResult(); castResult.m_fraction = 1f; if (convexCaster.CalcTimeOfImpact(ref m_convexShapeFrom,ref m_convexShapeTo,ref m_triangleToWorld, ref m_triangleToWorld, castResult)) { //add hit if (castResult.m_normal.LengthSquared() > 0.0001f) { if (castResult.m_fraction < m_hitFraction) { /* btContinuousConvexCast's normal is already in world space */ /* #ifdef USE_SUBSIMPLEX_CONVEX_CAST //rotate normal into worldspace castResult.m_normal = m_convexShapeFrom.getBasis() * castResult.m_normal; #endif //USE_SUBSIMPLEX_CONVEX_CAST */ castResult.m_normal.Normalize(); ReportHit (ref castResult.m_normal,ref castResult.m_hitPoint,castResult.m_fraction,partId,triangleIndex); } } } }
public void ProcessTriangle(ObjectArray<Vector3> triangle, int partId, int triangleIndex) { //do a swept sphere for now Matrix ident = Matrix.Identity; CastResult castResult = new CastResult(); castResult.m_fraction = m_hitFraction; SphereShape pointShape = new SphereShape(m_ccdSphereRadius); TriangleShape triShape = new TriangleShape(triangle[0],triangle[1],triangle[2]); VoronoiSimplexSolver simplexSolver = new VoronoiSimplexSolver(); SubSimplexConvexCast convexCaster = new SubSimplexConvexCast(pointShape,triShape,simplexSolver); //GjkConvexCast convexCaster(&pointShape,convexShape,&simplexSolver); //ContinuousConvexCollision convexCaster(&pointShape,convexShape,&simplexSolver,0); //local space? if (convexCaster.CalcTimeOfImpact(ref m_ccdSphereFromTrans,ref m_ccdSphereToTrans, ref ident,ref ident,castResult)) { if (m_hitFraction > castResult.m_fraction) { m_hitFraction = castResult.m_fraction; } } }
public override float CalculateTimeOfImpact(CollisionObject body0,CollisionObject body1,DispatcherInfo dispatchInfo,ManifoldResult resultOut) { ///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold ///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold ///body0.m_worldTransform, float resultFraction = 1.0f; float squareMot0 = (body0.GetInterpolationWorldTransform().Translation - body0.GetWorldTransform().Translation).LengthSquared(); float squareMot1 = (body1.GetInterpolationWorldTransform().Translation - body1.GetWorldTransform().Translation).LengthSquared(); if (squareMot0 < body0.GetCcdSquareMotionThreshold() && squareMot1 < body1.GetCcdSquareMotionThreshold()) { return resultFraction; } //An adhoc way of testing the Continuous Collision Detection algorithms //One object is approximated as a sphere, to simplify things //Starting in penetration should report no time of impact //For proper CCD, better accuracy and handling of 'allowed' penetration should be added //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies) /// Convex0 against sphere for Convex1 { ConvexShape convex0 = (ConvexShape)(body0.GetCollisionShape()); SphereShape sphere1 = new SphereShape(body1.GetCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation CastResult result = new CastResult(); VoronoiSimplexSolver voronoiSimplex = new VoronoiSimplexSolver(); //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); ///Simplification, one object is simplified as a sphere GjkConvexCast ccd1 = new GjkConvexCast( convex0 ,sphere1,voronoiSimplex); //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); if (ccd1.CalcTimeOfImpact(body0.GetWorldTransform(),body0.GetInterpolationWorldTransform(), body1.GetWorldTransform(),body1.GetInterpolationWorldTransform(),result)) { //store result.m_fraction in both bodies if (body0.GetHitFraction()> result.m_fraction) { body0.SetHitFraction( result.m_fraction ); } if (body1.GetHitFraction() > result.m_fraction) { body1.SetHitFraction( result.m_fraction); } if (resultFraction > result.m_fraction) { resultFraction = result.m_fraction; } } } /// Sphere (for convex0) against Convex1 { ConvexShape convex1 = (ConvexShape)(body1.GetCollisionShape()); SphereShape sphere0 = new SphereShape(body0.GetCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation CastResult result = new CastResult(); VoronoiSimplexSolver voronoiSimplex = new VoronoiSimplexSolver(); //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); ///Simplification, one object is simplified as a sphere GjkConvexCast ccd1 = new GjkConvexCast(sphere0,convex1,voronoiSimplex); //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); if (ccd1.CalcTimeOfImpact(body0.GetWorldTransform(),body0.GetInterpolationWorldTransform(), body1.GetWorldTransform(),body1.GetInterpolationWorldTransform(),result)) { //store result.m_fraction in both bodies if (body0.GetHitFraction() > result.m_fraction) { body0.SetHitFraction( result.m_fraction); } if (body1.GetHitFraction() > result.m_fraction) { body1.SetHitFraction( result.m_fraction); } if (resultFraction > result.m_fraction) { resultFraction = result.m_fraction; } } } return resultFraction; }
/// objectQuerySingle performs a collision detection query and calls the resultCallback. It is used internally by rayTest. public static void ObjectQuerySingle(ConvexShape castShape,ref Matrix convexFromTrans,ref Matrix convexToTrans, CollisionObject collisionObject,CollisionShape collisionShape, ref Matrix colObjWorldTransform, ConvexResultCallback resultCallback, float allowedPenetration) { if (collisionShape.IsConvex()) { //BT_PROFILE("convexSweepConvex"); CastResult castResult = new CastResult(); castResult.m_allowedPenetration = allowedPenetration; castResult.m_fraction = resultCallback.m_closestHitFraction;//float(1.);//?? ConvexShape convexShape = (ConvexShape) collisionShape; VoronoiSimplexSolver simplexSolver = new VoronoiSimplexSolver(); GjkEpaPenetrationDepthSolver gjkEpaPenetrationSolver = new GjkEpaPenetrationDepthSolver(); ContinuousConvexCollision convexCaster1 = new ContinuousConvexCollision(castShape,convexShape,simplexSolver, gjkEpaPenetrationSolver); //btGjkConvexCast convexCaster2(castShape,convexShape,&simplexSolver); //btSubsimplexConvexCast convexCaster3(castShape,convexShape,&simplexSolver); IConvexCast castPtr = convexCaster1; if (castPtr.CalcTimeOfImpact(ref convexFromTrans,ref convexToTrans,ref colObjWorldTransform,ref colObjWorldTransform,castResult)) { //add hit if (castResult.m_normal.LengthSquared() > 0.0001f) { if (castResult.m_fraction < resultCallback.m_closestHitFraction) { castResult.m_normal.Normalize(); LocalConvexResult localConvexResult = new LocalConvexResult ( collisionObject, null, ref castResult.m_normal, ref castResult.m_hitPoint, castResult.m_fraction ); bool normalInWorldSpace = true; resultCallback.AddSingleResult(localConvexResult, normalInWorldSpace); } } } } else { if (collisionShape.IsConcave()) { if (collisionShape.ShapeType==BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE) { //BT_PROFILE("convexSweepbtBvhTriangleMesh"); BvhTriangleMeshShape triangleMesh = (BvhTriangleMeshShape)collisionShape; Matrix worldTocollisionObject = Matrix.Invert(colObjWorldTransform); Vector3 convexFromLocal = Vector3.Transform(convexFromTrans.Translation,worldTocollisionObject); Vector3 convexToLocal = Vector3.Transform(convexToTrans.Translation,worldTocollisionObject); // rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation Matrix rotationXform = MathUtil.BasisMatrix(ref worldTocollisionObject) * MathUtil.BasisMatrix(ref convexToTrans); BridgeTriangleConvexcastCallback tccb = new BridgeTriangleConvexcastCallback(castShape, ref convexFromTrans,ref convexToTrans,resultCallback,collisionObject,triangleMesh, ref colObjWorldTransform); tccb.m_hitFraction = resultCallback.m_closestHitFraction; Vector3 boxMinLocal = new Vector3(); Vector3 boxMaxLocal = new Vector3(); castShape.GetAabb(ref rotationXform, ref boxMinLocal, ref boxMaxLocal); triangleMesh.PerformConvexCast(tccb,ref convexFromLocal,ref convexToLocal,ref boxMinLocal, ref boxMaxLocal); } else { //BT_PROFILE("convexSweepConcave"); ConcaveShape concaveShape = (ConcaveShape)collisionShape; Matrix worldTocollisionObject = Matrix.Invert(colObjWorldTransform); Vector3 convexFromLocal = Vector3.Transform(convexFromTrans.Translation,worldTocollisionObject); Vector3 convexToLocal = Vector3.Transform(convexToTrans.Translation,worldTocollisionObject); // rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation Matrix rotationXform = MathUtil.BasisMatrix(ref worldTocollisionObject) * MathUtil.BasisMatrix(ref convexToTrans); BridgeTriangleConvexcastCallback2 tccb = new BridgeTriangleConvexcastCallback2(castShape, ref convexFromTrans, ref convexToTrans, resultCallback, collisionObject, concaveShape, ref colObjWorldTransform); tccb.m_hitFraction = resultCallback.m_closestHitFraction; Vector3 boxMinLocal = new Vector3(); Vector3 boxMaxLocal = new Vector3(); castShape.GetAabb(ref rotationXform, ref boxMinLocal, ref boxMaxLocal); Vector3 rayAabbMinLocal = convexFromLocal; MathUtil.VectorMin(ref convexToLocal,ref rayAabbMinLocal); //rayAabbMinLocal.setMin(convexToLocal); Vector3 rayAabbMaxLocal = convexFromLocal; //rayAabbMaxLocal.setMax(convexToLocal); MathUtil.VectorMax(ref convexToLocal,ref rayAabbMaxLocal); rayAabbMinLocal += boxMinLocal; rayAabbMaxLocal += boxMaxLocal; concaveShape.ProcessAllTriangles(tccb,ref rayAabbMinLocal,ref rayAabbMaxLocal); } } else { ///@todo : use AABB tree or other BVH acceleration structure! if (collisionShape.IsCompound()) { //BT_PROFILE("convexSweepCompound"); CompoundShape compoundShape = (CompoundShape)collisionShape; for (int i=0;i<compoundShape.GetNumChildShapes();i++) { Matrix childTrans = compoundShape.GetChildTransform(i); CollisionShape childCollisionShape = compoundShape.GetChildShape(i); Matrix childWorldTrans = MathUtil.BulletMatrixMultiply(colObjWorldTransform,childTrans); // replace collision shape so that callback can determine the triangle CollisionShape saveCollisionShape = collisionObject.GetCollisionShape(); collisionObject.InternalSetTemporaryCollisionShape((CollisionShape)childCollisionShape); LocalInfoAdder my_cb = new LocalInfoAdder(i, resultCallback); my_cb.m_closestHitFraction = resultCallback.m_closestHitFraction; ObjectQuerySingle(castShape, ref convexFromTrans,ref convexToTrans, collisionObject, childCollisionShape, ref childWorldTrans, my_cb, allowedPenetration); // restore collisionObject.InternalSetTemporaryCollisionShape(saveCollisionShape); } } } } }
public virtual void RayTestSingle(ref Matrix rayFromTrans,ref Matrix rayToTrans, CollisionObject collisionObject, CollisionShape collisionShape, ref Matrix colObjWorldTransform, RayResultCallback resultCallback) { SphereShape pointShape = new SphereShape(0.0f); pointShape.Margin = 0f; ConvexShape castShape = pointShape; if (collisionShape.IsConvex()) { // BT_PROFILE("rayTestConvex"); CastResult castResult = new CastResult(); castResult.m_fraction = resultCallback.m_closestHitFraction; ConvexShape convexShape = (ConvexShape)collisionShape; VoronoiSimplexSolver simplexSolver = new VoronoiSimplexSolver(); //#define USE_SUBSIMPLEX_CONVEX_CAST 1 //#ifdef USE_SUBSIMPLEX_CONVEX_CAST // FIXME - MAN - convexcat here seems to make big difference to forklift. SubSimplexConvexCast convexCaster = new SubSimplexConvexCast(castShape, convexShape, simplexSolver); //GjkConvexCast convexCaster = new GjkConvexCast(castShape, convexShape, simplexSolver); //#else //btGjkConvexCast convexCaster(castShape,convexShape,&simplexSolver); //btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0); //#endif //#USE_SUBSIMPLEX_CONVEX_CAST if (convexCaster.CalcTimeOfImpact(ref rayFromTrans,ref rayToTrans,ref colObjWorldTransform,ref colObjWorldTransform,castResult)) { //add hit if (castResult.m_normal.LengthSquared() > 0.0001f) { if (castResult.m_fraction < resultCallback.m_closestHitFraction) { //if (resultCallback.m_closestHitFraction != 1f) //{ // int ibreak = 0; // convexCaster.calcTimeOfImpact(ref rayFromTrans, ref rayToTrans, ref colObjWorldTransform, ref colObjWorldTransform, castResult); //} //#ifdef USE_SUBSIMPLEX_CONVEX_CAST //rotate normal into worldspace castResult.m_normal = Vector3.TransformNormal(castResult.m_normal,rayFromTrans); //#endif //USE_SUBSIMPLEX_CONVEX_CAST castResult.m_normal.Normalize(); LocalRayResult localRayResult = new LocalRayResult( collisionObject, null, ref castResult.m_normal, castResult.m_fraction ); bool normalInWorldSpace = true; resultCallback.AddSingleResult(localRayResult, normalInWorldSpace); } } } castResult.Cleanup(); } else { if (collisionShape.IsConcave()) { // BT_PROFILE("rayTestConcave"); if (collisionShape.ShapeType==BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE && collisionShape is BvhTriangleMeshShape) { ///optimized version for btBvhTriangleMeshShape BvhTriangleMeshShape triangleMesh = (BvhTriangleMeshShape)collisionShape; Matrix worldTocollisionObject = Matrix.Invert(colObjWorldTransform); Vector3 rayFromLocal = Vector3.Transform(rayFromTrans.Translation,worldTocollisionObject); Vector3 rayToLocal = Vector3.Transform(rayToTrans.Translation,worldTocollisionObject); Matrix transform = Matrix.Identity; BridgeTriangleRaycastCallback rcb = new BridgeTriangleRaycastCallback(ref rayFromLocal,ref rayToLocal, resultCallback,collisionObject,triangleMesh,ref transform); rcb.m_hitFraction = resultCallback.m_closestHitFraction; triangleMesh.PerformRaycast(rcb,ref rayFromLocal,ref rayToLocal); rcb.Cleanup(); } else { //generic (slower) case ConcaveShape concaveShape = (ConcaveShape)collisionShape; Matrix worldTocollisionObject = Matrix.Invert(colObjWorldTransform); Vector3 rayFromLocal = Vector3.Transform(rayFromTrans.Translation,worldTocollisionObject); Vector3 rayToLocal = Vector3.Transform(rayToTrans.Translation,worldTocollisionObject); //ConvexCast::CastResult Matrix transform = Matrix.Identity; BridgeTriangleConcaveRaycastCallback rcb = new BridgeTriangleConcaveRaycastCallback(ref rayFromLocal, ref rayToLocal, resultCallback, collisionObject, concaveShape,ref transform); rcb.m_hitFraction = resultCallback.m_closestHitFraction; Vector3 rayAabbMinLocal = rayFromLocal; MathUtil.VectorMin(ref rayToLocal,ref rayAabbMinLocal); Vector3 rayAabbMaxLocal = rayFromLocal; MathUtil.VectorMax(ref rayToLocal,ref rayAabbMaxLocal); concaveShape.ProcessAllTriangles(rcb,ref rayAabbMinLocal,ref rayAabbMaxLocal); rcb.Cleanup(); } } else { // BT_PROFILE("rayTestCompound"); ///@todo: use AABB tree or other BVH acceleration structure, see btDbvt if (collisionShape.IsCompound()) { CompoundShape compoundShape = (CompoundShape)(collisionShape); int i=0; for (i=0;i<compoundShape.GetNumChildShapes();i++) { Matrix childTrans = compoundShape.GetChildTransform(i); CollisionShape childCollisionShape = compoundShape.GetChildShape(i); Matrix childWorldTrans = MathUtil.BulletMatrixMultiply(colObjWorldTransform,childTrans) ; // replace collision shape so that callback can determine the triangle CollisionShape saveCollisionShape = collisionObject.GetCollisionShape(); collisionObject.InternalSetTemporaryCollisionShape((CollisionShape)childCollisionShape); LocalInfoAdder2 my_cb = new LocalInfoAdder2(i, resultCallback); my_cb.m_closestHitFraction = resultCallback.m_closestHitFraction; RayTestSingle(ref rayFromTrans,ref rayToTrans, collisionObject, childCollisionShape, ref childWorldTrans, my_cb); // restore collisionObject.InternalSetTemporaryCollisionShape(saveCollisionShape); my_cb.cleanup(); } } } } }
public DefaultCollisionConfiguration(DefaultCollisionConstructionInfo constructionInfo) { m_simplexSolver = new VoronoiSimplexSolver(); m_pdSolver = new GjkEpaPenetrationDepthSolver(); //m_pdSolver = new MinkowskiPenetrationDepthSolver(); m_useEpaPenetrationAlgorithm = true; //#define USE_EPA 1 //#ifdef USE_EPA // mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16); // m_pdSolver = new (mem)btGjkEpaPenetrationDepthSolver; //#else // mem = btAlignedAlloc(sizeof(btMinkowskiPenetrationDepthSolver),16); // m_pdSolver = new (mem)btMinkowskiPenetrationDepthSolver; //#endif//USE_EPA //default CreationFunctions, filling the m_doubleDispatch table m_convexConvexCreateFunc = new ConvexConvexCreateFunc(m_simplexSolver,m_pdSolver); m_convexConcaveCreateFunc = new ConvexConcaveCreateFunc(); m_swappedConvexConcaveCreateFunc = new SwappedConvexConcaveCreateFunc(); m_compoundCreateFunc = new CompoundCreateFunc(); m_swappedCompoundCreateFunc = new SwappedCompoundCreateFunc(); m_emptyCreateFunc = new EmptyCreateFunc(); m_sphereSphereCF = new SphereSphereCreateFunc(); //#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM // mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16); // m_sphereBoxCF = new(mem) btSphereBoxCollisionAlgorithm::CreateFunc; // mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16); // m_boxSphereCF = new (mem)btSphereBoxCollisionAlgorithm::CreateFunc; // m_boxSphereCF->m_swapped = true; //#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM m_sphereTriangleCF = new SphereTriangleCreateFunc(); m_triangleSphereCF = new SphereTriangleCreateFunc(); m_triangleSphereCF.m_swapped = true; m_boxBoxCF = new BoxBoxCreateFunc(); //convex versus plane m_convexPlaneCF = new ConvexPlaneCreateFunc(); m_planeConvexCF = new ConvexPlaneCreateFunc(); m_planeConvexCF.m_swapped = true; ///calculate maximum element size, big enough to fit any collision algorithm in the memory pool //int maxSize = sizeof(btConvexConvexAlgorithm); //int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm); //int maxSize3 = sizeof(btCompoundCollisionAlgorithm); //int sl = sizeof(btConvexSeparatingDistanceUtil); //sl = sizeof(btGjkPairDetector); //int collisionAlgorithmMaxElementSize = btMax(maxSize,maxSize2); //collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3); //if (constructionInfo.m_stackAlloc) //{ // m_ownsStackAllocator = false; // this->m_stackAlloc = constructionInfo.m_stackAlloc; //} else //{ // m_ownsStackAllocator = true; // void* mem = btAlignedAlloc(sizeof(btStackAlloc),16); // m_stackAlloc = new(mem)btStackAlloc(constructionInfo.m_defaultStackAllocatorSize); //} //if (constructionInfo.m_persistentManifoldPool) //{ // m_ownsPersistentManifoldPool = false; // m_persistentManifoldPool = constructionInfo.m_persistentManifoldPool; //} else //{ // m_ownsPersistentManifoldPool = true; // void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); // m_persistentManifoldPool = new (mem) btPoolAllocator(sizeof(btPersistentManifold),constructionInfo.m_defaultMaxPersistentManifoldPoolSize); //} //if (constructionInfo.m_collisionAlgorithmPool) //{ // m_ownsCollisionAlgorithmPool = false; // m_collisionAlgorithmPool = constructionInfo.m_collisionAlgorithmPool; //} else //{ // m_ownsCollisionAlgorithmPool = true; // void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); // m_collisionAlgorithmPool = new(mem) btPoolAllocator(collisionAlgorithmMaxElementSize,constructionInfo.m_defaultMaxCollisionAlgorithmPoolSize); //} }