diff --git a/Code/GamePhysics/Implementation/PhysicsAPI_Impl.cpp b/Code/GamePhysics/Implementation/PhysicsAPI_Impl.cpp index 614014e2..61bcb706 100644 --- a/Code/GamePhysics/Implementation/PhysicsAPI_Impl.cpp +++ b/Code/GamePhysics/Implementation/PhysicsAPI_Impl.cpp @@ -15,7 +15,7 @@ API_Impl API_instance; namespace { void OnPossibleCollision( Octree& worldScene, unsigned int protoTempRef, unsigned int deuterTempRef ) - { /** @todo TODO: OnPossibleCollision is a temporary solution .*/ + { auto proto = worldScene.GetCustomBody( protoTempRef ); auto deuter = worldScene.GetCustomBody( deuterTempRef ); @@ -26,13 +26,33 @@ namespace ICustomBody::State protoState; proto->GetState( protoState ); ICustomBody::State deuterState; deuter->GetState( deuterState ); - Float4 protoG = protoState.GetLinearMomentum(worldPointOfContact.xyz ), - deuterG = deuterState.GetLinearMomentum( worldPointOfContact.xyz ); + // calc from perspective of deuter. + Float4 normal = worldPointOfContact - Float4(deuterState.GetCenterPosition(), 1.0f ); // Init value is only borrowed + if( normal.Dot(normal) > 0.0f ) + { + deuter->GetNormalAt( worldPointOfContact, normal ); + } + else + { // special case: deuter is completly contained within proto or they have overlapping centers. + + normal = Float4( protoState.GetCenterPosition() - deuterState.GetCenterPosition(), 0.0f ); + if( normal.Dot(normal) == 0.0f ) + { // they have overlapping centers. Rebound at least + // calculate and store time interpolation value, for later rebound. + proto->SetTimeOfContact( worldPointOfContact ); + return; + } + + // borrowing the negated normal of proto. + proto->GetNormalAt( worldPointOfContact, normal ); + normal = -normal; + } + + Float4 protoG = protoState.GetLinearMomentum( worldPointOfContact.xyz ), + deuterG = deuterState.GetLinearMomentum( worldPointOfContact.xyz ); - // calc from perspective of deuter - Float4 normal; deuter->GetNormalAt( worldPointOfContact, normal ); Float protoG_Magnitude = protoG.Dot( normal ), - deuterG_Magnitude = deuterG.Dot( normal ); + deuterG_Magnitude = deuterG.Dot( normal ); // if they are not relatively moving towards eachother, there is no collision Float deltaPos = normal.Dot( Float4(deuterState.GetCenterPosition(), 1) - Float4(protoState.GetCenterPosition(), 1) ); @@ -65,25 +85,38 @@ namespace // bounce Float4 bounceD = normal * -Formula::CollisionResponse::Bounce( deuterState.GetRestitutionCoeff(), - deuterState.GetMass(), deuterG_Magnitude, - protoState.GetMass(), protoG_Magnitude ); + deuterState.GetMass(), deuterG_Magnitude, + protoState.GetMass(), protoG_Magnitude ); // calc from perspective of proto - proto->GetNormalAt( worldPointOfContact, normal ); - protoG_Magnitude = protoG.Dot( normal ), - deuterG_Magnitude = deuterG.Dot( normal ); + + normal = worldPointOfContact - Float4(protoState.GetCenterPosition(), 1.0f ); + if( normal.Dot(normal) > 0.0f ) + { + proto->GetNormalAt( worldPointOfContact, normal ); + protoG_Magnitude = protoG.Dot( normal ); + deuterG_Magnitude = deuterG.Dot( normal ); + } + else + { // special case: proto is completly contained within deuter. + // borrowing the negated normal of deuter. + deuter->GetNormalAt( worldPointOfContact, normal ); + normal = -normal; + protoG_Magnitude = -protoG_Magnitude; + deuterG_Magnitude = -deuterG_Magnitude; + } // bounce Float4 bounceP = normal * Formula::CollisionResponse::Bounce( protoState.GetRestitutionCoeff(), - protoState.GetMass(), protoG_Magnitude, - deuterState.GetMass(), deuterG_Magnitude ); + protoState.GetMass(), protoG_Magnitude, + deuterState.GetMass(), deuterG_Magnitude ); Float4 bounce = Average( bounceD, bounceP ); Float4 friction = Formula::CollisionResponse::Friction( protoG_Magnitude, normal, - Float4(protoState.GetLinearMomentum(), 0), protoState.GetFrictionCoeff_Static(), protoState.GetFrictionCoeff_Kinetic(), protoState.GetMass(), - Float4(deuterState.GetLinearMomentum(), 0), deuterState.GetFrictionCoeff_Static(), deuterState.GetFrictionCoeff_Kinetic(), deuterState.GetMass()); + Float4(protoState.GetLinearMomentum(), 0), protoState.GetFrictionCoeff_Static(), protoState.GetFrictionCoeff_Kinetic(), protoState.GetMass(), + Float4(deuterState.GetLinearMomentum(), 0), deuterState.GetFrictionCoeff_Static(), deuterState.GetFrictionCoeff_Kinetic(), deuterState.GetMass()); Float kineticEnergyPBefore = Oyster::Physics3D::Formula::LinearKineticEnergy( protoState.GetMass(), protoState.GetLinearMomentum()/protoState.GetMass() ); diff --git a/Code/GamePhysics/PhysicsStructs-Impl.h b/Code/GamePhysics/PhysicsStructs-Impl.h index 311b81f8..d3907b54 100644 --- a/Code/GamePhysics/PhysicsStructs-Impl.h +++ b/Code/GamePhysics/PhysicsStructs-Impl.h @@ -159,7 +159,12 @@ namespace Oyster inline ::Oyster::Math::Float3 CustomBodyState::GetLinearMomentum( const ::Oyster::Math::Float3 &at ) const { - return this->linearMomentum + ::Oyster::Physics3D::Formula::TangentialLinearMomentum( this->angularMomentum, at - this->centerPos ); + ::Oyster::Math::Float3 offset = at - this->centerPos; + if( offset.Dot(offset) > 0.0f ) + { + return this->linearMomentum + ::Oyster::Physics3D::Formula::TangentialLinearMomentum( this->angularMomentum, offset ); + } + return this->linearMomentum; } inline const ::Oyster::Math::Float3 & CustomBodyState::GetAngularMomentum() const