diff --git a/Code/GamePhysics/GamePhysics.vcxproj b/Code/GamePhysics/GamePhysics.vcxproj index 06e64fd1..1abcc6f8 100644 --- a/Code/GamePhysics/GamePhysics.vcxproj +++ b/Code/GamePhysics/GamePhysics.vcxproj @@ -166,6 +166,8 @@ + + diff --git a/Code/GamePhysics/GamePhysics.vcxproj.filters b/Code/GamePhysics/GamePhysics.vcxproj.filters index 15221691..aa3cbd73 100644 --- a/Code/GamePhysics/GamePhysics.vcxproj.filters +++ b/Code/GamePhysics/GamePhysics.vcxproj.filters @@ -42,6 +42,12 @@ Header Files\Include + + Header Files\Include + + + Header Files\Include + diff --git a/Code/GamePhysics/Implementation/Octree.cpp b/Code/GamePhysics/Implementation/Octree.cpp index b841b49d..a1ccdbd8 100644 --- a/Code/GamePhysics/Implementation/Octree.cpp +++ b/Code/GamePhysics/Implementation/Octree.cpp @@ -31,6 +31,7 @@ Octree& Octree::operator=(const Octree& orig) void Octree::AddObject(UniquePointer< ICustomBody > customBodyRef) { + customBodyRef->SetScene( this ); Data data; //Data* tempPtr = this->worldNode.dataPtr; diff --git a/Code/GamePhysics/Implementation/PhysicsAPI_Impl.cpp b/Code/GamePhysics/Implementation/PhysicsAPI_Impl.cpp index 46b3369c..f917407b 100644 --- a/Code/GamePhysics/Implementation/PhysicsAPI_Impl.cpp +++ b/Code/GamePhysics/Implementation/PhysicsAPI_Impl.cpp @@ -4,10 +4,10 @@ #include "SphericalRigidBody.h" using namespace ::Oyster::Physics; -using namespace ::Oyster::Physics3D; using namespace ::Oyster::Math; using namespace ::Oyster::Collision3D; using namespace ::Utility::DynamicMemory; +using namespace ::Utility::Value; API_Impl API_instance; @@ -18,40 +18,70 @@ namespace auto proto = worldScene.GetCustomBody( protoTempRef ); auto deuter = worldScene.GetCustomBody( deuterTempRef ); - float deltaWhen; - Float3 worldWhere; - if( proto->Intersects(*deuter, 1.0f, deltaWhen, worldWhere) ) + Float4 worldPointOfContact; + if( proto->Intersects(*deuter, worldPointOfContact) ) { - proto->CallSubscription( proto, deuter ); + switch( proto->CallSubscription(proto, deuter) ) + { + case ICustomBody::SubscriptMessage_ignore_collision_response: + break; + default: + { // Apply CollisionResponse in pure gather pattern + ICustomBody::State protoState; proto->GetState( protoState ); + ICustomBody::State deuterState; deuter->GetState( deuterState ); + + Float4 protoG = protoState.GetLinearMomentum( worldPointOfContact ), + deuterG = deuterState.GetLinearMomentum( worldPointOfContact ); + + // calc from perspective of deuter + Float4 normal; deuter->GetNormalAt( worldPointOfContact, normal ); + Float protoG_Magnitude = protoG.Dot( normal ), + deuterG_Magnitude = deuterG.Dot( normal ); + + // bounce + Float4 bounceD = normal * -Formula::CollisionResponse::Bounce( deuterState.GetRestitutionCoeff(), + deuterState.GetMass(), deuterG_Magnitude, + protoState.GetMass(), protoG_Magnitude ); + + //sumJ -= Formula::CollisionResponse::Friction( impulse, normal, + // protoState.GetLinearMomentum(), protoState.GetFrictionCoeff_Static(), protoState.GetFrictionCoeff_Kinetic(), protoState.GetMass(), + // deuterState.GetLinearMomentum(), deuterState.GetFrictionCoeff_Static(), deuterState.GetFrictionCoeff_Kinetic(), deuterState.GetMass()); + + // calc from perspective of proto + proto->GetNormalAt( worldPointOfContact, normal ); + protoG_Magnitude = protoG.Dot( normal ), + deuterG_Magnitude = deuterG.Dot( normal ); + + // bounce + Float4 bounceP = normal * Formula::CollisionResponse::Bounce( protoState.GetRestitutionCoeff(), + protoState.GetMass(), protoG_Magnitude, + deuterState.GetMass(), deuterG_Magnitude ); + + Float4 bounce = Average( bounceD, bounceP ); + //Float4 bounce = bounceD + bounceP; + + // FRICTION + // Apply + //sumJ += ( 1 / deuterState.GetMass() )*frictionImpulse; + // FRICTION END + + Float4 forwardedDeltaPos, forwardedDeltaAxis; + { // @todo TODO: is this right? + Float4 bounceAngularImpulse = ::Oyster::Math::Float4( (worldPointOfContact - protoState.GetCenterPosition()).xyz.Cross(bounce.xyz), 0.0f ), + bounceLinearImpulse = bounce - bounceAngularImpulse; + proto->Predict( forwardedDeltaPos, forwardedDeltaAxis, bounceLinearImpulse, bounceAngularImpulse, API_instance.GetFrameTimeLength() ); + } + + protoState.ApplyForwarding( forwardedDeltaPos, forwardedDeltaAxis ); + protoState.ApplyImpulse( bounce, worldPointOfContact, normal ); + proto->SetState( protoState ); + } + break; + } } } } -Float4x4 & MomentOfInertia::CreateSphereMatrix( const Float mass, const Float radius, ::Oyster::Math::Float4x4 &targetMem ) -{ - return targetMem = Formula::MomentOfInertia::Sphere(mass, radius); -} - -Float4x4 & MomentOfInertia::CreateHollowSphereMatrix( const Float mass, const Float radius, ::Oyster::Math::Float4x4 &targetMem ) -{ - return targetMem = Formula::MomentOfInertia::HollowSphere(mass, radius); -} - -Float4x4 & MomentOfInertia::CreateCuboidMatrix( const Float mass, const Float height, const Float width, const Float depth, ::Oyster::Math::Float4x4 &targetMem ) -{ - return targetMem = Formula::MomentOfInertia::Cuboid(mass, height, width, depth); -} - -Float4x4 & MomentOfInertia::CreateCylinderMatrix( const Float mass, const Float height, const Float radius, ::Oyster::Math::Float4x4 &targetMem ) -{ - return targetMem = Formula::MomentOfInertia::Cylinder(mass, height, radius); -} - -Float4x4 & MomentOfInertia::CreateRodMatrix( const Float mass, const Float length, ::Oyster::Math::Float4x4 &targetMem ) -{ - return targetMem = Formula::MomentOfInertia::RodCenter(mass, length); -} - API & API::Instance() { return API_instance; @@ -95,12 +125,23 @@ void API_Impl::SetSubscription( API::EventAction_Destruction functionPointer ) } } +float API_Impl::GetFrameTimeLength() const +{ + return this->updateFrameLength; +} + void API_Impl::Update() { /** @todo TODO: Update is a temporary solution .*/ + + + ::std::vector updateList; auto proto = this->worldScene.Sample( Universe(), updateList ).begin(); for( ; proto != updateList.end(); ++proto ) { + // Step 1: @todo TODO: Apply Gravity + + // Step 2: Apply Collision Response this->worldScene.Visit( *proto, OnPossibleCollision ); } @@ -151,101 +192,91 @@ void API_Impl::DestroyObject( const ICustomBody* objRef ) } } -void API_Impl::ApplyForceAt( const ICustomBody* objRef, const Float3 &worldPos, const Float3 &worldF ) -{ - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - //this->worldScene.GetCustomBody( tempRef )->Apply //!< @todo TODO: need function - this->worldScene.SetAsAltered( tempRef ); - } -} - -void API_Impl::ApplyCollisionResponse( const ICustomBody* objRefA, const ICustomBody* objRefB, Float &deltaWhen, Float3 &worldPointOfContact ) -{ - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRefA ); - if( tempRef != this->worldScene.invalid_ref ) - { - //! @todo TODO: implement stub - this->worldScene.SetAsAltered( tempRef ); - } -} - -void API_Impl::SetMomentOfInertiaTensor_KeepVelocity( const ICustomBody* objRef, const Float4x4 &localI ) -{ // deprecated - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - this->worldScene.GetCustomBody( tempRef )->SetMomentOfInertiaTensor_KeepVelocity( localI ); - } -} - -void API_Impl::SetMomentOfInertiaTensor_KeepMomentum( const ICustomBody* objRef, const Float4x4 &localI ) -{ // deprecated - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - this->worldScene.GetCustomBody( tempRef )->SetMomentOfInertiaTensor_KeepMomentum( localI ); - } -} - -void API_Impl::SetMass_KeepVelocity( const ICustomBody* objRef, Float m ) -{ // deprecated - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - this->worldScene.GetCustomBody( tempRef )->SetMass_KeepVelocity( m ); - } -} - -void API_Impl::SetMass_KeepMomentum( const ICustomBody* objRef, Float m ) -{ // deprecated - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - this->worldScene.GetCustomBody( tempRef )->SetMass_KeepMomentum( m ); - } -} - -void API_Impl::SetCenter( const ICustomBody* objRef, const Float3 &worldPos ) -{ - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - //this->worldScene.GetCustomBody( tempRef )->Set //!< @todo TODO: need function - this->worldScene.EvaluatePosition( tempRef ); - } -} - -void API_Impl::SetRotation( const ICustomBody* objRef, const Float4x4 &rotation ) -{ - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - this->worldScene.GetCustomBody( tempRef )->SetRotation( rotation ); - this->worldScene.EvaluatePosition( tempRef ); - } -} - -void API_Impl::SetOrientation( const ICustomBody* objRef, const Float4x4 &orientation ) -{ - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - this->worldScene.GetCustomBody( tempRef )->SetOrientation( orientation ); - this->worldScene.EvaluatePosition( tempRef ); - } -} - -void API_Impl::SetSize( const ICustomBody* objRef, const Float3 &size ) -{ - unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); - if( tempRef != this->worldScene.invalid_ref ) - { - this->worldScene.GetCustomBody( tempRef )->SetSize( size ); - this->worldScene.EvaluatePosition( tempRef ); - } -} +//void API_Impl::ApplyForceAt( const ICustomBody* objRef, const Float3 &worldPos, const Float3 &worldF ) +//{ +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// //this->worldScene.GetCustomBody( tempRef )->Apply //!< @todo TODO: need function +// this->worldScene.SetAsAltered( tempRef ); +// } +//} +// +//void API_Impl::SetMomentOfInertiaTensor_KeepVelocity( const ICustomBody* objRef, const Float4x4 &localI ) +//{ // deprecated +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// this->worldScene.GetCustomBody( tempRef )->SetMomentOfInertiaTensor_KeepVelocity( localI ); +// } +//} +// +//void API_Impl::SetMomentOfInertiaTensor_KeepMomentum( const ICustomBody* objRef, const Float4x4 &localI ) +//{ // deprecated +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// this->worldScene.GetCustomBody( tempRef )->SetMomentOfInertiaTensor_KeepMomentum( localI ); +// } +//} +// +//void API_Impl::SetMass_KeepVelocity( const ICustomBody* objRef, Float m ) +//{ // deprecated +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// this->worldScene.GetCustomBody( tempRef )->SetMass_KeepVelocity( m ); +// } +//} +// +//void API_Impl::SetMass_KeepMomentum( const ICustomBody* objRef, Float m ) +//{ // deprecated +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// this->worldScene.GetCustomBody( tempRef )->SetMass_KeepMomentum( m ); +// } +//} +// +//void API_Impl::SetCenter( const ICustomBody* objRef, const Float3 &worldPos ) +//{ +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// //this->worldScene.GetCustomBody( tempRef )->Set //!< @todo TODO: need function +// this->worldScene.EvaluatePosition( tempRef ); +// } +//} +// +//void API_Impl::SetRotation( const ICustomBody* objRef, const Float4x4 &rotation ) +//{ +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// this->worldScene.GetCustomBody( tempRef )->SetRotation( rotation ); +// this->worldScene.EvaluatePosition( tempRef ); +// } +//} +// +//void API_Impl::SetOrientation( const ICustomBody* objRef, const Float4x4 &orientation ) +//{ +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// this->worldScene.GetCustomBody( tempRef )->SetOrientation( orientation ); +// this->worldScene.EvaluatePosition( tempRef ); +// } +//} +// +//void API_Impl::SetSize( const ICustomBody* objRef, const Float3 &size ) +//{ +// unsigned int tempRef = this->worldScene.GetTemporaryReferenceOf( objRef ); +// if( tempRef != this->worldScene.invalid_ref ) +// { +// this->worldScene.GetCustomBody( tempRef )->SetSize( size ); +// this->worldScene.EvaluatePosition( tempRef ); +// } +//} UniquePointer API_Impl::CreateRigidBody( const API::SimpleBodyDescription &desc ) const { diff --git a/Code/GamePhysics/Implementation/PhysicsAPI_Impl.h b/Code/GamePhysics/Implementation/PhysicsAPI_Impl.h index 5de9c05a..0c08bf11 100644 --- a/Code/GamePhysics/Implementation/PhysicsAPI_Impl.h +++ b/Code/GamePhysics/Implementation/PhysicsAPI_Impl.h @@ -20,6 +20,8 @@ namespace Oyster void SetGravityConstant( float g ); void SetSubscription( EventAction_Destruction functionPointer ); + float GetFrameTimeLength() const; + void Update(); bool IsInLimbo( const ICustomBody* objRef ); @@ -30,17 +32,16 @@ namespace Oyster ::Utility::DynamicMemory::UniquePointer ExtractObject( const ICustomBody* objRef ); void DestroyObject( const ICustomBody* objRef ); - void ApplyForceAt( const ICustomBody* objRef, const ::Oyster::Math::Float3 &worldPos, const ::Oyster::Math::Float3 &worldF ); - void ApplyCollisionResponse( const ICustomBody* objRefA, const ICustomBody* objRefB, ::Oyster::Math::Float &deltaWhen, ::Oyster::Math::Float3 &worldPointOfContact ); + //void ApplyForceAt( const ICustomBody* objRef, const ::Oyster::Math::Float3 &worldPos, const ::Oyster::Math::Float3 &worldF ); - void SetMomentOfInertiaTensor_KeepVelocity( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &localI ); - void SetMomentOfInertiaTensor_KeepMomentum( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &localI ); - void SetMass_KeepVelocity( const ICustomBody* objRef, ::Oyster::Math::Float m ); - void SetMass_KeepMomentum( const ICustomBody* objRef, ::Oyster::Math::Float m ); - void SetCenter( const ICustomBody* objRef, const ::Oyster::Math::Float3 &worldPos ); - void SetRotation( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &rotation ); - void SetOrientation( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &orientation ); - void SetSize( const ICustomBody* objRef, const ::Oyster::Math::Float3 &size ); + //void SetMomentOfInertiaTensor_KeepVelocity( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &localI ); + //void SetMomentOfInertiaTensor_KeepMomentum( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &localI ); + //void SetMass_KeepVelocity( const ICustomBody* objRef, ::Oyster::Math::Float m ); + //void SetMass_KeepMomentum( const ICustomBody* objRef, ::Oyster::Math::Float m ); + //void SetCenter( const ICustomBody* objRef, const ::Oyster::Math::Float3 &worldPos ); + //void SetRotation( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &rotation ); + //void SetOrientation( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &orientation ); + //void SetSize( const ICustomBody* objRef, const ::Oyster::Math::Float3 &size ); ::Utility::DynamicMemory::UniquePointer CreateRigidBody( const SimpleBodyDescription &desc ) const; ::Utility::DynamicMemory::UniquePointer CreateRigidBody( const SphericalBodyDescription &desc ) const; diff --git a/Code/GamePhysics/Implementation/SimpleRigidBody.cpp b/Code/GamePhysics/Implementation/SimpleRigidBody.cpp index 80e352ea..09855984 100644 --- a/Code/GamePhysics/Implementation/SimpleRigidBody.cpp +++ b/Code/GamePhysics/Implementation/SimpleRigidBody.cpp @@ -8,19 +8,59 @@ using namespace ::Oyster::Collision3D; using namespace ::Utility::DynamicMemory; using namespace ::Utility::Value; +namespace Private +{ + const Float epsilon = (const Float)1e-20; + + // Float calculations can suffer roundingerrors. Which is where epsilon = 1e-20 comes into the picture + inline bool EqualsZero( const Float &value ) + { // by Dan Andersson + return Abs( value ) < epsilon; + } + + inline bool Contains( const Plane &container, const Float4 &pos ) + { // by Dan Andersson + return EqualsZero( container.normal.Dot( pos ) + container.phasing ); + } + + // revision of Ray Vs Plane intersect test, there ray is more of an axis + bool Intersects( const Ray &axis, const Plane &plane, Float &connectDistance ) + { // by Dan Andersson + Float c = plane.normal.Dot(axis.direction); + if( EqualsZero(c) ) + { // axis is parallell with the plane. (axis direction orthogonal with the planar normal) + connectDistance = 0.0f; + return Contains( plane, axis.origin ); + } + + connectDistance = -plane.phasing; + connectDistance -= plane.normal.Dot( axis.origin ); + connectDistance /= c; + + return true; + } +} + SimpleRigidBody::SimpleRigidBody() { - this->rigid = RigidBody( Box(Float4x4::identity, Float3::null, Float3(1.0f)), 16.0f, Float4x4::identity ); + this->rigid = RigidBody(); + this->rigid.SetMass_KeepMomentum( 16.0f ); this->gravityNormal = Float3::null; this->collisionAction = Default::EventAction_Collision; - this->ignoreGravity = false; + this->ignoreGravity = this->isForwarded = false; + this->scene = nullptr; } SimpleRigidBody::SimpleRigidBody( const API::SimpleBodyDescription &desc ) { - this->rigid = RigidBody( Box( desc.rotation, desc.centerPosition, desc.size ), - desc.mass, - desc.inertiaTensor ); + this->rigid.SetRotation( desc.rotation ); + this->rigid.centerPos = desc.centerPosition; + this->rigid.SetSize( desc.size ); + this->rigid.SetMass_KeepMomentum( desc.mass ); + this->rigid.SetMomentOfInertia_KeepMomentum( desc.inertiaTensor ); + this->deltaPos = Float4::null; + this->deltaAxis = Float4::null; + this->gravityNormal = Float3::null; if( desc.subscription ) @@ -33,6 +73,7 @@ SimpleRigidBody::SimpleRigidBody( const API::SimpleBodyDescription &desc ) } this->ignoreGravity = desc.ignoreGravity; + this->scene = nullptr; } SimpleRigidBody::~SimpleRigidBody() {} @@ -44,24 +85,60 @@ UniquePointer SimpleRigidBody::Clone() const SimpleRigidBody::State SimpleRigidBody::GetState() const { - return State( this->rigid.box.boundingOffset, this->rigid.box.center, AngularAxis(this->rigid.box.rotation).xyz ); + return State( this->rigid.GetMass(), this->rigid.restitutionCoeff, + this->rigid.frictionCoeff_Static, this->rigid.frictionCoeff_Kinetic, + this->rigid.GetMomentOfInertia(), this->rigid.boundingReach, + this->rigid.centerPos, this->rigid.axis, + this->rigid.momentum_Linear, this->rigid.momentum_Angular ); } SimpleRigidBody::State & SimpleRigidBody::GetState( SimpleRigidBody::State &targetMem ) const { - return targetMem = State( this->rigid.box.boundingOffset, this->rigid.box.center, AngularAxis(this->rigid.box.rotation).xyz ); + return targetMem = State( this->rigid.GetMass(), this->rigid.restitutionCoeff, + this->rigid.frictionCoeff_Static, this->rigid.frictionCoeff_Kinetic, + this->rigid.GetMomentOfInertia(), this->rigid.boundingReach, + this->rigid.centerPos, this->rigid.axis, + this->rigid.momentum_Linear, this->rigid.momentum_Angular ); } void SimpleRigidBody::SetState( const SimpleRigidBody::State &state ) -{ /** @todo TODO: temporary solution! Need to know it's occtree */ - this->rigid.box.boundingOffset = state.GetReach(); - this->rigid.box.center = state.GetCenterPosition(); - this->rigid.box.rotation = state.GetRotation(); +{ + this->rigid.centerPos = state.GetCenterPosition(); + this->rigid.SetRotation( state.GetRotation() ); + this->rigid.boundingReach = state.GetReach(); + this->rigid.momentum_Linear = state.GetLinearMomentum(); + this->rigid.momentum_Angular = state.GetAngularMomentum(); + this->rigid.impulse_Linear += state.GetLinearImpulse(); + this->rigid.impulse_Angular += state.GetAngularImpulse(); + this->rigid.restitutionCoeff = state.GetRestitutionCoeff(); + this->rigid.frictionCoeff_Static = state.GetFrictionCoeff_Static(); + this->rigid.frictionCoeff_Kinetic = state.GetFrictionCoeff_Kinetic(); + + if( state.IsForwarded() ) + { + this->deltaPos += state.GetForward_DeltaPos(); + this->deltaAxis += state.GetForward_DeltaAxis(); + this->isForwarded; + } + + if( this->scene ) + { + if( state.IsSpatiallyAltered() ) + { + unsigned int tempRef = this->scene->GetTemporaryReferenceOf( this ); + this->scene->SetAsAltered( tempRef ); + this->scene->EvaluatePosition( tempRef ); + } + else if( state.IsDisturbed() ) + { + this->scene->SetAsAltered( this->scene->GetTemporaryReferenceOf(this) ); + } + } } -void SimpleRigidBody::CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ) +ICustomBody::SubscriptMessage SimpleRigidBody::CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ) { - this->collisionAction( proto, deuter ); + return this->collisionAction( proto, deuter ); } bool SimpleRigidBody::IsAffectedByGravity() const @@ -69,34 +146,76 @@ bool SimpleRigidBody::IsAffectedByGravity() const return !this->ignoreGravity; } -bool SimpleRigidBody::Intersects( const ICustomBody &object, Float timeStepLength, Float &deltaWhen, Float3 &worldPointOfContact ) const -{ - if( object.Intersects(this->rigid.box) ) - { //! @todo TODO: better implementation needed - deltaWhen = timeStepLength; - worldPointOfContact = Average( this->rigid.box.center, object.GetCenter() ); - return true; - } - else - { - return false; - } -} - bool SimpleRigidBody::Intersects( const ICollideable &shape ) const { - return this->rigid.box.Intersects( shape ); + return Box( this->rigid.GetRotationMatrix(), this->rigid.centerPos, this->rigid.GetSize() ).Intersects( shape ); +} + +bool SimpleRigidBody::Intersects( const ICollideable &shape, Float4 &worldPointOfContact ) const +{ + return Box( this->rigid.GetRotationMatrix(), this->rigid.centerPos, this->rigid.GetSize() ).Intersects( shape, worldPointOfContact ); +} + +bool SimpleRigidBody::Intersects( const ICustomBody &object, Float4 &worldPointOfContact ) const +{ + return object.Intersects( Box(this->rigid.GetRotationMatrix(), this->rigid.centerPos, this->rigid.GetSize()), worldPointOfContact ); } Sphere & SimpleRigidBody::GetBoundingSphere( Sphere &targetMem ) const { - return targetMem = Sphere( this->rigid.box.center, this->rigid.box.boundingOffset.GetMagnitude() ); + return targetMem = Sphere( this->rigid.centerPos, this->rigid.boundingReach.GetMagnitude() ); } -Float3 & SimpleRigidBody::GetNormalAt( const Float3 &worldPos, Float3 &targetMem ) const +Float4 & SimpleRigidBody::GetNormalAt( const Float4 &worldPos, Float4 &targetMem ) const { - //! @todo TODO: better implementation needed - return targetMem = (worldPos - this->rigid.box.center).GetNormalized(); + Float4 offset = worldPos - this->rigid.centerPos; + Float distance = offset.Dot( offset ); + Float3 normal = Float3::null; + + if( distance != 0.0f ) + { // sanity check + Ray axis( Float4::standard_unit_w, offset / (Float)::std::sqrt(distance) ); + Float minDistance = numeric_limits::max(); + Float4x4 rotationMatrix = this->rigid.GetRotationMatrix(); + + if( Private::Intersects(axis, Plane(rotationMatrix.v[0], -this->rigid.boundingReach.x), axis.collisionDistance) ) + { // check along x-axis + if( axis.collisionDistance < 0.0f ) + normal = -rotationMatrix.v[0].xyz; + else + normal = rotationMatrix.v[0].xyz; + + minDistance = Abs( axis.collisionDistance ); + } + + if( Private::Intersects(axis, Plane(rotationMatrix.v[1], -this->rigid.boundingReach.y), axis.collisionDistance) ) + { // check along y-axis + distance = Abs( axis.collisionDistance ); // recycling memory + if( minDistance > distance ) + { + if( axis.collisionDistance < 0.0f ) + normal = -rotationMatrix.v[1].xyz; + else + normal = rotationMatrix.v[1].xyz; + + minDistance = distance; + } + } + + if( Private::Intersects(axis, Plane(rotationMatrix.v[2], -this->rigid.boundingReach.z), axis.collisionDistance) ) + { // check along z-axis + if( minDistance > Abs( axis.collisionDistance ) ) + { + if( axis.collisionDistance < 0.0f ) + normal = -rotationMatrix.v[2].xyz; + else + normal = rotationMatrix.v[2].xyz; + } + } + } + targetMem.xyz = normal; + targetMem.w = 0.0f; + return targetMem; } Float3 & SimpleRigidBody::GetGravityNormal( Float3 &targetMem ) const @@ -104,41 +223,59 @@ Float3 & SimpleRigidBody::GetGravityNormal( Float3 &targetMem ) const return targetMem = this->gravityNormal; } -Float3 & SimpleRigidBody::GetCenter( Float3 &targetMem ) const -{ - return targetMem = this->rigid.box.center; -} +//Float3 & SimpleRigidBody::GetCenter( Float3 &targetMem ) const +//{ +// return targetMem = this->rigid.centerPos; +//} +// +//Float4x4 & SimpleRigidBody::GetRotation( Float4x4 &targetMem ) const +//{ +// return targetMem = this->rigid.box.rotation; +//} +// +//Float4x4 & SimpleRigidBody::GetOrientation( Float4x4 &targetMem ) const +//{ +// return targetMem = this->rigid.GetOrientation(); +//} +// +//Float4x4 & SimpleRigidBody::GetView( Float4x4 &targetMem ) const +//{ +// return targetMem = this->rigid.GetView(); +//} -Float4x4 & SimpleRigidBody::GetRotation( Float4x4 &targetMem ) const -{ - return targetMem = this->rigid.box.rotation; -} - -Float4x4 & SimpleRigidBody::GetOrientation( Float4x4 &targetMem ) const -{ - return targetMem = this->rigid.GetOrientation(); -} - -Float4x4 & SimpleRigidBody::GetView( Float4x4 &targetMem ) const -{ - return targetMem = this->rigid.GetView(); -} - -Float3 SimpleRigidBody::GetRigidLinearVelocity() const -{ - return this->rigid.GetLinearVelocity(); -} +//Float3 SimpleRigidBody::GetRigidLinearVelocity() const +//{ +// return this->rigid.GetLinearVelocity(); +//} UpdateState SimpleRigidBody::Update( Float timeStepLength ) { + if( this->isForwarded ) + { + this->rigid.Move( this->deltaPos, this->deltaAxis ); + this->deltaPos = Float4::null; + this->deltaAxis = Float4::null; + this->isForwarded = false; + } + this->rigid.Update_LeapFrog( timeStepLength ); - // compare previous and new state and return result + //! @todo TODO: compare previous and new state and return result //return this->current == this->previous ? UpdateState_resting : UpdateState_altered; return UpdateState_altered; } +void SimpleRigidBody::Predict( Float4 &outDeltaPos, Float4 &outDeltaAxis, const Float4 &actingLinearImpulse, const Float4 &actingAngularImpulse, Float deltaTime ) +{ + this->rigid.Predict_LeapFrog( outDeltaPos, outDeltaAxis, actingLinearImpulse, actingAngularImpulse, deltaTime ); +} + +void SimpleRigidBody::SetScene( void *scene ) +{ + this->scene = (Octree*)scene; +} + void SimpleRigidBody::SetSubscription( ICustomBody::EventAction_Collision functionPointer ) { if( functionPointer ) @@ -162,47 +299,47 @@ void SimpleRigidBody::SetGravityNormal( const Float3 &normalizedVector ) this->gravityNormal = normalizedVector; } -void SimpleRigidBody::SetMomentOfInertiaTensor_KeepVelocity( const Float4x4 &localI ) -{ - this->rigid.SetMomentOfInertia_KeepVelocity( localI ); -} - -void SimpleRigidBody::SetMomentOfInertiaTensor_KeepMomentum( const Float4x4 &localI ) -{ - this->rigid.SetMomentOfInertia_KeepMomentum( localI ); -} - -void SimpleRigidBody::SetMass_KeepVelocity( Float m ) -{ - this->rigid.SetMass_KeepVelocity( m ); -} - -void SimpleRigidBody::SetMass_KeepMomentum( Float m ) -{ - this->rigid.SetMass_KeepMomentum( m ); -} - -void SimpleRigidBody::SetCenter( const Float3 &worldPos ) -{ - this->rigid.SetCenter( worldPos ); -} - -void SimpleRigidBody::SetRotation( const Float4x4 &rotation ) -{ - this->rigid.SetRotation( rotation ); -} - -void SimpleRigidBody::SetOrientation( const Float4x4 &orientation ) -{ - this->rigid.SetOrientation( orientation ); -} - -void SimpleRigidBody::SetSize( const Float3 &size ) -{ - this->rigid.SetSize( size ); -} - -void SimpleRigidBody::SetMomentum( const Float3 &worldG ) -{ - this->rigid.SetLinearMomentum( worldG ); -} \ No newline at end of file +//void SimpleRigidBody::SetMomentOfInertiaTensor_KeepVelocity( const Float4x4 &localI ) +//{ +// this->rigid.SetMomentOfInertia_KeepVelocity( localI ); +//} +// +//void SimpleRigidBody::SetMomentOfInertiaTensor_KeepMomentum( const Float4x4 &localI ) +//{ +// this->rigid.SetMomentOfInertia_KeepMomentum( localI ); +//} +// +//void SimpleRigidBody::SetMass_KeepVelocity( Float m ) +//{ +// this->rigid.SetMass_KeepVelocity( m ); +//} +// +//void SimpleRigidBody::SetMass_KeepMomentum( Float m ) +//{ +// this->rigid.SetMass_KeepMomentum( m ); +//} +// +//void SimpleRigidBody::SetCenter( const Float3 &worldPos ) +//{ +// this->rigid.SetCenter( worldPos ); +//} +// +//void SimpleRigidBody::SetRotation( const Float4x4 &rotation ) +//{ +// this->rigid.SetRotation( rotation ); +//} +// +//void SimpleRigidBody::SetOrientation( const Float4x4 &orientation ) +//{ +// this->rigid.SetOrientation( orientation ); +//} +// +//void SimpleRigidBody::SetSize( const Float3 &size ) +//{ +// this->rigid.SetSize( size ); +//} +// +//void SimpleRigidBody::SetMomentum( const Float3 &worldG ) +//{ +// this->rigid.SetLinearMomentum( worldG ); +//} diff --git a/Code/GamePhysics/Implementation/SimpleRigidBody.h b/Code/GamePhysics/Implementation/SimpleRigidBody.h index 9eefeb48..618e0235 100644 --- a/Code/GamePhysics/Implementation/SimpleRigidBody.h +++ b/Code/GamePhysics/Implementation/SimpleRigidBody.h @@ -3,6 +3,7 @@ #include "..\PhysicsAPI.h" #include "RigidBody.h" +#include "Octree.h" namespace Oyster { namespace Physics { @@ -18,41 +19,46 @@ namespace Oyster { namespace Physics State GetState() const; State & GetState( State &targetMem ) const; void SetState( const State &state ); - ::Oyster::Math::Float3 GetRigidLinearVelocity() const; + //::Oyster::Math::Float3 GetRigidLinearVelocity() const; - void CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ); + SubscriptMessage CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ); bool IsAffectedByGravity() const; - bool Intersects( const ICustomBody &object, ::Oyster::Math::Float timeStepLength, ::Oyster::Math::Float &deltaWhen, ::Oyster::Math::Float3 &worldPointOfContact ) const; bool Intersects( const ::Oyster::Collision3D::ICollideable &shape ) const; + bool Intersects( const ::Oyster::Collision3D::ICollideable &shape, ::Oyster::Math::Float4 &worldPointOfContact ) const; + bool Intersects( const ICustomBody &object, ::Oyster::Math::Float4 &worldPointOfContact ) const; ::Oyster::Collision3D::Sphere & GetBoundingSphere( ::Oyster::Collision3D::Sphere &targetMem = ::Oyster::Collision3D::Sphere() ) const; - ::Oyster::Math::Float3 & GetNormalAt( const ::Oyster::Math::Float3 &worldPos, ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const; + ::Oyster::Math::Float4 & GetNormalAt( const ::Oyster::Math::Float4 &worldPos, ::Oyster::Math::Float4 &targetMem = ::Oyster::Math::Float4() ) const; ::Oyster::Math::Float3 & GetGravityNormal( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const; - ::Oyster::Math::Float3 & GetCenter( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const; - ::Oyster::Math::Float4x4 & GetRotation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; - ::Oyster::Math::Float4x4 & GetOrientation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; - ::Oyster::Math::Float4x4 & GetView( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; + //::Oyster::Math::Float3 & GetCenter( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const; + //::Oyster::Math::Float4x4 & GetRotation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; + //::Oyster::Math::Float4x4 & GetOrientation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; + //::Oyster::Math::Float4x4 & GetView( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; UpdateState Update( ::Oyster::Math::Float timeStepLength ); + void Predict( ::Oyster::Math::Float4 &outDeltaPos, ::Oyster::Math::Float4 &outDeltaAxis, const ::Oyster::Math::Float4 &actingLinearImpulse, const ::Oyster::Math::Float4 &actingAngularImpulse, ::Oyster::Math::Float deltaTime ); + void SetScene( void *scene ); void SetSubscription( EventAction_Collision functionPointer ); void SetGravity( bool ignore); void SetGravityNormal( const ::Oyster::Math::Float3 &normalizedVector ); - void SetMomentOfInertiaTensor_KeepVelocity( const ::Oyster::Math::Float4x4 &localI ); - void SetMomentOfInertiaTensor_KeepMomentum( const ::Oyster::Math::Float4x4 &localI ); - void SetMass_KeepVelocity( ::Oyster::Math::Float m ); - void SetMass_KeepMomentum( ::Oyster::Math::Float m ); - void SetCenter( const ::Oyster::Math::Float3 &worldPos ); - void SetRotation( const ::Oyster::Math::Float4x4 &rotation ); - void SetOrientation( const ::Oyster::Math::Float4x4 &orientation ); - void SetSize( const ::Oyster::Math::Float3 &size ); - void SetMomentum( const ::Oyster::Math::Float3 &worldG ); + //void SetMomentOfInertiaTensor_KeepVelocity( const ::Oyster::Math::Float4x4 &localI ); + //void SetMomentOfInertiaTensor_KeepMomentum( const ::Oyster::Math::Float4x4 &localI ); + //void SetMass_KeepVelocity( ::Oyster::Math::Float m ); + //void SetMass_KeepMomentum( ::Oyster::Math::Float m ); + //void SetCenter( const ::Oyster::Math::Float3 &worldPos ); + //void SetRotation( const ::Oyster::Math::Float4x4 &rotation ); + //void SetOrientation( const ::Oyster::Math::Float4x4 &orientation ); + //void SetSize( const ::Oyster::Math::Float3 &size ); + //void SetMomentum( const ::Oyster::Math::Float3 &worldG ); private: ::Oyster::Physics3D::RigidBody rigid; + ::Oyster::Math::Float4 deltaPos, deltaAxis; ::Oyster::Math::Float3 gravityNormal; EventAction_Collision collisionAction; - bool ignoreGravity; + Octree *scene; + bool ignoreGravity, isForwarded; }; } } diff --git a/Code/GamePhysics/Implementation/SphericalRigidBody.cpp b/Code/GamePhysics/Implementation/SphericalRigidBody.cpp index 364d7454..95901763 100644 --- a/Code/GamePhysics/Implementation/SphericalRigidBody.cpp +++ b/Code/GamePhysics/Implementation/SphericalRigidBody.cpp @@ -10,18 +10,26 @@ using namespace ::Utility::Value; SphericalRigidBody::SphericalRigidBody() { - this->rigid = RigidBody( Box(Float4x4::identity, Float3::null, Float3(1.0f)), 10.0f, Float4x4::identity ); + this->rigid = RigidBody(); + this->rigid.SetMass_KeepMomentum( 10.0f ); this->gravityNormal = Float3::null; this->collisionAction = Default::EventAction_Collision; - this->ignoreGravity = false; + this->ignoreGravity = this->isForwarded = false; + this->scene = nullptr; this->body = Sphere( Float3::null, 0.5f ); } SphericalRigidBody::SphericalRigidBody( const API::SphericalBodyDescription &desc ) { - this->rigid = RigidBody( Box( desc.rotation, desc.centerPosition, Float3(2.0f * desc.radius) ), - desc.mass, - MomentOfInertia::CreateSphereMatrix( desc.mass, desc.radius ) ); + this->rigid = RigidBody(); + this->rigid.SetRotation( desc.rotation ); + this->rigid.centerPos = desc.centerPosition; + this->rigid.boundingReach = Float4( desc.radius, desc.radius, desc.radius, 0.0f ); + this->rigid.SetMass_KeepMomentum( desc.mass ); + this->rigid.SetMomentOfInertia_KeepMomentum( Formula::MomentOfInertia::CreateSphereMatrix( desc.mass, desc.radius ) ); + this->deltaPos = Float4::null; + this->deltaAxis = Float4::null; + this->gravityNormal = Float3::null; if( desc.subscription ) @@ -34,6 +42,7 @@ SphericalRigidBody::SphericalRigidBody( const API::SphericalBodyDescription &des } this->ignoreGravity = desc.ignoreGravity; + this->scene = nullptr; this->body = Sphere( desc.centerPosition, desc.radius ); } @@ -46,24 +55,60 @@ UniquePointer SphericalRigidBody::Clone() const SphericalRigidBody::State SphericalRigidBody::GetState() const { - return State( this->rigid.box.boundingOffset, this->rigid.box.center, AngularAxis(this->rigid.box.rotation).xyz ); + return State( this->rigid.GetMass(), this->rigid.restitutionCoeff, + this->rigid.frictionCoeff_Static, this->rigid.frictionCoeff_Kinetic, + this->rigid.GetMomentOfInertia(), this->rigid.boundingReach, + this->rigid.centerPos, this->rigid.axis, + this->rigid.momentum_Linear, this->rigid.momentum_Angular ); } SphericalRigidBody::State & SphericalRigidBody::GetState( SphericalRigidBody::State &targetMem ) const { - return targetMem = State( this->rigid.box.boundingOffset, this->rigid.box.center, AngularAxis(this->rigid.box.rotation).xyz ); + return targetMem = State( this->rigid.GetMass(), this->rigid.restitutionCoeff, + this->rigid.frictionCoeff_Static, this->rigid.frictionCoeff_Kinetic, + this->rigid.GetMomentOfInertia(), this->rigid.boundingReach, + this->rigid.centerPos, this->rigid.axis, + this->rigid.momentum_Linear, this->rigid.momentum_Angular ); } void SphericalRigidBody::SetState( const SphericalRigidBody::State &state ) -{ /** @todo TODO: temporary solution! Need to know it's occtree */ - this->rigid.box.boundingOffset = state.GetReach(); - this->rigid.box.center = state.GetCenterPosition(); - this->rigid.box.rotation = state.GetRotation(); +{ + this->rigid.centerPos = state.GetCenterPosition(); + this->rigid.SetRotation( state.GetRotation() ); + this->rigid.boundingReach = state.GetReach(); + this->rigid.momentum_Linear = state.GetLinearMomentum(); + this->rigid.momentum_Angular = state.GetAngularMomentum(); + this->rigid.impulse_Linear += state.GetLinearImpulse(); + this->rigid.impulse_Angular += state.GetAngularImpulse(); + this->rigid.restitutionCoeff = state.GetRestitutionCoeff(); + this->rigid.frictionCoeff_Static = state.GetFrictionCoeff_Static(); + this->rigid.frictionCoeff_Kinetic = state.GetFrictionCoeff_Kinetic(); + + if( state.IsForwarded() ) + { + this->deltaPos += state.GetForward_DeltaPos(); + this->deltaAxis += state.GetForward_DeltaAxis(); + this->isForwarded = false; + } + + if( this->scene ) + { + if( state.IsSpatiallyAltered() ) + { + unsigned int tempRef = this->scene->GetTemporaryReferenceOf( this ); + this->scene->SetAsAltered( tempRef ); + this->scene->EvaluatePosition( tempRef ); + } + else if( state.IsDisturbed() ) + { + this->scene->SetAsAltered( this->scene->GetTemporaryReferenceOf(this) ); + } + } } -void SphericalRigidBody::CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ) +ICustomBody::SubscriptMessage SphericalRigidBody::CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ) { - this->collisionAction( proto, deuter ); + return this->collisionAction( proto, deuter ); } bool SphericalRigidBody::IsAffectedByGravity() const @@ -71,23 +116,19 @@ bool SphericalRigidBody::IsAffectedByGravity() const return !this->ignoreGravity; } -bool SphericalRigidBody::Intersects( const ICustomBody &object, Float timeStepLength, Float &deltaWhen, Float3 &worldPointOfContact ) const -{ - if( object.Intersects(this->body) ) - { //! @todo TODO: better implementation needed - deltaWhen = timeStepLength; - worldPointOfContact = Average( this->body.center, object.GetCenter() ); - return true; - } - else - { - return false; - } -} - bool SphericalRigidBody::Intersects( const ICollideable &shape ) const { - return this->rigid.box.Intersects( shape ); + return Sphere( this->rigid.centerPos, this->rigid.boundingReach.x ).Intersects( shape ); +} + +bool SphericalRigidBody::Intersects( const ICollideable &shape, Float4 &worldPointOfContact ) const +{ + return Sphere( this->rigid.centerPos, this->rigid.boundingReach.x ).Intersects( shape, worldPointOfContact ); +} + +bool SphericalRigidBody::Intersects( const ICustomBody &object, Float4 &worldPointOfContact ) const +{ + return object.Intersects( Sphere(this->rigid.centerPos, this->rigid.boundingReach.x), worldPointOfContact ); } Sphere & SphericalRigidBody::GetBoundingSphere( Sphere &targetMem ) const @@ -95,10 +136,16 @@ Sphere & SphericalRigidBody::GetBoundingSphere( Sphere &targetMem ) const return targetMem = this->body; } -Float3 & SphericalRigidBody::GetNormalAt( const Float3 &worldPos, Float3 &targetMem ) const +Float4 & SphericalRigidBody::GetNormalAt( const Float4 &worldPos, Float4 &targetMem ) const { - //! @todo TODO: better implementation needed - return targetMem = (worldPos - this->rigid.box.center).GetNormalized(); + targetMem = worldPos - this->rigid.centerPos; + Float magnitude = targetMem.GetMagnitude(); + if( magnitude != 0.0f ) + { // sanity check + targetMem.Normalize(); + } + + return targetMem; } Float3 & SphericalRigidBody::GetGravityNormal( Float3 &targetMem ) const @@ -106,41 +153,54 @@ Float3 & SphericalRigidBody::GetGravityNormal( Float3 &targetMem ) const return targetMem = this->gravityNormal; } -Float3 & SphericalRigidBody::GetCenter( Float3 &targetMem ) const -{ - return targetMem = this->rigid.box.center; -} +//Float3 & SphericalRigidBody::GetCenter( Float3 &targetMem ) const +//{ +// return targetMem = this->rigid.centerPos; +//} +// +//Float4x4 & SphericalRigidBody::GetRotation( Float4x4 &targetMem ) const +//{ +// return targetMem = this->rigid.box.rotation; +//} +// +//Float4x4 & SphericalRigidBody::GetOrientation( Float4x4 &targetMem ) const +//{ +// return targetMem = this->rigid.GetOrientation(); +//} +// +//Float4x4 & SphericalRigidBody::GetView( Float4x4 &targetMem ) const +//{ +// return targetMem = this->rigid.GetView(); +//} -Float4x4 & SphericalRigidBody::GetRotation( Float4x4 &targetMem ) const -{ - return targetMem = this->rigid.box.rotation; -} - -Float4x4 & SphericalRigidBody::GetOrientation( Float4x4 &targetMem ) const -{ - return targetMem = this->rigid.GetOrientation(); -} - -Float4x4 & SphericalRigidBody::GetView( Float4x4 &targetMem ) const -{ - return targetMem = this->rigid.GetView(); -} - -Float3 SphericalRigidBody::GetRigidLinearVelocity() const -{ - return this->rigid.GetLinearVelocity(); -} +//Float3 SphericalRigidBody::GetRigidLinearVelocity() const +//{ +// return this->rigid.GetLinearVelocity(); +//} UpdateState SphericalRigidBody::Update( Float timeStepLength ) { + if( this->isForwarded ) + { + this->rigid.Move( this->deltaPos, this->deltaAxis ); + this->deltaPos = Float4::null; + this->deltaAxis = Float4::null; + this->isForwarded = false; + } + this->rigid.Update_LeapFrog( timeStepLength ); - this->body.center = this->rigid.GetCenter(); + this->body.center = this->rigid.centerPos; // compare previous and new state and return result //return this->current == this->previous ? UpdateState_resting : UpdateState_altered; return UpdateState_altered; } +void SphericalRigidBody::Predict( ::Oyster::Math::Float4 &outDeltaPos, ::Oyster::Math::Float4 &outDeltaAxis, const ::Oyster::Math::Float4 &actingLinearImpulse, const ::Oyster::Math::Float4 &actingAngularImpulse, ::Oyster::Math::Float deltaTime ) +{ + this->rigid.Predict_LeapFrog( outDeltaPos, outDeltaAxis, actingLinearImpulse, actingAngularImpulse, deltaTime ); +} + void SphericalRigidBody::SetSubscription( ICustomBody::EventAction_Collision functionPointer ) { if( functionPointer ) @@ -153,7 +213,12 @@ void SphericalRigidBody::SetSubscription( ICustomBody::EventAction_Collision fun } } -void SphericalRigidBody::SetGravity( bool ignore) +void SphericalRigidBody::SetScene( void *scene ) +{ + this->scene = (Octree*)scene; +} + +void SphericalRigidBody::SetGravity( bool ignore ) { this->ignoreGravity = ignore; this->gravityNormal = Float3::null; @@ -164,50 +229,50 @@ void SphericalRigidBody::SetGravityNormal( const Float3 &normalizedVector ) this->gravityNormal = normalizedVector; } -void SphericalRigidBody::SetMomentOfInertiaTensor_KeepVelocity( const Float4x4 &localI ) -{ - this->rigid.SetMomentOfInertia_KeepVelocity( localI ); -} - -void SphericalRigidBody::SetMomentOfInertiaTensor_KeepMomentum( const Float4x4 &localI ) -{ - this->rigid.SetMomentOfInertia_KeepMomentum( localI ); -} - -void SphericalRigidBody::SetMass_KeepVelocity( Float m ) -{ - this->rigid.SetMass_KeepVelocity( m ); -} - -void SphericalRigidBody::SetMass_KeepMomentum( Float m ) -{ - this->rigid.SetMass_KeepMomentum( m ); -} - -void SphericalRigidBody::SetCenter( const Float3 &worldPos ) -{ - this->rigid.SetCenter( worldPos ); - this->body.center = worldPos; -} - -void SphericalRigidBody::SetRotation( const Float4x4 &rotation ) -{ - this->rigid.SetRotation( rotation ); -} - -void SphericalRigidBody::SetOrientation( const Float4x4 &orientation ) -{ - this->rigid.SetOrientation( orientation ); - this->body.center = orientation.v[3].xyz; -} - -void SphericalRigidBody::SetSize( const Float3 &size ) -{ - this->rigid.SetSize( size ); - this->body.radius = 0.5f * Min( Min( size.x, size.y ), size.z ); // inline Min( FloatN )? -} - -void SphericalRigidBody::SetMomentum( const Float3 &worldG ) -{ - this->rigid.SetLinearMomentum( worldG ); -} \ No newline at end of file +//void SphericalRigidBody::SetMomentOfInertiaTensor_KeepVelocity( const Float4x4 &localI ) +//{ +// this->rigid.SetMomentOfInertia_KeepVelocity( localI ); +//} +// +//void SphericalRigidBody::SetMomentOfInertiaTensor_KeepMomentum( const Float4x4 &localI ) +//{ +// this->rigid.SetMomentOfInertia_KeepMomentum( localI ); +//} +// +//void SphericalRigidBody::SetMass_KeepVelocity( Float m ) +//{ +// this->rigid.SetMass_KeepVelocity( m ); +//} +// +//void SphericalRigidBody::SetMass_KeepMomentum( Float m ) +//{ +// this->rigid.SetMass_KeepMomentum( m ); +//} +// +//void SphericalRigidBody::SetCenter( const Float3 &worldPos ) +//{ +// this->rigid.SetCenter( worldPos ); +// this->body.center = worldPos; +//} +// +//void SphericalRigidBody::SetRotation( const Float4x4 &rotation ) +//{ +// this->rigid.SetRotation( rotation ); +//} +// +//void SphericalRigidBody::SetOrientation( const Float4x4 &orientation ) +//{ +// this->rigid.SetOrientation( orientation ); +// this->body.center = orientation.v[3].xyz; +//} +// +//void SphericalRigidBody::SetSize( const Float3 &size ) +//{ +// this->rigid.SetSize( size ); +// this->body.radius = 0.5f * Min( Min( size.x, size.y ), size.z ); // inline Min( FloatN )? +//} +// +//void SphericalRigidBody::SetMomentum( const Float3 &worldG ) +//{ +// this->rigid.SetLinearMomentum( worldG ); +//} diff --git a/Code/GamePhysics/Implementation/SphericalRigidBody.h b/Code/GamePhysics/Implementation/SphericalRigidBody.h index 4d003f99..51d1b998 100644 --- a/Code/GamePhysics/Implementation/SphericalRigidBody.h +++ b/Code/GamePhysics/Implementation/SphericalRigidBody.h @@ -4,6 +4,7 @@ #include "..\PhysicsAPI.h" #include "RigidBody.h" #include "Sphere.h" +#include "Octree.h" namespace Oyster { namespace Physics { @@ -19,41 +20,46 @@ namespace Oyster { namespace Physics State GetState() const; State & GetState( State &targetMem = State() ) const; void SetState( const State &state ); - ::Oyster::Math::Float3 GetRigidLinearVelocity() const; + //::Oyster::Math::Float3 GetRigidLinearVelocity() const; - void CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ); + SubscriptMessage CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ); bool IsAffectedByGravity() const; - bool Intersects( const ICustomBody &object, ::Oyster::Math::Float timeStepLength, ::Oyster::Math::Float &deltaWhen, ::Oyster::Math::Float3 &worldPointOfContact ) const; bool Intersects( const ::Oyster::Collision3D::ICollideable &shape ) const; + bool Intersects( const ::Oyster::Collision3D::ICollideable &shape, ::Oyster::Math::Float4 &worldPointOfContact ) const; + bool Intersects( const ICustomBody &object, ::Oyster::Math::Float4 &worldPointOfContact ) const; ::Oyster::Collision3D::Sphere & GetBoundingSphere( ::Oyster::Collision3D::Sphere &targetMem = ::Oyster::Collision3D::Sphere() ) const; - ::Oyster::Math::Float3 & GetNormalAt( const ::Oyster::Math::Float3 &worldPos, ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const; + ::Oyster::Math::Float4 & GetNormalAt( const ::Oyster::Math::Float4 &worldPos, ::Oyster::Math::Float4 &targetMem = ::Oyster::Math::Float4() ) const; ::Oyster::Math::Float3 & GetGravityNormal( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const; - ::Oyster::Math::Float3 & GetCenter( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const; - ::Oyster::Math::Float4x4 & GetRotation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; - ::Oyster::Math::Float4x4 & GetOrientation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; - ::Oyster::Math::Float4x4 & GetView( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; + //::Oyster::Math::Float3 & GetCenter( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const; + //::Oyster::Math::Float4x4 & GetRotation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; + //::Oyster::Math::Float4x4 & GetOrientation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; + //::Oyster::Math::Float4x4 & GetView( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const; UpdateState Update( ::Oyster::Math::Float timeStepLength ); + void Predict( ::Oyster::Math::Float4 &outDeltaPos, ::Oyster::Math::Float4 &outDeltaAxis, const ::Oyster::Math::Float4 &actingLinearImpulse, const ::Oyster::Math::Float4 &actingAngularImpulse, ::Oyster::Math::Float deltaTime ); + void SetScene( void *scene ); void SetSubscription( EventAction_Collision functionPointer ); void SetGravity( bool ignore); void SetGravityNormal( const ::Oyster::Math::Float3 &normalizedVector ); - void SetMomentOfInertiaTensor_KeepVelocity( const ::Oyster::Math::Float4x4 &localI ); - void SetMomentOfInertiaTensor_KeepMomentum( const ::Oyster::Math::Float4x4 &localI ); - void SetMass_KeepVelocity( ::Oyster::Math::Float m ); - void SetMass_KeepMomentum( ::Oyster::Math::Float m ); - void SetCenter( const ::Oyster::Math::Float3 &worldPos ); - void SetRotation( const ::Oyster::Math::Float4x4 &rotation ); - void SetOrientation( const ::Oyster::Math::Float4x4 &orientation ); - void SetSize( const ::Oyster::Math::Float3 &size ); - void SetMomentum( const ::Oyster::Math::Float3 &worldG ); + //void SetMomentOfInertiaTensor_KeepVelocity( const ::Oyster::Math::Float4x4 &localI ); + //void SetMomentOfInertiaTensor_KeepMomentum( const ::Oyster::Math::Float4x4 &localI ); + //void SetMass_KeepVelocity( ::Oyster::Math::Float m ); + //void SetMass_KeepMomentum( ::Oyster::Math::Float m ); + //void SetCenter( const ::Oyster::Math::Float3 &worldPos ); + //void SetRotation( const ::Oyster::Math::Float4x4 &rotation ); + //void SetOrientation( const ::Oyster::Math::Float4x4 &orientation ); + //void SetSize( const ::Oyster::Math::Float3 &size ); + //void SetMomentum( const ::Oyster::Math::Float3 &worldG ); private: ::Oyster::Physics3D::RigidBody rigid; + ::Oyster::Math::Float4 deltaPos, deltaAxis; ::Oyster::Math::Float3 gravityNormal; EventAction_Collision collisionAction; - bool ignoreGravity; + bool ignoreGravity, isForwarded; + Octree *scene; ::Oyster::Collision3D::Sphere body; }; } } diff --git a/Code/GamePhysics/PhysicsAPI.h b/Code/GamePhysics/PhysicsAPI.h index 04d0d3f1..0904551d 100644 --- a/Code/GamePhysics/PhysicsAPI.h +++ b/Code/GamePhysics/PhysicsAPI.h @@ -35,20 +35,6 @@ namespace Oyster const float gravity_constant = (const float)6.67284e-11; //!< The _big_G_! ( N(m/kg)^2 ) Used in real gravityforcefields. } - class PHYSICS_DLL_USAGE MomentOfInertia - { - public: - static ::Oyster::Math::Float4x4 & CreateSphereMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float radius, ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ); - - static ::Oyster::Math::Float4x4 & CreateHollowSphereMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float radius, ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ); - - static ::Oyster::Math::Float4x4 & CreateCuboidMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float height, const ::Oyster::Math::Float width, const ::Oyster::Math::Float depth, ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ); - - static ::Oyster::Math::Float4x4 & CreateCylinderMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float height, const ::Oyster::Math::Float radius, ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ); - - static ::Oyster::Math::Float4x4 & CreateRodMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float length, ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ); - }; - class PHYSICS_DLL_USAGE API { public: @@ -138,82 +124,73 @@ namespace Oyster ********************************************************/ virtual void DestroyObject( const ICustomBody* objRef ) = 0; - /******************************************************** - * Apply force on an object. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param worldPos: Relative to the world origo. (Not relative to object) [m] - * @param worldF: Vector with the direction and magnitude of the force. [N] - ********************************************************/ - virtual void ApplyForceAt( const ICustomBody* objRef, const ::Oyster::Math::Float3 &worldPos, const ::Oyster::Math::Float3 &worldF ) = 0; + ///******************************************************** + // * Apply force on an object. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param worldPos: Relative to the world origo. (Not relative to object) [m] + // * @param worldF: Vector with the direction and magnitude of the force. [N] + // ********************************************************/ + //virtual void ApplyForceAt( const ICustomBody* objRef, const ::Oyster::Math::Float3 &worldPos, const ::Oyster::Math::Float3 &worldF ) = 0; - /******************************************************** - * Apply force on an object. - * @param objRefA: A pointer to the ICustomBody representing a physical object. - * @param objRefB: A pointer to the ICustomBody representing a physical object. - * @param deltaWhen: The elapsed simulation time since last update frame. [s] - * @param worldPointOfContact: Point of Collision, relative to the world origo. (Not relative to the objects) [m] - ********************************************************/ - virtual void ApplyCollisionResponse( const ICustomBody* objRefA, const ICustomBody* objRefB, ::Oyster::Math::Float &deltaWhen, ::Oyster::Math::Float3 &worldPointOfContact ) = 0; - - /******************************************************** - * Sets the MomentOfInertia tensor matrix of an object without changing it's angular velocity. - * Noticeable effect: The angular momentum will change. Changing the amount of kinetic energy. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param localI: The tensor matrix relative to the axises of the object. @see MomentOfInertia namespace. - ********************************************************/ - virtual void SetMomentOfInertiaTensor_KeepVelocity( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &localI ) = 0; - - /******************************************************** - * Sets the MomentOfInertia tensor matrix of an object without changing it's angular momentum. - * Noticeable effect: The angular velocity will change. Can be used to create slow effects. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param localI: The tensor matrix relative to the axises of the object. @see MomentOfInertia namespace. - ********************************************************/ - virtual void SetMomentOfInertiaTensor_KeepMomentum( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &localI ) = 0; - - /******************************************************** - * Sets the mass of an object without changing it's linear velocity. - * Noticeable effect: The linear momentum will change. Changing the amount of kinetic energy. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param m: [kg] - ********************************************************/ - virtual void SetMass_KeepVelocity( const ICustomBody* objRef, ::Oyster::Math::Float m ) = 0; - - /******************************************************** - * Sets the mass of an object without changing it's linear velocity. - * Noticeable effect: The linear velocity will change. Can be used to create slow effects. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param m: [kg] - ********************************************************/ - virtual void SetMass_KeepMomentum( const ICustomBody* objRef, ::Oyster::Math::Float m ) = 0; - - /******************************************************** - * Instantly moves an object. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param worldPos: Relative to the world origo. (Not relative to object) [m] - ********************************************************/ - virtual void SetCenter( const ICustomBody* objRef, const ::Oyster::Math::Float3 &worldPos ) = 0; - - /******************************************************** - * Instantly redirects object. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param rotation: New rotation. - ********************************************************/ - virtual void SetRotation( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &rotation ) = 0; - - /******************************************************** - * Instantly moves and redirects object. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param orientation: New orientation. - ********************************************************/ - virtual void SetOrientation( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &orientation ) = 0; - - /******************************************************** - * Resizes the boundingBox. - * @param objRef: A pointer to the ICustomBody representing a physical object. - * @param size: New size of this [m] - ********************************************************/ - virtual void SetSize( const ICustomBody* objRef, const ::Oyster::Math::Float3 &size ) = 0; + ///******************************************************** + // * Sets the MomentOfInertia tensor matrix of an object without changing it's angular velocity. + // * Noticeable effect: The angular momentum will change. Changing the amount of kinetic energy. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param localI: The tensor matrix relative to the axises of the object. @see MomentOfInertia namespace. + // ********************************************************/ + //virtual void SetMomentOfInertiaTensor_KeepVelocity( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &localI ) = 0; + // + ///******************************************************** + // * Sets the MomentOfInertia tensor matrix of an object without changing it's angular momentum. + // * Noticeable effect: The angular velocity will change. Can be used to create slow effects. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param localI: The tensor matrix relative to the axises of the object. @see MomentOfInertia namespace. + // ********************************************************/ + //virtual void SetMomentOfInertiaTensor_KeepMomentum( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &localI ) = 0; + // + ///******************************************************** + // * Sets the mass of an object without changing it's linear velocity. + // * Noticeable effect: The linear momentum will change. Changing the amount of kinetic energy. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param m: [kg] + // ********************************************************/ + //virtual void SetMass_KeepVelocity( const ICustomBody* objRef, ::Oyster::Math::Float m ) = 0; + // + ///******************************************************** + // * Sets the mass of an object without changing it's linear velocity. + // * Noticeable effect: The linear velocity will change. Can be used to create slow effects. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param m: [kg] + // ********************************************************/ + //virtual void SetMass_KeepMomentum( const ICustomBody* objRef, ::Oyster::Math::Float m ) = 0; + // + ///******************************************************** + // * Instantly moves an object. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param worldPos: Relative to the world origo. (Not relative to object) [m] + // ********************************************************/ + //virtual void SetCenter( const ICustomBody* objRef, const ::Oyster::Math::Float3 &worldPos ) = 0; + // + ///******************************************************** + // * Instantly redirects object. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param rotation: New rotation. + // ********************************************************/ + //virtual void SetRotation( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &rotation ) = 0; + // + ///******************************************************** + // * Instantly moves and redirects object. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param orientation: New orientation. + // ********************************************************/ + //virtual void SetOrientation( const ICustomBody* objRef, const ::Oyster::Math::Float4x4 &orientation ) = 0; + // + ///******************************************************** + // * Resizes the boundingBox. + // * @param objRef: A pointer to the ICustomBody representing a physical object. + // * @param size: New size of this [m] + // ********************************************************/ + //virtual void SetSize( const ICustomBody* objRef, const ::Oyster::Math::Float3 &size ) = 0; /******************************************************** * Creates a new dynamically allocated object that can be used as a component for more complex ICustomBodies. @@ -245,11 +222,6 @@ namespace Oyster SubscriptMessage_ignore_collision_response }; - /******************************************************** - * @param gameObjectRef: a pointer to the object in the game owning the rigid body. - ********************************************************/ - void* gameObjectRef; - typedef SubscriptMessage (*EventAction_Collision)( const ICustomBody *proto, const ICustomBody *deuter ); typedef Struct::SimpleBodyDescription SimpleBodyDescription; typedef Struct::SphericalBodyDescription SphericalBodyDescription; @@ -266,7 +238,7 @@ namespace Oyster /******************************************************** * @todo TODO: need doc ********************************************************/ - virtual void CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ) = 0; + virtual SubscriptMessage CallSubscription( const ICustomBody *proto, const ICustomBody *deuter ) = 0; /******************************************************** * @todo TODO: need doc @@ -281,7 +253,7 @@ namespace Oyster /******************************************************** * @return the linear velocity of the rigid body in a vector. ********************************************************/ - virtual Math::Float3 GetRigidLinearVelocity() const = 0; + //virtual Math::Float3 GetRigidLinearVelocity() const = 0; /******************************************************** * @todo TODO: need doc @@ -293,22 +265,28 @@ namespace Oyster ********************************************************/ virtual bool IsAffectedByGravity() const = 0; - /******************************************************** - * Performs a detailed Intersect test and returns if, when and where. - * @param object: What this is intersect testing against. - * @param timeStepLength: The value set by API::SetDeltaTime(...) - * @param deltaWhen: Time in seconds since last update frame til timeOfContact. 0.0f <= deltaWhen <= timeStepLength - * @param worldPointOfContact: Where at timeOfContact, this and object touches eachother. - * @return true if this truly intersects with object. - ********************************************************/ - virtual bool Intersects( const ICustomBody &object, ::Oyster::Math::Float timeStepLength, ::Oyster::Math::Float &deltaWhen, ::Oyster::Math::Float3 &worldPointOfContact ) const = 0; - /******************************************************** * param shape: Any defined sample shape. * @return true if this truly intersects with shape. ********************************************************/ virtual bool Intersects( const ::Oyster::Collision3D::ICollideable &shape ) const = 0; + /******************************************************** + * Performs a detailed Intersect test and returns if, when and where. + * @param shape: Any defined sample shape. + * @param worldPointOfContact: Where at timeOfContact, this and object touches eachother. + * @return true if this truly intersects with object. + ********************************************************/ + virtual bool Intersects( const ::Oyster::Collision3D::ICollideable &shape, ::Oyster::Math::Float4 &worldPointOfContact ) const = 0; + + /******************************************************** + * Performs a detailed Intersect test and returns if, when and where. + * @param object: What this is intersect testing against. + * @param worldPointOfContact: Where at timeOfContact, this and object touches eachother. + * @return true if this truly intersects with object. + ********************************************************/ + virtual bool Intersects( const ICustomBody &object, ::Oyster::Math::Float4 &worldPointOfContact ) const = 0; + /******************************************************** * Required by Engine's Collision Search. * @param targetMem: Provided memory that written into and then returned. @@ -322,7 +300,7 @@ namespace Oyster * @param targetMem: Provided memory that written into and then returned. * @return a surface normal in worldSpace. ********************************************************/ - virtual ::Oyster::Math::Float3 & GetNormalAt( const ::Oyster::Math::Float3 &worldPos, ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const = 0; + virtual ::Oyster::Math::Float4 & GetNormalAt( const ::Oyster::Math::Float4 &worldPos, ::Oyster::Math::Float4 &targetMem = ::Oyster::Math::Float4() ) const = 0; /******************************************************** * The gravity normal will have same direction as the total gravity force pulling on this and have the magnitude of 1.0f. @@ -331,37 +309,49 @@ namespace Oyster ********************************************************/ virtual ::Oyster::Math::Float3 & GetGravityNormal( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const = 0; - /******************************************************** - * The world position of this center of gravity. - * @param targetMem: Provided memory that written into and then returned. - * @return a position in worldSpace. - ********************************************************/ - virtual ::Oyster::Math::Float3 & GetCenter( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const = 0; - - /******************************************************** - * @param targetMem: Provided memory that written into and then returned. - * @return a copy of this's rotation matrix. - ********************************************************/ - virtual ::Oyster::Math::Float4x4 & GetRotation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const = 0; - - /******************************************************** - * @param targetMem: Provided memory that written into and then returned. - * @return a copy of this's orientation matrix. - ********************************************************/ - virtual ::Oyster::Math::Float4x4 & GetOrientation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const = 0; - - /******************************************************** - * @param targetMem: Provided memory that written into and then returned. - * @return a copy of this's view matrix. - ********************************************************/ - virtual ::Oyster::Math::Float4x4 & GetView( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const = 0; + ///******************************************************** + // * The world position of this center of gravity. + // * @param targetMem: Provided memory that written into and then returned. + // * @return a position in worldSpace. + // ********************************************************/ + //virtual ::Oyster::Math::Float3 & GetCenter( ::Oyster::Math::Float3 &targetMem = ::Oyster::Math::Float3() ) const = 0; + // + ///******************************************************** + // * @param targetMem: Provided memory that written into and then returned. + // * @return a copy of this's rotation matrix. + // ********************************************************/ + //virtual ::Oyster::Math::Float4x4 & GetRotation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const = 0; + // + ///******************************************************** + // * @param targetMem: Provided memory that written into and then returned. + // * @return a copy of this's orientation matrix. + // ********************************************************/ + //virtual ::Oyster::Math::Float4x4 & GetOrientation( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const = 0; + // + ///******************************************************** + // * @param targetMem: Provided memory that written into and then returned. + // * @return a copy of this's view matrix. + // ********************************************************/ + //virtual ::Oyster::Math::Float4x4 & GetView( ::Oyster::Math::Float4x4 &targetMem = ::Oyster::Math::Float4x4() ) const = 0; /******************************************************** * To not be called if is in Engine * Is called during API::Update ********************************************************/ virtual UpdateState Update( ::Oyster::Math::Float timeStepLength ) = 0; + + /******************************************************** + * @todo TODO: add doc + ********************************************************/ + virtual void Predict( ::Oyster::Math::Float4 &outDeltaPos, ::Oyster::Math::Float4 &outDeltaAxis, const ::Oyster::Math::Float4 &actingLinearImpulse, const ::Oyster::Math::Float4 &actingAngularImpulse, ::Oyster::Math::Float deltaTime ) = 0; + /******************************************************** + * Sets which scene this ICustomBody is within. + * Reserved to only be used by the scene. + * @todo TODO: create an IScene interface + ********************************************************/ + virtual void SetScene( void *scene ) = 0; + /******************************************************** * Sets the function that will be called by the engine * whenever a collision occurs. @@ -380,63 +370,64 @@ namespace Oyster ********************************************************/ virtual void SetGravityNormal( const ::Oyster::Math::Float3 &normalizedVector ) = 0; - /******************************************************** - * To not be called if is in Engine - * Use API::SetMomentOfInertiaTensor_KeepVelocity(...) instead - ********************************************************/ - virtual void SetMomentOfInertiaTensor_KeepVelocity( const ::Oyster::Math::Float4x4 &localI ) = 0; - - /******************************************************** - * To not be called if is in Engine - * Use API::SetMomentOfInertiaTensor_KeepMomentum(...) - ********************************************************/ - virtual void SetMomentOfInertiaTensor_KeepMomentum( const ::Oyster::Math::Float4x4 &localI ) = 0; - - /******************************************************** - * To not be called if is in Engine - * Use API::SetMass_KeepVelocity(...) - ********************************************************/ - virtual void SetMass_KeepVelocity( ::Oyster::Math::Float m ) = 0; - - /******************************************************** - * To not be called if is in Engine - * Use API::SetMass_KeepMomentum(...) - ********************************************************/ - virtual void SetMass_KeepMomentum( ::Oyster::Math::Float m ) = 0; - - /******************************************************** - * To not be called if is in Engine - * Use API::SetCenter(...) - ********************************************************/ - virtual void SetCenter( const ::Oyster::Math::Float3 &worldPos ) = 0; - - /******************************************************** - * To not be called if is in Engine - * Use API::SetRotation(...) - ********************************************************/ - virtual void SetRotation( const ::Oyster::Math::Float4x4 &rotation ) = 0; - - /******************************************************** - * To not be called if is in Engine - * Use API::SetOrientation(...) - ********************************************************/ - virtual void SetOrientation( const ::Oyster::Math::Float4x4 &orientation ) = 0; + ///******************************************************** + // * To not be called if is in Engine + // * Use API::SetMomentOfInertiaTensor_KeepVelocity(...) instead + // ********************************************************/ + //virtual void SetMomentOfInertiaTensor_KeepVelocity( const ::Oyster::Math::Float4x4 &localI ) = 0; + // + ///******************************************************** + // * To not be called if is in Engine + // * Use API::SetMomentOfInertiaTensor_KeepMomentum(...) + // ********************************************************/ + //virtual void SetMomentOfInertiaTensor_KeepMomentum( const ::Oyster::Math::Float4x4 &localI ) = 0; + // + ///******************************************************** + // * To not be called if is in Engine + // * Use API::SetMass_KeepVelocity(...) + // ********************************************************/ + //virtual void SetMass_KeepVelocity( ::Oyster::Math::Float m ) = 0; + // + ///******************************************************** + // * To not be called if is in Engine + // * Use API::SetMass_KeepMomentum(...) + // ********************************************************/ + //virtual void SetMass_KeepMomentum( ::Oyster::Math::Float m ) = 0; + // + ///******************************************************** + // * To not be called if is in Engine + // * Use API::SetCenter(...) + // ********************************************************/ + //virtual void SetCenter( const ::Oyster::Math::Float3 &worldPos ) = 0; + // + ///******************************************************** + // * To not be called if is in Engine + // * Use API::SetRotation(...) + // ********************************************************/ + //virtual void SetRotation( const ::Oyster::Math::Float4x4 &rotation ) = 0; + // + ///******************************************************** + // * To not be called if is in Engine + // * Use API::SetOrientation(...) + // ********************************************************/ + //virtual void SetOrientation( const ::Oyster::Math::Float4x4 &orientation ) = 0; - /******************************************************** - * To not be called if is in Engine - * Use API::SetSize(...) - ********************************************************/ - virtual void SetSize( const ::Oyster::Math::Float3 &size ) = 0; + ///******************************************************** + // * To not be called if is in Engine + // * Use API::SetSize(...) + // ********************************************************/ + //virtual void SetSize( const ::Oyster::Math::Float3 &size ) = 0; - /******************************************************** - * To not be called if is in Engine - * Use API::?? @todo TODO: - ********************************************************/ - virtual void SetMomentum( const ::Oyster::Math::Float3 &worldG ) = 0; + ///******************************************************** + // * To not be called if is in Engine + // * Use API::?? @todo TODO: + // ********************************************************/ + //virtual void SetMomentum( const ::Oyster::Math::Float3 &worldG ) = 0; }; } } #include "PhysicsStructs.h" +#include "PhysicsFormula.h" #endif \ No newline at end of file diff --git a/Code/GamePhysics/PhysicsFormula-Impl.h b/Code/GamePhysics/PhysicsFormula-Impl.h new file mode 100644 index 00000000..323fd732 --- /dev/null +++ b/Code/GamePhysics/PhysicsFormula-Impl.h @@ -0,0 +1,76 @@ +#ifndef PHYSICS_FORMULA_IMPL_H +#define PHYSICS_FORMULA_IMPL_H + +#include "PhysicsFormula.h" +#include "OysterPhysics3D.h" + +namespace Oyster { namespace Physics { namespace Formula +{ + namespace MomentOfInertia + { + inline ::Oyster::Math::Float4x4 CreateSphereMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float radius ) + { + return ::Oyster::Physics3D::Formula::MomentOfInertia::Sphere(mass, radius); + } + + inline ::Oyster::Math::Float4x4 CreateHollowSphereMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float radius ) + { + return ::Oyster::Physics3D::Formula::MomentOfInertia::HollowSphere(mass, radius); + } + + inline ::Oyster::Math::Float4x4 CreateCuboidMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float height, const ::Oyster::Math::Float width, const ::Oyster::Math::Float depth ) + { + return ::Oyster::Physics3D::Formula::MomentOfInertia::Cuboid(mass, height, width, depth); + } + + inline ::Oyster::Math::Float4x4 CreateCylinderMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float height, const ::Oyster::Math::Float radius ) + { + return ::Oyster::Physics3D::Formula::MomentOfInertia::Cylinder(mass, height, radius); + } + + inline ::Oyster::Math::Float4x4 CreateRodMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float length ) + { + return ::Oyster::Physics3D::Formula::MomentOfInertia::RodCenter(mass, length); + } + } + + namespace CollisionResponse + { + inline ::Oyster::Math::Float Bounce( ::Oyster::Math::Float e, ::Oyster::Math::Float mA, ::Oyster::Math::Float gA, ::Oyster::Math::Float mB, ::Oyster::Math::Float gB ) + { + //return (e + 1) * (mB*gA - mA*gB) / (mA + mB); + return (e + 1) * (mA*gB - mB*gA) / (mA + mB); + } + + inline ::Oyster::Math::Float4 Friction( ::Oyster::Math::Float i, ::Oyster::Math::Float4 iN, ::Oyster::Math::Float4 momA, ::Oyster::Math::Float sFA, ::Oyster::Math::Float dFA, ::Oyster::Math::Float mA, ::Oyster::Math::Float4 momB, ::Oyster::Math::Float sFB, ::Oyster::Math::Float dFB, ::Oyster::Math::Float mB ) + { + // FRICTION + // Relative momentum after normal impulse + ::Oyster::Math::Float4 relativeMomentum = momB - momA; + + ::Oyster::Math::Float4 tanFriction = relativeMomentum - relativeMomentum.Dot( iN )*iN; + tanFriction.Normalize(); + + ::Oyster::Math::Float magnitudeFriction = -relativeMomentum.Dot( tanFriction ); + magnitudeFriction = magnitudeFriction*mA*mB/( mA + mB ); + + ::Oyster::Math::Float mu = 0.5f*( sFA + sFB ); + + ::Oyster::Math::Float4 frictionImpulse; + if( abs(magnitudeFriction) < i*mu ) + { + frictionImpulse = magnitudeFriction*tanFriction; + } + else + { + ::Oyster::Math::Float dynamicFriction = 0.5f*( dFA + dFB ); + frictionImpulse = -i*tanFriction*dynamicFriction; + } + + return ( 1 / mA )*frictionImpulse; + } + } + +} } } + +#endif \ No newline at end of file diff --git a/Code/GamePhysics/PhysicsFormula.h b/Code/GamePhysics/PhysicsFormula.h new file mode 100644 index 00000000..fe91ae3a --- /dev/null +++ b/Code/GamePhysics/PhysicsFormula.h @@ -0,0 +1,35 @@ +#ifndef PHYSICS_FORMULA_H +#define PHYSICS_FORMULA_H + +#include "OysterMath.h" +#include "OysterPhysics3D.h" + +namespace Oyster { namespace Physics { namespace Formula +{ + namespace MomentOfInertia + { + ::Oyster::Math::Float4x4 CreateSphereMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float radius ); + ::Oyster::Math::Float4x4 CreateHollowSphereMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float radius ); + ::Oyster::Math::Float4x4 CreateCuboidMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float height, const ::Oyster::Math::Float width, const ::Oyster::Math::Float depth ); + ::Oyster::Math::Float4x4 CreateCylinderMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float height, const ::Oyster::Math::Float radius ); + ::Oyster::Math::Float4x4 CreateRodMatrix( const ::Oyster::Math::Float mass, const ::Oyster::Math::Float length ); + } + + namespace CollisionResponse + { + ::Oyster::Math::Float Bounce( ::Oyster::Math::Float coeffOfRestitution, + ::Oyster::Math::Float massA, ::Oyster::Math::Float momentumA, + ::Oyster::Math::Float massB, ::Oyster::Math::Float momentumB ); + + ::Oyster::Math::Float4 Friction( ::Oyster::Math::Float impulse, ::Oyster::Math::Float4 impulseNormal, + ::Oyster::Math::Float4 momentumA, ::Oyster::Math::Float staticFrictionA, + ::Oyster::Math::Float dynamicFrictionA, ::Oyster::Math::Float massA, + ::Oyster::Math::Float4 momentumB, ::Oyster::Math::Float staticFrictionB, + ::Oyster::Math::Float dynamicFrictionB, ::Oyster::Math::Float massB ); + + } +} } } + +#include "PhysicsFormula-Impl.h" + +#endif \ No newline at end of file diff --git a/Code/GamePhysics/PhysicsStructs-Impl.h b/Code/GamePhysics/PhysicsStructs-Impl.h index 3de46ee2..e7704460 100644 --- a/Code/GamePhysics/PhysicsStructs-Impl.h +++ b/Code/GamePhysics/PhysicsStructs-Impl.h @@ -10,8 +10,8 @@ namespace Oyster { namespace Physics inline SimpleBodyDescription::SimpleBodyDescription() { this->rotation = ::Oyster::Math::Float4x4::identity; - this->centerPosition = ::Oyster::Math::Float3::null; - this->size = ::Oyster::Math::Float3( 1.0f ); + this->centerPosition = ::Oyster::Math::Float4::null; + this->size = ::Oyster::Math::Float4( 1.0f ); this->mass = 12.0f; this->inertiaTensor = ::Oyster::Math::Float4x4::identity; this->subscription = NULL; @@ -21,33 +21,77 @@ namespace Oyster { namespace Physics inline SphericalBodyDescription::SphericalBodyDescription() { this->rotation = ::Oyster::Math::Float4x4::identity; - this->centerPosition = ::Oyster::Math::Float3::null; + this->centerPosition = ::Oyster::Math::Float4::null; this->radius = 0.5f; this->mass = 10.0f; this->subscription = NULL; this->ignoreGravity = false; } - - inline CustomBodyState::CustomBodyState( const ::Oyster::Math::Float3 &reach, const ::Oyster::Math::Float3 ¢erPos, const ::Oyster::Math::Float3 &rotation ) + inline CustomBodyState::CustomBodyState( ::Oyster::Math::Float mass, ::Oyster::Math::Float restitutionCoeff, ::Oyster::Math::Float staticFrictionCoeff, ::Oyster::Math::Float kineticFrictionCoeff, const ::Oyster::Math::Float4x4 &inertiaTensor, const ::Oyster::Math::Float4 &reach, const ::Oyster::Math::Float4 ¢erPos, const ::Oyster::Math::Float4 &rotation, const ::Oyster::Math::Float4 &linearMomentum, const ::Oyster::Math::Float4 &angularMomentum ) { - this->reach = ::Oyster::Math::Float4( reach, 0.0f ); - this->centerPos = ::Oyster::Math::Float4( centerPos, 1.0f ); - this->angularAxis = ::Oyster::Math::Float4( rotation, 0.0f ); - this->isSpatiallyAltered = this->isDisturbed = false; + this->mass = mass; + this->restitutionCoeff = restitutionCoeff; + this->staticFrictionCoeff = staticFrictionCoeff; + this->kineticFrictionCoeff = kineticFrictionCoeff; + this->inertiaTensor = inertiaTensor; + this->reach = reach; + this->centerPos = centerPos; + this->angularAxis = rotation; + this->linearMomentum = linearMomentum; + this->angularMomentum = angularMomentum; + this->linearImpulse = this->angularImpulse = ::Oyster::Math::Float4::null; + this->deltaPos = this->deltaAxis = ::Oyster::Math::Float4::null; + this->isSpatiallyAltered = this->isDisturbed = this->isForwarded = false; } inline CustomBodyState & CustomBodyState::operator = ( const CustomBodyState &state ) { + this->mass = state.mass; + this->restitutionCoeff = state.restitutionCoeff; + this->staticFrictionCoeff = state.staticFrictionCoeff; + this->kineticFrictionCoeff = state.kineticFrictionCoeff; + this->inertiaTensor = state.inertiaTensor; this->reach = state.reach; this->centerPos = state.centerPos; this->angularAxis = state.angularAxis; - + this->linearMomentum = state.linearMomentum; + this->angularMomentum = state.angularMomentum; + this->linearImpulse = state.linearImpulse; + this->angularImpulse = state.angularImpulse; + this->deltaPos = state.deltaPos; + this->deltaAxis = state.deltaAxis; this->isSpatiallyAltered = state.isSpatiallyAltered; this->isDisturbed = state.isDisturbed; + this->isForwarded = state.isForwarded; return *this; } + inline const ::Oyster::Math::Float CustomBodyState::GetMass() const + { + return this->mass; + } + + inline const ::Oyster::Math::Float CustomBodyState::GetRestitutionCoeff() const + { + return this->restitutionCoeff; + } + + inline const ::Oyster::Math::Float CustomBodyState::GetFrictionCoeff_Static() const + { + return this->staticFrictionCoeff; + } + + inline const ::Oyster::Math::Float CustomBodyState::GetFrictionCoeff_Kinetic() const + { + return this->kineticFrictionCoeff; + } + + inline const ::Oyster::Math::Float4x4 & CustomBodyState::GetMomentOfInertia() const + { + return this->inertiaTensor; + } + inline const ::Oyster::Math::Float4 & CustomBodyState::GetReach() const { return this->reach; @@ -73,25 +117,116 @@ namespace Oyster { namespace Physics return ::Oyster::Math3D::RotationMatrix( this->GetAngularAxis().xyz ); } - inline void CustomBodyState::SetSize( const ::Oyster::Math::Float3 &size ) + inline ::Oyster::Math::Float4x4 CustomBodyState::GetOrientation() const + { + return ::Oyster::Math3D::OrientationMatrix( this->angularAxis.xyz, this->centerPos.xyz ); + } + + inline ::Oyster::Math::Float4x4 CustomBodyState::GetView() const + { + return ::Oyster::Math3D::ViewMatrix( this->angularAxis.xyz, this->centerPos.xyz ); + } + + inline const ::Oyster::Math::Float4 & CustomBodyState::GetLinearMomentum() const + { + return this->linearMomentum; + } + + inline ::Oyster::Math::Float4 CustomBodyState::GetLinearMomentum( const ::Oyster::Math::Float4 &at ) const + { + //return this->linearMomentum + ::Oyster::Physics3D::Formula::TangentialLinearMomentum( this->angularMomentum, at - this->centerPos ); // C3083 error? + return this->linearMomentum + ::Oyster::Math::Float4( this->angularMomentum.xyz.Cross((at - this->centerPos).xyz), 0.0f ); + } + + inline const ::Oyster::Math::Float4 & CustomBodyState::GetAngularMomentum() const + { + return this->angularMomentum; + } + + inline const ::Oyster::Math::Float4 & CustomBodyState::GetLinearImpulse() const + { + return this->linearImpulse; + } + + inline const ::Oyster::Math::Float4 & CustomBodyState::GetAngularImpulse() const + { + return this->angularImpulse; + } + + inline const ::Oyster::Math::Float4 & CustomBodyState::GetForward_DeltaPos() const + { + return this->deltaPos; + } + + inline const ::Oyster::Math::Float4 & CustomBodyState::GetForward_DeltaAxis() const + { + return this->deltaAxis; + } + + inline void CustomBodyState::SetMass_KeepMomentum( ::Oyster::Math::Float m ) + { + this->mass = m; + } + + inline void CustomBodyState::SetMass_KeepVelocity( ::Oyster::Math::Float m ) + { + if( m != 0.0f ) + { // sanity block! + // Formula::LinearMomentum( m, Formula::LinearVelocity(this->mass, this->linearMomentum) ) + // is the same as (this->linearMomentum / this->mass) * m = (m / this->mass) * this->linearMomentum + this->linearMomentum *= (m / this->mass); + this->mass = m; + } + } + + inline void CustomBodyState::SetRestitutionCoeff( ::Oyster::Math::Float e ) + { + this->restitutionCoeff = e; + } + + inline void CustomBodyState::SetFrictionCoeff( ::Oyster::Math::Float staticU, ::Oyster::Math::Float kineticU ) + { + this->staticFrictionCoeff = staticU; + this->kineticFrictionCoeff = kineticU; + } + + inline void CustomBodyState::SetMomentOfInertia_KeepMomentum( const ::Oyster::Math::Float4x4 &tensor ) + { + this->inertiaTensor = tensor; + } + + inline void CustomBodyState::SetMomentOfInertia_KeepVelocity( const ::Oyster::Math::Float4x4 &tensor ) + { + if( tensor.GetDeterminant() != 0.0f ) + { // sanity block! + ::Oyster::Math::Float4x4 rotation = ::Oyster::Math3D::RotationMatrix(this->angularAxis.xyz); + //::Oyster::Math::Float4 w = ::Oyster::Physics3D::Formula::AngularVelocity( (rotation * this->inertiaTensor).GetInverse(), this->angularMomentum ); // C3083 error? + ::Oyster::Math::Float4 w = (rotation * this->inertiaTensor).GetInverse() * this->angularMomentum; + this->inertiaTensor = tensor; + //this->angularMomentum = ::Oyster::Physics3D::Formula::AngularMomentum( rotation * tensor, w ); // C3083 error? + this->angularMomentum = rotation * tensor * w; + } + } + + inline void CustomBodyState::SetSize( const ::Oyster::Math::Float4 &size ) { this->SetReach( 0.5f * size ); } - inline void CustomBodyState::SetReach( const ::Oyster::Math::Float3 &halfSize ) + inline void CustomBodyState::SetReach( const ::Oyster::Math::Float4 &halfSize ) { this->reach.xyz = halfSize; this->reach = ::Utility::Value::Max( this->reach, ::Oyster::Math::Float4::null ); this->isSpatiallyAltered = this->isDisturbed = true; } - inline void CustomBodyState::SetCenterPosition( const ::Oyster::Math::Float3 ¢erPos ) + inline void CustomBodyState::SetCenterPosition( const ::Oyster::Math::Float4 ¢erPos ) { this->centerPos.xyz = centerPos; this->isSpatiallyAltered = this->isDisturbed = true; } - inline void CustomBodyState::SetRotation( const ::Oyster::Math::Float3 &angularAxis ) + inline void CustomBodyState::SetRotation( const ::Oyster::Math::Float4 &angularAxis ) { this->angularAxis.xyz = angularAxis; this->isSpatiallyAltered = this->isDisturbed = true; @@ -99,7 +234,78 @@ namespace Oyster { namespace Physics inline void CustomBodyState::SetRotation( const ::Oyster::Math::Float4x4 &rotation ) { - this->SetRotation( ::Oyster::Math3D::AngularAxis(rotation).xyz ); + this->SetRotation( ::Oyster::Math3D::AngularAxis(rotation) ); + } + + inline void CustomBodyState::SetOrientation( const ::Oyster::Math::Float4x4 &orientation ) + { + this->SetRotation( ::Oyster::Math3D::ExtractAngularAxis(orientation) ); + this->SetCenterPosition( orientation.v[3] ); + } + + inline void CustomBodyState::SetLinearMomentum( const ::Oyster::Math::Float4 &g ) + { + this->linearMomentum.xyz = g; + this->isDisturbed = true; + } + + inline void CustomBodyState::SetAngularMomentum( const ::Oyster::Math::Float4 &h ) + { + this->angularMomentum.xyz = h; + this->isDisturbed = true; + } + + inline void CustomBodyState::SetLinearImpulse( const ::Oyster::Math::Float4 &j ) + { + this->linearImpulse.xyz = j; + this->isDisturbed = true; + } + + inline void CustomBodyState::SetAngularImpulse( const ::Oyster::Math::Float4 &j ) + { + this->angularImpulse.xyz = j; + this->isDisturbed = true; + } + + inline void CustomBodyState::AddRotation( const ::Oyster::Math::Float4 &angularAxis ) + { + this->angularAxis += angularAxis; + this->isSpatiallyAltered = this->isDisturbed = true; + } + + inline void CustomBodyState::AddTranslation( const ::Oyster::Math::Float4 &deltaPos ) + { + this->centerPos += deltaPos; + this->isSpatiallyAltered = this->isDisturbed = true; + } + + inline void CustomBodyState::ApplyLinearImpulse( const ::Oyster::Math::Float4 &j ) + { + this->linearImpulse += j; + this->isDisturbed = true; + } + + inline void CustomBodyState::ApplyAngularImpulse( const ::Oyster::Math::Float4 &j ) + { + this->angularImpulse += j; + this->isDisturbed = true; + } + + inline void CustomBodyState::ApplyImpulse( const ::Oyster::Math::Float4 &j, const ::Oyster::Math::Float4 &at, const ::Oyster::Math::Float4 &normal ) + { + //::Oyster::Math::Float4 tangentialImpulse = ::Oyster::Physics3D::Formula::AngularMomentum( j, at - this->centerPos ); // C3083 error? + ::Oyster::Math::Float4 tangentialImpulse = ::Oyster::Math::Float4( (at - this->centerPos).xyz.Cross(j.xyz), 0.0f ); + this->linearImpulse += j - tangentialImpulse; + this->angularImpulse += tangentialImpulse; + + this->isDisturbed = true; + } + + inline void CustomBodyState::ApplyForwarding( const ::Oyster::Math::Float4 &deltaPos, const ::Oyster::Math::Float4 &deltaAxis ) + { + this->deltaPos += deltaPos; + this->deltaAxis += deltaAxis; + this->isDisturbed = this->isForwarded = true; } inline bool CustomBodyState::IsSpatiallyAltered() const @@ -111,6 +317,11 @@ namespace Oyster { namespace Physics { return this->isDisturbed; } + + inline bool CustomBodyState::IsForwarded() const + { + return this->isForwarded; + } } } } diff --git a/Code/GamePhysics/PhysicsStructs.h b/Code/GamePhysics/PhysicsStructs.h index c1f74640..3c17ae6d 100644 --- a/Code/GamePhysics/PhysicsStructs.h +++ b/Code/GamePhysics/PhysicsStructs.h @@ -11,8 +11,8 @@ namespace Oyster { namespace Physics struct SimpleBodyDescription { ::Oyster::Math::Float4x4 rotation; - ::Oyster::Math::Float3 centerPosition; - ::Oyster::Math::Float3 size; + ::Oyster::Math::Float4 centerPosition; + ::Oyster::Math::Float4 size; ::Oyster::Math::Float mass; ::Oyster::Math::Float4x4 inertiaTensor; ::Oyster::Physics::ICustomBody::EventAction_Collision subscription; @@ -24,7 +24,7 @@ namespace Oyster { namespace Physics struct SphericalBodyDescription { ::Oyster::Math::Float4x4 rotation; - ::Oyster::Math::Float3 centerPosition; + ::Oyster::Math::Float4 centerPosition; ::Oyster::Math::Float radius; ::Oyster::Math::Float mass; ::Oyster::Physics::ICustomBody::EventAction_Collision subscription; @@ -36,31 +36,77 @@ namespace Oyster { namespace Physics struct CustomBodyState { public: - CustomBodyState( const ::Oyster::Math::Float3 &reach = ::Oyster::Math::Float3::null, - const ::Oyster::Math::Float3 ¢erPos = ::Oyster::Math::Float3::null, - const ::Oyster::Math::Float3 &rotation = ::Oyster::Math::Float3::null ); + CustomBodyState( ::Oyster::Math::Float mass = 1.0f, + ::Oyster::Math::Float restitutionCoeff = 1.0f, + ::Oyster::Math::Float staticFrictionCoeff = 1.0f, + ::Oyster::Math::Float kineticFrictionCoeff = 1.0f, + const ::Oyster::Math::Float4x4 &inertiaTensor = ::Oyster::Math::Float4x4::identity, + const ::Oyster::Math::Float4 &reach = ::Oyster::Math::Float4::null, + const ::Oyster::Math::Float4 ¢erPos = ::Oyster::Math::Float4::standard_unit_w, + const ::Oyster::Math::Float4 &rotation = ::Oyster::Math::Float4::null, + const ::Oyster::Math::Float4 &linearMomentum = ::Oyster::Math::Float4::null, + const ::Oyster::Math::Float4 &angularMomentum = ::Oyster::Math::Float4::null ); CustomBodyState & operator = ( const CustomBodyState &state ); - const ::Oyster::Math::Float4 & GetReach() const; - ::Oyster::Math::Float4 GetSize() const; - const ::Oyster::Math::Float4 & GetCenterPosition() const; - const ::Oyster::Math::Float4 & GetAngularAxis() const; - ::Oyster::Math::Float4x4 GetRotation() const; - - void SetSize( const ::Oyster::Math::Float3 &size ); - void SetReach( const ::Oyster::Math::Float3 &halfSize ); - void SetCenterPosition( const ::Oyster::Math::Float3 ¢erPos ); - void SetRotation( const ::Oyster::Math::Float3 &angularAxis ); + const ::Oyster::Math::Float GetMass() const; + const ::Oyster::Math::Float GetRestitutionCoeff() const; + const ::Oyster::Math::Float GetFrictionCoeff_Static() const; + const ::Oyster::Math::Float GetFrictionCoeff_Kinetic() const; + const ::Oyster::Math::Float4x4 & GetMomentOfInertia() const; + const ::Oyster::Math::Float4 & GetReach() const; + ::Oyster::Math::Float4 GetSize() const; + const ::Oyster::Math::Float4 & GetCenterPosition() const; + const ::Oyster::Math::Float4 & GetAngularAxis() const; + ::Oyster::Math::Float4x4 GetRotation() const; + ::Oyster::Math::Float4x4 GetOrientation() const; + ::Oyster::Math::Float4x4 GetView() const; + const ::Oyster::Math::Float4 & GetLinearMomentum() const; + ::Oyster::Math::Float4 GetLinearMomentum( const ::Oyster::Math::Float4 &at ) const; + const ::Oyster::Math::Float4 & GetAngularMomentum() const; + const ::Oyster::Math::Float4 & GetLinearImpulse() const; + const ::Oyster::Math::Float4 & GetAngularImpulse() const; + const ::Oyster::Math::Float4 & GetForward_DeltaPos() const; + const ::Oyster::Math::Float4 & GetForward_DeltaAxis() const; + + void SetMass_KeepMomentum( ::Oyster::Math::Float m ); + void SetMass_KeepVelocity( ::Oyster::Math::Float m ); + void SetRestitutionCoeff( ::Oyster::Math::Float e ); + void SetFrictionCoeff( ::Oyster::Math::Float staticU, ::Oyster::Math::Float kineticU ); + void SetMomentOfInertia_KeepMomentum( const ::Oyster::Math::Float4x4 &tensor ); + void SetMomentOfInertia_KeepVelocity( const ::Oyster::Math::Float4x4 &tensor ); + void SetSize( const ::Oyster::Math::Float4 &size ); + void SetReach( const ::Oyster::Math::Float4 &halfSize ); + void SetCenterPosition( const ::Oyster::Math::Float4 ¢erPos ); + void SetRotation( const ::Oyster::Math::Float4 &angularAxis ); void SetRotation( const ::Oyster::Math::Float4x4 &rotation ); + void SetOrientation( const ::Oyster::Math::Float4x4 &orientation ); + void SetLinearMomentum( const ::Oyster::Math::Float4 &g ); + void SetAngularMomentum( const ::Oyster::Math::Float4 &h ); + void SetLinearImpulse( const ::Oyster::Math::Float4 &j ); + void SetAngularImpulse( const ::Oyster::Math::Float4 &j ); + + void AddRotation( const ::Oyster::Math::Float4 &angularAxis ); + void AddTranslation( const ::Oyster::Math::Float4 &deltaPos ); + + void ApplyLinearImpulse( const ::Oyster::Math::Float4 &j ); + void ApplyAngularImpulse( const ::Oyster::Math::Float4 &j ); + void ApplyImpulse( const ::Oyster::Math::Float4 &j, const ::Oyster::Math::Float4 &at, const ::Oyster::Math::Float4 &normal ); + void ApplyForwarding( const ::Oyster::Math::Float4 &deltaPos, const ::Oyster::Math::Float4 &deltaAxis ); bool IsSpatiallyAltered() const; bool IsDisturbed() const; + bool IsForwarded() const; private: + ::Oyster::Math::Float mass, restitutionCoeff, staticFrictionCoeff, kineticFrictionCoeff; + ::Oyster::Math::Float4x4 inertiaTensor; ::Oyster::Math::Float4 reach, centerPos, angularAxis; + ::Oyster::Math::Float4 linearMomentum, angularMomentum; + ::Oyster::Math::Float4 linearImpulse, angularImpulse; + ::Oyster::Math::Float4 deltaPos, deltaAxis; // Forwarding data sum - bool isSpatiallyAltered, isDisturbed; + bool isSpatiallyAltered, isDisturbed, isForwarded; }; } } } diff --git a/Code/OysterMath/LinearMath.h b/Code/OysterMath/LinearMath.h index 8bca1c19..b5eab471 100644 --- a/Code/OysterMath/LinearMath.h +++ b/Code/OysterMath/LinearMath.h @@ -266,6 +266,12 @@ namespace LinearAlgebra3D return ::std::asin( ::LinearAlgebra::Vector4(rotationMatrix.v[1].z, rotationMatrix.v[2].x, rotationMatrix.v[0].y, 1) ); } + template + inline ::LinearAlgebra::Vector4 ExtractAngularAxis( const ::LinearAlgebra::Matrix4x4 &orientationMatrix ) + { + return ::std::asin( ::LinearAlgebra::Vector4(orientationMatrix.v[1].z, orientationMatrix.v[2].x, orientationMatrix.v[0].y, 0) ); + } + template inline ::LinearAlgebra::Matrix4x4 & TranslationMatrix( const ::LinearAlgebra::Vector3 &position, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) { @@ -275,6 +281,106 @@ namespace LinearAlgebra3D 0, 0, 0, 1 ); } + template + inline ::LinearAlgebra::Quaternion Rotation( const ScalarType &radian, const ::LinearAlgebra::Vector3 &normalizedAxis ) + { + ScalarType r = radian * 0.5f, + s = std::sin( r ), + c = std::cos( r ); + + return ::LinearAlgebra::Quaternion( normalizedAxis * s, c ); + } + + template + inline ::LinearAlgebra::Quaternion Rotation( const ScalarType &radian, const ::LinearAlgebra::Vector4 &normalizedAxis ) + { + ScalarType r = radian * 0.5f, + s = std::sin( r ), + c = std::cos( r ); + + return ::LinearAlgebra::Quaternion( (normalizedAxis * s).xyz, c ); + } + + template + inline ::LinearAlgebra::Quaternion Rotation( const ::LinearAlgebra::Vector3 &angularAxis ) + { + ScalarType radius = angularAxis.Dot( angularAxis ); + if( radius != 0 ) + { + radius = (ScalarType)::std::sqrt( radius ); + return Rotation( radius, angularAxis / radius ); + } + else + { + return ::LinearAlgebra::Quaternion::identity; + } + } + + template + inline ::LinearAlgebra::Quaternion Rotation( const ::LinearAlgebra::Vector4 &angularAxis ) + { + ScalarType radius = angularAxis.Dot( angularAxis ); + if( radius != 0 ) + { + radius = (ScalarType)::std::sqrt( radius ); + return Rotation( radius, angularAxis / radius ); + } + else + { + return ::LinearAlgebra::Quaternion::identity; + } + } + + template + inline ::LinearAlgebra::Matrix4x4 & RotationMatrix( const ::LinearAlgebra::Quaternion &rotationQuaternion, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) + { + ::LinearAlgebra::Quaternion conjugate = rotationQuaternion.GetConjugate(); + + targetMem.v[0] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(1,0,0)*conjugate).imaginary, 0 ); + targetMem.v[1] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(0,1,0)*conjugate).imaginary, 0 ); + targetMem.v[2] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(0,0,1)*conjugate).imaginary, 0 ); + targetMem.v[3] = ::LinearAlgebra::Vector4::standard_unit_w; + return targetMem; + } + + template + inline ::LinearAlgebra::Matrix4x4 & OrientationMatrix( const ::LinearAlgebra::Quaternion &rotationQuaternion, const ::LinearAlgebra::Vector3 &translation, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) + { + ::LinearAlgebra::Quaternion conjugate = rotationQuaternion.GetConjugate(); + + targetMem.v[0] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(1,0,0)*conjugate).imaginary, 0 ); + targetMem.v[1] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(0,1,0)*conjugate).imaginary, 0 ); + targetMem.v[2] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(0,0,1)*conjugate).imaginary, 0 ); + targetMem.v[3] = ::LinearAlgebra::Vector4( translation, 1 ); + return targetMem; + } + + template + inline ::LinearAlgebra::Matrix4x4 & OrientationMatrix( const ::LinearAlgebra::Quaternion &rotationQuaternion, const ::LinearAlgebra::Vector4 &translation, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) + { + ::LinearAlgebra::Quaternion conjugate = rotationQuaternion.GetConjugate(); + + targetMem.v[0] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(1,0,0)*conjugate).imaginary, 0 ); + targetMem.v[1] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(0,1,0)*conjugate).imaginary, 0 ); + targetMem.v[2] = ::LinearAlgebra::Vector4( (rotationQuaternion*::LinearAlgebra::Vector3(0,0,1)*conjugate).imaginary, 0 ); + targetMem.v[3] = translation; + return targetMem; + } + + template + inline ::LinearAlgebra::Matrix4x4 & ViewMatrix( const ::LinearAlgebra::Quaternion &rotationQuaternion, const ::LinearAlgebra::Vector3 &translation, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) + { + OrientationMatrix( rotationQuaternion, translation, targetMem ); + return InverseOrientationMatrix( targetMem, targetMem ); + } + + template + inline ::LinearAlgebra::Matrix4x4 & ViewMatrix( const ::LinearAlgebra::Quaternion &rotationQuaternion, const ::LinearAlgebra::Vector4 &translation, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) + { + OrientationMatrix( rotationQuaternion, translation, targetMem ); + return InverseOrientationMatrix( targetMem, targetMem ); + } + template inline ::LinearAlgebra::Matrix3x3 & RotationMatrix_AxisX( const ScalarType &radian, ::LinearAlgebra::Matrix3x3 &targetMem = ::LinearAlgebra::Matrix3x3() ) { @@ -400,18 +506,35 @@ namespace LinearAlgebra3D } template - ::LinearAlgebra::Matrix4x4 & OrientationMatrix( const ::LinearAlgebra::Vector3 &sumDeltaAngularAxis, const ::LinearAlgebra::Vector3 &sumTranslation, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) - { /** @todo TODO: not tested */ - ScalarType radian = sumDeltaAngularAxis.Dot( sumDeltaAngularAxis ); + ::LinearAlgebra::Matrix4x4 & OrientationMatrix( const ::LinearAlgebra::Vector3 &angularAxis, const ::LinearAlgebra::Vector3 &translation, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) + { + ScalarType radian = angularAxis.Dot( angularAxis ); if( radian > 0 ) { radian = ::std::sqrt( radian ); - return OrientationMatrix( sumDeltaAngularAxis / radian, radian, sumTranslation, targetMem ); + return OrientationMatrix( angularAxis / radian, radian, translation, targetMem ); } else { targetMem = ::LinearAlgebra::Matrix4x4::identity; - targetMem.v[3].xyz = sumTranslation; + targetMem.v[3].xyz = translation; + return targetMem; + } + } + + template + ::LinearAlgebra::Matrix4x4 & ViewMatrix( const ::LinearAlgebra::Vector3 &angularAxis, const ::LinearAlgebra::Vector3 &translation, ::LinearAlgebra::Matrix4x4 &targetMem = ::LinearAlgebra::Matrix4x4() ) + { + ScalarType radian = angularAxis.Dot( angularAxis ); + if( radian > 0 ) + { + radian = ::std::sqrt( radian ); + return InverseOrientationMatrix( OrientationMatrix(angularAxis / radian, radian, translation, targetMem) ); + } + else + { + targetMem = ::LinearAlgebra::Matrix4x4::identity; + targetMem.v[3].xyz = -translation; return targetMem; } } @@ -534,9 +657,17 @@ namespace LinearAlgebra3D inline ::LinearAlgebra::Vector3 VectorProjection( const ::LinearAlgebra::Vector3 &vector, const ::LinearAlgebra::Vector3 &axis ) { return axis * ( vector.Dot(axis) / axis.Dot(axis) ); } + template + inline ::LinearAlgebra::Vector4 VectorProjection( const ::LinearAlgebra::Vector4 &vector, const ::LinearAlgebra::Vector4 &axis ) + { return axis * ( vector.Dot(axis) / axis.Dot(axis) ); } + template inline ::LinearAlgebra::Vector3 NormalProjection( const ::LinearAlgebra::Vector3 &vector, const ::LinearAlgebra::Vector3 &normalizedAxis ) { return normalizedAxis * ( vector.Dot(normalizedAxis) ); } + + template + inline ::LinearAlgebra::Vector4 NormalProjection( const ::LinearAlgebra::Vector4 &vector, const ::LinearAlgebra::Vector4 &normalizedAxis ) + { return normalizedAxis * ( vector.Dot(normalizedAxis) ); } } #include "Utilities.h" diff --git a/Code/OysterMath/OysterMath.cpp b/Code/OysterMath/OysterMath.cpp index cf9fa8ae..f44de9fd 100644 --- a/Code/OysterMath/OysterMath.cpp +++ b/Code/OysterMath/OysterMath.cpp @@ -91,11 +91,61 @@ namespace Oyster { namespace Math3D return ::LinearAlgebra3D::AngularAxis( rotationMatrix ); } + Float4 ExtractAngularAxis( const Float4x4 &orientationMatrix ) + { + return ::LinearAlgebra3D::ExtractAngularAxis( orientationMatrix ); + } + Float4x4 & TranslationMatrix( const Float3 &position, Float4x4 &targetMem ) { return ::LinearAlgebra3D::TranslationMatrix( position, targetMem ); } + Quaternion Rotation( Float radian, const Float3 &normalizedAxis ) + { + return ::LinearAlgebra3D::Rotation( radian, normalizedAxis ); + } + + Quaternion Rotation( Float radian, const Float4 &normalizedAxis ) + { + return ::LinearAlgebra3D::Rotation( radian, normalizedAxis ); + } + + Quaternion Rotation( const Float3 &angularAxis ) + { + return ::LinearAlgebra3D::Rotation( angularAxis ); + } + + Quaternion Rotation( const Float4 &angularAxis ) + { + return ::LinearAlgebra3D::Rotation( angularAxis ); + } + + Float4x4 & RotationMatrix( const Quaternion &rotationQuaternion, Float4x4 &targetMem ) + { + return ::LinearAlgebra3D::RotationMatrix( rotationQuaternion, targetMem ); + } + + Float4x4 & OrientationMatrix( const Quaternion &rotationQuaternion, const Float3 &translation, Float4x4 &targetMem ) + { + return ::LinearAlgebra3D::OrientationMatrix( rotationQuaternion, translation, targetMem ); + } + + Float4x4 & OrientationMatrix( const Quaternion &rotationQuaternion, const Float4 &translation, Float4x4 &targetMem ) + { + return ::LinearAlgebra3D::OrientationMatrix( rotationQuaternion, translation, targetMem ); + } + + Float4x4 & ViewMatrix( const Quaternion &rotationQuaternion, const Float3 &translation, Float4x4 &targetMem ) + { + return ::LinearAlgebra3D::ViewMatrix( rotationQuaternion, translation, targetMem ); + } + + Float4x4 & ViewMatrix( const Quaternion &rotationQuaternion, const Float4 &translation, Float4x4 &targetMem ) + { + return ::LinearAlgebra3D::ViewMatrix( rotationQuaternion, translation, targetMem ); + } + Float4x4 & RotationMatrix_AxisX( const Float &radian, Float4x4 &targetMem ) { return ::LinearAlgebra3D::RotationMatrix_AxisX( radian, targetMem ); @@ -147,9 +197,14 @@ namespace Oyster { namespace Math3D return ::LinearAlgebra3D::OrientationMatrix( normalizedAxis, deltaRadian, sumTranslation, targetMem ); } - Float4x4 & OrientationMatrix( const Float3 &sumDeltaAngularAxis, const Float3 &sumTranslation, Float4x4 &targetMem ) + Float4x4 & OrientationMatrix( const Float3 &angularAxis, const Float3 &translation, Float4x4 &targetMem ) { - return ::LinearAlgebra3D::OrientationMatrix( sumDeltaAngularAxis, sumTranslation, targetMem ); + return ::LinearAlgebra3D::OrientationMatrix( angularAxis, translation, targetMem ); + } + + Float4x4 & ViewMatrix( const Float3 &angularAxis, const Float3 &translation, Float4x4 &targetMem ) + { + return ::LinearAlgebra3D::ViewMatrix( angularAxis, translation, targetMem ); } Float4x4 & OrientationMatrix( const Float3 &sumDeltaAngularAxis, const Float3 &sumTranslation, const Float3 ¢erOfMass, Float4x4 &targetMem ) @@ -207,8 +262,18 @@ namespace Oyster { namespace Math3D return ::LinearAlgebra3D::VectorProjection( vector, axis ); } + Float4 VectorProjection( const Float4 &vector, const Float4 &axis ) + { + return ::LinearAlgebra3D::VectorProjection( vector, axis ); + } + Float3 NormalProjection( const Float3 &vector, const Float3 &normalizedAxis ) { return ::LinearAlgebra3D::NormalProjection( vector, normalizedAxis ); } + + Float4 NormalProjection( const Float4 &vector, const Float4 &normalizedAxis ) + { + return ::LinearAlgebra3D::NormalProjection( vector, normalizedAxis ); + } } } \ No newline at end of file diff --git a/Code/OysterMath/OysterMath.h b/Code/OysterMath/OysterMath.h index 72fe7478..2fe57718 100644 --- a/Code/OysterMath/OysterMath.h +++ b/Code/OysterMath/OysterMath.h @@ -9,17 +9,19 @@ #include "LinearMath.h" #include -namespace Oyster { namespace Math /// Oyster's native math library +namespace Oyster { namespace Math //! Oyster's native math library { - typedef float Float; /// Oyster's native scalar is float + typedef float Float; //!< Oyster's native scalar is float - typedef ::LinearAlgebra::Vector2 Float2; /// 2D Linear Vector for Oyster - typedef ::LinearAlgebra::Vector3 Float3; /// 3D Linear Vector for Oyster - typedef ::LinearAlgebra::Vector4 Float4; /// 4D Linear Vector for Oyster + typedef ::LinearAlgebra::Vector2 Float2; //!< 2D Linear Vector for Oyster + typedef ::LinearAlgebra::Vector3 Float3; //!< 3D Linear Vector for Oyster + typedef ::LinearAlgebra::Vector4 Float4; //!< 4D Linear Vector for Oyster - typedef ::LinearAlgebra::Matrix2x2 Float2x2; /// 2x2 Linear Matrix for Oyster - typedef ::LinearAlgebra::Matrix3x3 Float3x3; /// 3x3 Linear Matrix for Oyster - typedef ::LinearAlgebra::Matrix4x4 Float4x4; /// 4x4 Linear Matrix for Oyster + typedef ::LinearAlgebra::Matrix2x2 Float2x2; //!< 2x2 Linear Matrix for Oyster + typedef ::LinearAlgebra::Matrix3x3 Float3x3; //!< 3x3 Linear Matrix for Oyster + typedef ::LinearAlgebra::Matrix4x4 Float4x4; //!< 4x4 Linear Matrix for Oyster + + typedef ::LinearAlgebra::Quaternion Quaternion; //!< Quaternion for Oyster typedef Float4x4 Matrix; // by popular demand typedef Float2 Vector2; // by popular demand @@ -28,20 +30,20 @@ namespace Oyster { namespace Math /// Oyster's native math library const Float pi = 3.1415926535897932384626433832795f; - /// Function Highly recommended to check at start, just in case current version is using a feature that might be available. - /// @todo TODO: create a template UniquePointer to use here + //! Function Highly recommended to check at start, just in case current version is using a feature that might be available. + //! @todo TODO: create a template UniquePointer to use here bool IsSupported(); - /// Creates a solution matrix for 'out´= 'targetMem' * 'in'. - /// Returns false if there is no explicit solution. + //! Creates a solution matrix for 'out´= 'targetMem' * 'in'. + //! Returns false if there is no explicit solution. bool SuperpositionMatrix( const Float2x2 &in, const Float2x2 &out, Float2x2 &targetMem ); - /// Creates a solution matrix for 'out´= 'targetMem' * 'in'. - /// Returns false if there is no explicit solution. + //! Creates a solution matrix for 'out´= 'targetMem' * 'in'. + //! Returns false if there is no explicit solution. bool SuperpositionMatrix( const Float3x3 &in, const Float3x3 &out, Float3x3 &targetMem ); - /// Creates a solution matrix for 'out´= 'targetMem' * 'in'. - /// Returns false if there is no explicit solution. + //! Creates a solution matrix for 'out´= 'targetMem' * 'in'. + //! Returns false if there is no explicit solution. bool SuperpositionMatrix( const Float4x4 &in, const Float4x4 &out, Float4x4 &targetMem ); } } @@ -96,54 +98,54 @@ inline ::Oyster::Math::Float3x3 operator * ( const ::Oyster::Math::Float &left, inline ::Oyster::Math::Float4x4 operator * ( const ::Oyster::Math::Float &left, const ::Oyster::Math::Float4x4 &right ) { return ::Oyster::Math::Float4x4(right) *= left; } -namespace Oyster { namespace Math2D /// Oyster's native math library specialized for 2D +namespace Oyster { namespace Math2D //! Oyster's native math library specialized for 2D { using namespace ::Oyster::Math; // deliberate inheritance from ::Oyster::Math namespace - /// If there is an Y-axis on a 2D plane, then there is an explicit X-axis on and that is what is returned. - /// Recommended too make sure that yAxis is normalized. + //! If there is an Y-axis on a 2D plane, then there is an explicit X-axis on and that is what is returned. + //! Recommended too make sure that yAxis is normalized. Float2 X_AxisTo( const Float2 &yAxis ); - /// If there is an X-axis on a 2D plane, then there is an explicit Y-axis and that is what is returned. - /// Recommended too make sure that yAxis is normalized. + //! If there is an X-axis on a 2D plane, then there is an explicit Y-axis and that is what is returned. + //! Recommended too make sure that yAxis is normalized. Float2 Y_AxisTo( const Float2 &xAxis ); - /// Sets and returns targetMem to a translationMatrix with position as translation. + //! Sets and returns targetMem to a translationMatrix with position as translation. Float3x3 & TranslationMatrix( const Float2 &position, Float3x3 &targetMem = Float3x3() ); - /// Sets and returns targetMem as a counterclockwise rotationMatrix + //! Sets and returns targetMem as a counterclockwise rotationMatrix Float3x3 & RotationMatrix( const Float &radian, Float3x3 &targetMem = Float3x3() ); - /// If rotation is assumed to be by all definitions a rotation matrix. Then this is a much faster inverse method. + //! If rotation is assumed to be by all definitions a rotation matrix. Then this is a much faster inverse method. Float2x2 & InverseRotationMatrix( const Float2x2 &rotation, Float2x2 &targetMem = Float2x2() ); - /// If rotation is assumed to be by all definitions a rotation matrix. Then this is a much faster inverse method. + //! If rotation is assumed to be by all definitions a rotation matrix. Then this is a much faster inverse method. Float3x3 & InverseRotationMatrix( const Float3x3 &rotation, Float3x3 &targetMem = Float3x3() ); - /// Sets and returns targetMem as an orientation Matrix composed by the rotation matrix and translation vector + //! Sets and returns targetMem as an orientation Matrix composed by the rotation matrix and translation vector Float3x3 & OrientationMatrix( const Float2x2 &rotation, const Float2 &translation, Float3x3 &targetMem = Float3x3() ); - /// Sets and returns targetMem as an orientation Matrix composed by the rotation matrix and translation vector + //! Sets and returns targetMem as an orientation Matrix composed by the rotation matrix and translation vector Float3x3 & OrientationMatrix( const Float3x3 &rotation, const Float2 &translation, Float3x3 &targetMem = Float3x3() ); - /// Sets and returns targetMem as an orientation Matrix with position as translation and radian rotation + //! Sets and returns targetMem as an orientation Matrix with position as translation and radian rotation Float3x3 & OrientationMatrix( const Float2 &position, const Float &radian, Float3x3 &targetMem = Float3x3() ); - /// Sets and returns targetMem as an orientation Matrix with position as translation and local y-axis directed at lookAt + //! Sets and returns targetMem as an orientation Matrix with position as translation and local y-axis directed at lookAt Float3x3 & OrientationMatrix( const Float2 &position, const Float2 &lookAt, Float3x3 &targetMem = Float3x3() ); - /// Sets and returns targetMem as an orientation Matrix that is rotated around localCenterOfRotation and then translated with position. - /// TODO: not tested + //! Sets and returns targetMem as an orientation Matrix that is rotated around localCenterOfRotation and then translated with position. + //! TODO: not tested Float3x3 & OrientationMatrix( const Float2 &position, Float radian, const Float2 &localCenterOfRotation, Float3x3 &targetMem = Float3x3() ); - /// If orientationMatrix is assumed to be by all definitions a rigid orientation matrix aka rigid body matrix. Then this is a much faster inverse method. + //! If orientationMatrix is assumed to be by all definitions a rigid orientation matrix aka rigid body matrix. Then this is a much faster inverse method. Float3x3 & InverseOrientationMatrix( const Float3x3 &orientationMatrix, Float3x3 &targetMem = Float3x3() ); - /// Returns targetmem after writing the rotation data from orientation, into it. + //! Returns targetmem after writing the rotation data from orientation, into it. Float3x3 & ExtractRotationMatrix( const Float3x3 &orientation, Float3x3 &targetMem = Float3x3() ); } } -namespace Oyster { namespace Math3D /// Oyster's native math library specialized for 3D +namespace Oyster { namespace Math3D //! Oyster's native math library specialized for 3D { using namespace ::Oyster::Math; // deliberate inheritance from ::Oyster::Math namespace @@ -153,35 +155,65 @@ namespace Oyster { namespace Math3D /// Oyster's native math library specialized //! Extracts the angularAxis from rotationMatrix Float4 AngularAxis( const Float4x4 &rotationMatrix ); - /// Sets and returns targetMem to a translationMatrix with position as translation. + //! Extracts the angularAxis from orientationMatrix + Float4 ExtractAngularAxis( const Float4x4 &orientationMatrix ); + + //! Sets and returns targetMem to a translationMatrix with position as translation. Float4x4 & TranslationMatrix( const Float3 &position, Float4x4 &targetMem = Float4x4() ); - /// Sets and returns targetMem as an counterclockwise rotation matrix around the global X-axis + /** @todo TODO: add doc */ + Quaternion Rotation( Float radian, const Float3 &normalizedAxis ); + + /** @todo TODO: add doc */ + Quaternion Rotation( Float radian, const Float3 &normalizedAxis ); + + /** @todo TODO: add doc */ + Quaternion Rotation( const Float3 &angularAxis ); + + /** @todo TODO: add doc */ + Quaternion Rotation( const Float4 &angularAxis ); + + /** @todo TODO: add doc */ + Float4x4 & RotationMatrix( const Quaternion &rotationQuaternion, Float4x4 &targetMem = Float4x4() ); + + /** @todo TODO: add doc */ + Float4x4 & OrientationMatrix( const Quaternion &rotationQuaternion, const Float3 &translation, Float4x4 &targetMem = Float4x4() ); + + /** @todo TODO: add doc */ + Float4x4 & OrientationMatrix( const Quaternion &rotationQuaternion, const Float4 &translation, Float4x4 &targetMem = Float4x4() ); + + /** @todo TODO: add doc */ + Float4x4 & ViewMatrix( const Quaternion &rotationQuaternion, const Float3 &translation, Float4x4 &targetMem = Float4x4() ); + + /** @todo TODO: add doc */ + Float4x4 & ViewMatrix( const Quaternion &rotationQuaternion, const Float4 &translation, Float4x4 &targetMem = Float4x4() ); + + //! Sets and returns targetMem as an counterclockwise rotation matrix around the global X-axis Float4x4 & RotationMatrix_AxisX( const Float &radian, Float4x4 &targetMem = Float4x4() ); - /// Sets and returns targetMem as an counterclockwise rotation matrix around the global Y-axis + //! Sets and returns targetMem as an counterclockwise rotation matrix around the global Y-axis Float4x4 & RotationMatrix_AxisY( const Float &radian, Float4x4 &targetMem = Float4x4() ); - /// Sets and returns targetMem as an counterclockwise rotation matrix around the global Z-axis + //! Sets and returns targetMem as an counterclockwise rotation matrix around the global Z-axis Float4x4 & RotationMatrix_AxisZ( const Float &radian, Float4x4 &targetMem = Float4x4() ); - /// Sets and returns targetMem as an counterclockwise rotation matrix around the angularAxis. + //! Sets and returns targetMem as an counterclockwise rotation matrix around the angularAxis. Float4x4 & RotationMatrix( const Float3 &angularAxis, Float4x4 &targetMem = Float4x4() ); - /// Sets and returns targetMem as an counterclockwise rotation matrix around the normalizedAxis. - /// Please make sure normalizedAxis is normalized. + //! Sets and returns targetMem as an counterclockwise rotation matrix around the normalizedAxis. + //! Please make sure normalizedAxis is normalized. Float4x4 & RotationMatrix( const Float &radian, const Float3 &normalizedAxis, Float4x4 &targetMem = Float4x4() ); - /// If rotation is assumed to be by all definitions a rotation matrix. Then this is a much faster inverse method. + //! If rotation is assumed to be by all definitions a rotation matrix. Then this is a much faster inverse method. Float3x3 & InverseRotationMatrix( const Float3x3 &rotation, Float3x3 &targetMem = Float3x3() ); - /// If rotation is assumed to be by all definitions a rotation matrix. Then this is a much faster inverse method. + //! If rotation is assumed to be by all definitions a rotation matrix. Then this is a much faster inverse method. Float4x4 & InverseRotationMatrix( const Float4x4 &rotation, Float4x4 &targetMem = Float4x4() ); - /// Sets and returns targetMem as an orientation Matrix composed by the rotation matrix and translation vector + //! Sets and returns targetMem as an orientation Matrix composed by the rotation matrix and translation vector Float4x4 & OrientationMatrix( const Float3x3 &rotation, const Float3 &translation, Float4x4 &targetMem = Float4x4() ); - /// Sets and returns targetMem as an orientation Matrix composed by the rotation matrix and translation vector + //! Sets and returns targetMem as an orientation Matrix composed by the rotation matrix and translation vector Float4x4 & OrientationMatrix( const Float4x4 &rotation, const Float3 &translation, Float4x4 &targetMem = Float4x4() ); /******************************************************************* @@ -191,19 +223,26 @@ namespace Oyster { namespace Math3D /// Oyster's native math library specialized * @param sumTranslation: sum of all the translation vectors. * @param targetMem: is set to a rigibody matrix that rotate counterclockwise and then translates. * @return targetMem - * @todo TODO: not tested *******************************************************************/ Float4x4 & OrientationMatrix( const Float3 &normalizedAxis, const Float & deltaRadian, const Float3 &sumTranslation, Float4x4 &targetMem = Float4x4() ); /******************************************************************* * Sets and returns targetMem as an orientation Matrix - * @param sumDeltaAngularAxis: sum of all ( (1/I) * ( L x D ) )-vectorproducts. There I is known as "moment of inertia", L as "angular momentum vector" and D the "lever vector". - * @param sumTranslation: sum of all the translation vectors. + * @param angularAxis: sum of all ( (1/I) * ( L x D ) )-vectorproducts. There I is known as "moment of inertia", L as "angular momentum vector" and D the "lever vector". + * @param translation: sum of all the translation vectors. * @param targetMem: is set to a rigibody matrix that rotate counterclockwise and then translates. * @return targetMem - * @todo TODO: not tested *******************************************************************/ - Float4x4 & OrientationMatrix( const Float3 &sumDeltaAngularAxis, const Float3 &sumTranslation, Float4x4 &targetMem = Float4x4() ); + Float4x4 & OrientationMatrix( const Float3 &angularAxis, const Float3 &translation, Float4x4 &targetMem = Float4x4() ); + + /******************************************************************* + * Sets and returns targetMem as a view Matrix + * @param angularAxis: sum of all ( (1/I) * ( L x D ) )-vectorproducts. There I is known as "moment of inertia", L as "angular momentum vector" and D the "lever vector". + * @param translation: sum of all the translation vectors. + * @param targetMem: is set to a rigibody matrix that rotate counterclockwise and then translates. + * @return targetMem + *******************************************************************/ + Float4x4 & ViewMatrix( const Float3 &angularAxis, const Float3 &translation, Float4x4 &targetMem = Float4x4() ); /******************************************************************* * Sets and returns targetMem as an orientation Matrix @@ -228,14 +267,14 @@ namespace Oyster { namespace Math3D /// Oyster's native math library specialized //! @todo TODO: Add documentation and not tested Float4x4 & ViewMatrix_LookAtPos( const Float3 &worldLookAt, const Float3 &normalizedUpVector, const Float3 &worldPos, Float4x4 &targetMem = Float4x4() ); - /// If orientationMatrix is assumed to be by all definitions a rigid orientation matrix aka rigid body matrix. Then this is a much faster inverse method. + //! If orientationMatrix is assumed to be by all definitions a rigid orientation matrix aka rigid body matrix. Then this is a much faster inverse method. Float4x4 & InverseOrientationMatrix( const Float4x4 &orientationMatrix, Float4x4 &targetMem = Float4x4() ); // O0 = T0 * R0 // O1 = T1 * T0 * R1 * R0 Float4x4 & UpdateOrientationMatrix( const Float3 &deltaPosition, const Float4x4 &deltaRotationMatrix, Float4x4 &orientationMatrix ); - /// Returns targetmem after writing the rotation data from orientation, into it. + //! Returns targetmem after writing the rotation data from orientation, into it. Float4x4 & ExtractRotationMatrix( const Float4x4 &orientation, Float4x4 &targetMem = Float4x4() ); /******************************************************************* @@ -262,13 +301,19 @@ namespace Oyster { namespace Math3D /// Oyster's native math library specialized *******************************************************************/ Float4x4 & ProjectionMatrix_Perspective( const Float &verticalFoV, const Float &aspectRatio, const Float &nearClip = ::std::numeric_limits::epsilon(), const Float &farClip = ::std::numeric_limits::max(), Float4x4 &targetMem = Float4x4() ); - /// returns the component vector of vector that is parallell with axis + //! returns the component vector of vector that is parallell with axis Float3 VectorProjection( const Float3 &vector, const Float3 &axis ); - /// returns the component vector of vector that is parallell with axis. Faster than VectorProjection. + //! returns the component vector of vector that is parallell with axis + Float4 VectorProjection( const Float4 &vector, const Float4 &axis ); + + //! returns the component vector of vector that is parallell with axis. Faster than VectorProjection. Float3 NormalProjection( const Float3 &vector, const Float3 &normalizedAxis ); - /// Helper inline function that sets and then returns targetMem = projection * view + //! returns the component vector of vector that is parallell with axis. Faster than VectorProjection. + Float4 NormalProjection( const Float4 &vector, const Float4 &normalizedAxis ); + + //! Helper inline function that sets and then returns targetMem = projection * view inline Float4x4 & ViewProjectionMatrix( const Float4x4 &view, const Float4x4 &projection, Float4x4 &targetMem = Float4x4() ) { return targetMem = projection * view; } @@ -280,7 +325,7 @@ namespace Oyster { namespace Math3D /// Oyster's native math library specialized inline Float4x4 TransformMatrix( const Float4x4 &transformer, const Float4x4 &transformee ) { return transformer * transformee; } - /// Helper inline function that sets and then returns targetMem = transformer * transformee + //! Helper inline function that sets and then returns targetMem = transformer * transformee inline Float4 & TransformVector( const Float4x4 &transformer, const Float4 &transformee, Float4 &targetMem = Float4() ) { return targetMem = transformer * transformee; } } } diff --git a/Code/OysterMath/Quaternion.h b/Code/OysterMath/Quaternion.h index fd19100f..da790f75 100644 --- a/Code/OysterMath/Quaternion.h +++ b/Code/OysterMath/Quaternion.h @@ -22,8 +22,10 @@ namespace LinearAlgebra char byte[sizeof(ScalarType[2])]; }; + static const Quaternion null; + static const Quaternion identity; + Quaternion( ); - Quaternion( const Quaternion &quaternion ); Quaternion( const Vector3 &imaginary, const ScalarType &real ); operator ScalarType* ( ); @@ -53,40 +55,54 @@ namespace LinearAlgebra // Body /////////////////////////////////////////////////////////////////////////////////// + template const Quaternion Quaternion::null = Quaternion( Vector3((ScalarType)0), (ScalarType)0 ); + template const Quaternion Quaternion::identity = Quaternion( Vector3((ScalarType)0), (ScalarType)1 ); + template Quaternion::Quaternion( ) : imaginary(), real() {} template - Quaternion::Quaternion( const Quaternion &quaternion ) - { this->imaginary = quaternion.imaginary; this->real = quaternion.real; } - - template - Quaternion::Quaternion( const Vector3 &_imaginary, const ScalarType &_real ) - { this->imaginary = _imaginary; this->real = _real; } + Quaternion::Quaternion( const Vector3 &imaginary, const ScalarType &real ) + { + this->imaginary = imaginary; + this->real = real; + } template inline Quaternion::operator ScalarType* ( ) - { return this->element; } + { + return this->element; + } template inline Quaternion::operator const ScalarType* ( ) const - { return this->element; } + { + return this->element; + } template inline Quaternion::operator char* ( ) - { return this->byte; } + { + return this->byte; + } template inline Quaternion::operator const char* ( ) const - { return this->byte; } + { + return this->byte; + } template inline ScalarType & Quaternion::operator [] ( int i ) - { return this->element[i]; } + { + return this->element[i]; + } template inline const ScalarType & Quaternion::operator [] ( int i ) const - { return this->element[i]; } + { + return this->element[i]; + } template Quaternion & Quaternion::operator = ( const Quaternion &quaternion ) @@ -154,27 +170,39 @@ namespace LinearAlgebra template inline Quaternion Quaternion::operator * ( const ScalarType &scalar ) const - { return Quaternion(*this) *= scalar; } + { + return Quaternion(*this) *= scalar; + } template inline Quaternion Quaternion::operator / ( const ScalarType &scalar ) const - { return Quaternion(*this) /= scalar; } + { + return Quaternion(*this) /= scalar; + } template inline Quaternion Quaternion::operator + ( const Quaternion &quaternion ) const - { return Quaternion(*this) += quaternion; } + { + return Quaternion(*this) += quaternion; + } template inline Quaternion Quaternion::operator - ( const Quaternion &quaternion ) const - { return Quaternion(*this) -= quaternion; } + { + return Quaternion(*this) -= quaternion; + } template inline Quaternion Quaternion::operator - ( ) const - { return Quaternion(-this->imaginary, -this->real); } + { + return Quaternion(-this->imaginary, -this->real); + } template inline Quaternion Quaternion::GetConjugate( ) const - { return Quaternion(-this->imaginary, this->real ); } + { + return Quaternion(-this->imaginary, this->real ); + } } #endif \ No newline at end of file diff --git a/Code/OysterPhysics3D/Box.cpp b/Code/OysterPhysics3D/Box.cpp index 382c6732..f55415b7 100644 --- a/Code/OysterPhysics3D/Box.cpp +++ b/Code/OysterPhysics3D/Box.cpp @@ -16,10 +16,17 @@ Box::Box( ) : ICollideable(Type_box) } Box::Box( const Float4x4 &r, const Float3 &p, const Float3 &s ) : ICollideable(Type_box) +{ + this->rotation = r; + this->center = Float4( p, 1.0f ); + this->boundingOffset = Float4( s * 0.5f , 0.0f); +} + +Box::Box( const Float4x4 &r, const Float4 &p, const Float4 &s ) : ICollideable(Type_box) { this->rotation = r; this->center = p; - this->boundingOffset = Float3(s*0.5); + this->boundingOffset = s * 0.5f; } Box::~Box( ) {} @@ -41,16 +48,35 @@ bool Box::Intersects( const ICollideable &target ) const { switch( target.type ) { - case Type_universe: return true; - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - case Type_ray: return Utility::Intersect( *this, *(Ray*)&target, ((Ray*)&target)->collisionDistance ); - case Type_sphere: return Utility::Intersect( *this, *(Sphere*)&target ); - case Type_plane: return Utility::Intersect( *this, *(Plane*)&target ); - // case Type_triangle: return false; // TODO: : - case Type_box_axis_aligned: return Utility::Intersect( *this, *(BoxAxisAligned*)&target ); - case Type_box: return Utility::Intersect( *this, *(Box*)&target ); - // case Type_frustrum: return false; // TODO: : - default: return false; + case Type_universe: return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, ((const Ray&)target).collisionDistance ); + case Type_sphere: return Utility::Intersect( *this, (const Sphere&)target ); + case Type_plane: return Utility::Intersect( *this, (const Plane&)target ); + // case Type_triangle: return false; // TODO: : + case Type_box_axis_aligned: return Utility::Intersect( *this, (const BoxAxisAligned&)target ); + case Type_box: return Utility::Intersect( *this, (const Box&)target ); + // case Type_frustrum: return false; // TODO: : + default: return false; + } +} + +bool Box::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ + switch( target.type ) + { + case Type_universe: + worldPointOfContact = this->center; + return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target, worldPointOfContact ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, ((const Ray&)target).collisionDistance, worldPointOfContact ); + case Type_sphere: return Utility::Intersect( *this, (const Sphere&)target, worldPointOfContact ); + case Type_plane: return Utility::Intersect( *this, (const Plane&)target, worldPointOfContact ); + // case Type_triangle: return false; // TODO: : + case Type_box_axis_aligned: return Utility::Intersect( *this, (const BoxAxisAligned&)target, worldPointOfContact ); + case Type_box: return Utility::Intersect( *this, (const Box&)target, worldPointOfContact ); + // case Type_frustrum: return false; // TODO: : + default: return false; } } @@ -58,12 +84,12 @@ bool Box::Contains( const ICollideable &target ) const { switch( target.type ) { - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - // case Type_sphere: return false; // TODO: - // case Type_triangle: return false; // TODO: - // case Type_box_axis_aligned: return false; // TODO: - // case Type_box: return false; // TODO: - // case Type_frustrum: return false; // TODO: + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + //case Type_sphere: return false; // TODO: + //case Type_triangle: return false; // TODO: + //case Type_box_axis_aligned: return false; // TODO: + //case Type_box: return false; // TODO: + //case Type_frustrum: return false; // TODO: default: return false; } } \ No newline at end of file diff --git a/Code/OysterPhysics3D/Box.h b/Code/OysterPhysics3D/Box.h index d40c9f30..f98ae362 100644 --- a/Code/OysterPhysics3D/Box.h +++ b/Code/OysterPhysics3D/Box.h @@ -16,24 +16,26 @@ namespace Oyster { namespace Collision3D public: union { - struct{ ::Oyster::Math::Float4x4 rotation; ::Oyster::Math::Float3 center, boundingOffset; }; + struct{ ::Oyster::Math::Float4x4 rotation; ::Oyster::Math::Float4 center, boundingOffset; }; struct { - ::Oyster::Math::Float3 xAxis; ::Oyster::Math::Float paddingA; - ::Oyster::Math::Float3 yAxis; ::Oyster::Math::Float paddingB; - ::Oyster::Math::Float3 zAxis; ::Oyster::Math::Float paddingC; + ::Oyster::Math::Float4 xAxis; + ::Oyster::Math::Float4 yAxis; + ::Oyster::Math::Float4 zAxis; }; - char byte[sizeof(::Oyster::Math::Float4x4) + 2*sizeof(::Oyster::Math::Float3)]; + char byte[sizeof(::Oyster::Math::Float4x4) + 2*sizeof(::Oyster::Math::Float4)]; }; Box( ); Box( const ::Oyster::Math::Float4x4 &rotation, const ::Oyster::Math::Float3 &worldPos, const ::Oyster::Math::Float3 &size ); + Box( const ::Oyster::Math::Float4x4 &rotation, const ::Oyster::Math::Float4 &worldPos, const ::Oyster::Math::Float4 &size ); virtual ~Box( ); Box & operator = ( const Box &box ); virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; } } diff --git a/Code/OysterPhysics3D/BoxAxisAligned.cpp b/Code/OysterPhysics3D/BoxAxisAligned.cpp index f50f4b6d..bd10016f 100644 --- a/Code/OysterPhysics3D/BoxAxisAligned.cpp +++ b/Code/OysterPhysics3D/BoxAxisAligned.cpp @@ -14,16 +14,16 @@ BoxAxisAligned::BoxAxisAligned( ) : ICollideable(Type_box_axis_aligned) this->maxVertex = Float3( 0.5f, 0.5f, 0.5f ); } -BoxAxisAligned::BoxAxisAligned( const Float3 &_minVertex, const Float3 &_maxVertex ) : ICollideable(Type_box_axis_aligned) +BoxAxisAligned::BoxAxisAligned( const Float3 &minVertex, const Float3 &maxVertex ) : ICollideable(Type_box_axis_aligned) { - this->minVertex = _minVertex; - this->maxVertex = _maxVertex; + this->minVertex = Float4( minVertex, 1.0f ); + this->maxVertex = Float4( maxVertex, 1.0f ); } BoxAxisAligned::BoxAxisAligned( const Float &leftClip, const Float &rightClip, const Float &topClip, const Float &bottomClip, const Float &nearClip, const Float &farClip ) : ICollideable(Type_box_axis_aligned) { - this->minVertex = Float3( leftClip, bottomClip, nearClip ); - this->maxVertex = Float3( rightClip, topClip, farClip ); + this->minVertex = Float4( leftClip, bottomClip, nearClip, 1.0f ); + this->maxVertex = Float4( rightClip, topClip, farClip, 1.0f ); } BoxAxisAligned::~BoxAxisAligned( ) {} @@ -44,29 +44,36 @@ bool BoxAxisAligned::Intersects( const ICollideable &target ) const { switch( target.type ) { - case Type_universe: return true; - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - case Type_ray: return Utility::Intersect( *this, *(Ray*)&target, ((Ray*)&target)->collisionDistance ); - case Type_sphere: return Utility::Intersect( *this, *(Sphere*)&target ); - case Type_plane: return Utility::Intersect( *this, *(Plane*)&target ); - // case Type_triangle: return false; // TODO: - case Type_box_axis_aligned: return Utility::Intersect( *this, *(BoxAxisAligned*)&target ); - // case Type_box: return false; // TODO: - // case Type_frustrum: return false; // TODO: - default: return false; + case Type_universe: return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, ((const Ray&)target).collisionDistance ); + case Type_sphere: return Utility::Intersect( *this, (const Sphere&)target ); + case Type_plane: return Utility::Intersect( *this, (const Plane&)target ); + // case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( *this, (const BoxAxisAligned&)target ); + // case Type_box: return false; // TODO: + // case Type_frustrum: return false; // TODO: + default: return false; } } +bool BoxAxisAligned::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ + //! @todo TODO: implement stub properly + return this->Intersects( target ); +} + bool BoxAxisAligned::Contains( const ICollideable &target ) const { - switch( target.type ) - { - // case Type_point: return false; // TODO: - // case Type_sphere: return false; // TODO: - // case Type_triangle: return false; // TODO: - // case Type_box_axis_aligned: return false; // TODO: - // case Type_box: return false; // TODO: - // case Type_frustrum: return false; // TODO: - default: return false; - } + //switch( target.type ) + //{ + ////case Type_point: return false; // TODO: + ////case Type_sphere: return false; // TODO: + ////case Type_triangle: return false; // TODO: + ////case Type_box_axis_aligned: return false; // TODO: + ////case Type_box: return false; // TODO: + ////case Type_frustrum: return false; // TODO: + //default: return false; + //} + return false; } \ No newline at end of file diff --git a/Code/OysterPhysics3D/BoxAxisAligned.h b/Code/OysterPhysics3D/BoxAxisAligned.h index a0e109b2..2ff39463 100644 --- a/Code/OysterPhysics3D/BoxAxisAligned.h +++ b/Code/OysterPhysics3D/BoxAxisAligned.h @@ -16,8 +16,8 @@ namespace Oyster { namespace Collision3D public: union { - struct{ ::Oyster::Math::Float3 minVertex, maxVertex; }; - char byte[2*sizeof(::Oyster::Math::Float3)]; + struct{ ::Oyster::Math::Float4 minVertex, maxVertex; }; + char byte[2*sizeof(::Oyster::Math::Float4)]; }; BoxAxisAligned( ); @@ -29,6 +29,7 @@ namespace Oyster { namespace Collision3D virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; } } diff --git a/Code/OysterPhysics3D/Frustrum.cpp b/Code/OysterPhysics3D/Frustrum.cpp index 7099c2ce..54e6a67f 100644 --- a/Code/OysterPhysics3D/Frustrum.cpp +++ b/Code/OysterPhysics3D/Frustrum.cpp @@ -5,8 +5,8 @@ #include "Frustrum.h" #include "OysterCollision3D.h" -using namespace Oyster::Math; -using namespace Oyster::Collision3D; +using namespace ::Oyster::Math; +using namespace ::Oyster::Collision3D; namespace PrivateStatic { @@ -76,12 +76,12 @@ namespace PrivateStatic Frustrum::Frustrum() : ICollideable(Type_frustrum) { - this->leftPlane = Plane( Float3::standard_unit_x, -0.5f ); - this->rightPlane = Plane(-Float3::standard_unit_x, 0.5f ), - this->bottomPlane = Plane( Float3::standard_unit_y, -0.5f ); - this->topPlane = Plane(-Float3::standard_unit_y, 0.5f ); - this->nearPlane = Plane( Float3::standard_unit_z, -0.5f ); - this->farPlane = Plane(-Float3::standard_unit_z, 0.5f ); + this->leftPlane = Plane( Float4::standard_unit_x, -0.5f ); + this->rightPlane = Plane(-Float4::standard_unit_x, 0.5f ), + this->bottomPlane = Plane( Float4::standard_unit_y, -0.5f ); + this->topPlane = Plane(-Float4::standard_unit_y, 0.5f ); + this->nearPlane = Plane( Float4::standard_unit_z, -0.5f ); + this->farPlane = Plane(-Float4::standard_unit_z, 0.5f ); } Frustrum::Frustrum( const Float4x4 &vp ) : ICollideable(Type_frustrum) @@ -198,39 +198,47 @@ void Frustrum::WriteToByte( unsigned int &nextIndex, unsigned char targetMem[] ) } ::Utility::DynamicMemory::UniquePointer Frustrum::Clone( ) const -{ return ::Utility::DynamicMemory::UniquePointer( new Frustrum(*this) ); } +{ + return ::Utility::DynamicMemory::UniquePointer( new Frustrum(*this) ); +} bool Frustrum::Intersects( const ICollideable &target ) const { switch( target.type ) { - case Type_universe: return true; - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - case Type_ray: return Utility::Intersect( *this, *(Ray*)&target, ((Ray*)&target)->collisionDistance ); - case Type_sphere: return Utility::Intersect( *this, *(Sphere*)&target ); - case Type_plane: return Utility::Intersect( *this, *(Plane*)&target ); - // case Type_triangle: return false; // TODO: - case Type_box_axis_aligned: return Utility::Intersect( *this, *(BoxAxisAligned*)&target ); - case Type_box: return Utility::Intersect( *this, *(Box*)&target ); - case Type_frustrum: return Utility::Intersect( *this, *(Frustrum*)&target ); - // case Type_line: return false; // TODO: - default: return false; + case Type_universe: return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, ((const Ray&)target).collisionDistance ); + case Type_sphere: return Utility::Intersect( *this, (const Sphere&)target ); + case Type_plane: return Utility::Intersect( *this, (const Plane&)target ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( *this, (const BoxAxisAligned&)target ); + case Type_box: return Utility::Intersect( *this, (const Box&)target ); + case Type_frustrum: return Utility::Intersect( *this, (const Frustrum&)target ); + //case Type_line: return false; // TODO: + default: return false; } } +bool Frustrum::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ + //! @todo TODO: implement stub properly + return this->Intersects( target ); +} + bool Frustrum::Contains( const ICollideable &target ) const { switch( target.type ) { - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - // case Type_ray: return false; // TODO: - // case Type_sphere: return false; // TODO: - // case Type_plane: return false; // TODO: - // case Type_triangle: return false; // TODO: - // case Type_box_axis_aligned: return false; // TODO: - // case Type_box: return false; // TODO: - // case Type_frustrum: return false; // TODO: - // case Type_line: return false; // TODO: - default: return false; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + //case Type_ray: return false; // TODO: + //case Type_sphere: return false; // TODO: + //case Type_plane: return false; // TODO: + //case Type_triangle: return false; // TODO: + //case Type_box_axis_aligned: return false; // TODO: + //case Type_box: return false; // TODO: + //case Type_frustrum: return false; // TODO: + //case Type_line: return false; // TODO: + default: return false; } } \ No newline at end of file diff --git a/Code/OysterPhysics3D/Frustrum.h b/Code/OysterPhysics3D/Frustrum.h index afd8d8bd..ba5656c5 100644 --- a/Code/OysterPhysics3D/Frustrum.h +++ b/Code/OysterPhysics3D/Frustrum.h @@ -39,6 +39,7 @@ namespace Oyster { namespace Collision3D virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; diff --git a/Code/OysterPhysics3D/ICollideable.h b/Code/OysterPhysics3D/ICollideable.h index 34a86f7b..b3f61671 100644 --- a/Code/OysterPhysics3D/ICollideable.h +++ b/Code/OysterPhysics3D/ICollideable.h @@ -6,6 +6,7 @@ #ifndef OYSTER_COLLISION_3D_ICOLLIDEABLE_H #define OYSTER_COLLISION_3D_ICOLLIDEABLE_H +#include "OysterMath.h" #include "Utilities.h" namespace Oyster { namespace Collision3D //! Contains a collection of 3D shapes and intercollission algorithms. @@ -34,6 +35,7 @@ namespace Oyster { namespace Collision3D //! Contains a collection of 3D shapes virtual ~ICollideable(); virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const = 0; + virtual bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const = 0; virtual bool Intersects( const ICollideable &target ) const = 0; virtual bool Contains( const ICollideable &target ) const = 0; }; diff --git a/Code/OysterPhysics3D/Line.cpp b/Code/OysterPhysics3D/Line.cpp index 17fe55f7..cebceaff 100644 --- a/Code/OysterPhysics3D/Line.cpp +++ b/Code/OysterPhysics3D/Line.cpp @@ -46,8 +46,29 @@ bool Line::Intersects( const ICollideable &target ) const return true; } - if( this->ray.Intersects( target ) ) if( this->ray.collisionDistance >= 0.0f ) if( this->ray.collisionDistance <= this->length ) + if( this->ray.Intersects(target) ) if( this->ray.collisionDistance >= 0.0f ) if( this->ray.collisionDistance <= this->length ) + { return true; + } + + this->ray.collisionDistance = 0.0f; + return false; +} + +bool Line::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ + if( target.type == Type_universe ) + { + this->ray.collisionDistance = 0.0f; + worldPointOfContact = this->ray.origin; + return true; + } + + if( this->ray.Intersects(target) ) if( this->ray.collisionDistance >= 0.0f ) if( this->ray.collisionDistance <= this->length ) + { + worldPointOfContact = this->ray.origin + this->ray.direction * this->ray.collisionDistance; + return true; + } this->ray.collisionDistance = 0.0f; return false; diff --git a/Code/OysterPhysics3D/Line.h b/Code/OysterPhysics3D/Line.h index f062c0dc..2e6d2d55 100644 --- a/Code/OysterPhysics3D/Line.h +++ b/Code/OysterPhysics3D/Line.h @@ -30,6 +30,7 @@ namespace Oyster { namespace Collision3D virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; } } diff --git a/Code/OysterPhysics3D/OysterCollision3D.cpp b/Code/OysterPhysics3D/OysterCollision3D.cpp index 5df9761c..3ef44974 100644 --- a/Code/OysterPhysics3D/OysterCollision3D.cpp +++ b/Code/OysterPhysics3D/OysterCollision3D.cpp @@ -30,10 +30,10 @@ namespace Oyster { namespace Collision3D { namespace Utility } // returns true if miss/reject - bool BoxVsRayPerSlabCheck( const Float3 &axis, const Float &boundingOffset, const Float3 &deltaPos, const Float3 rayDirection, Float &tMin, Float &tMax ) + bool BoxVsRayPerSlabCheck( const Float4 &axis, const Float &boundingOffset, const Float4 &deltaPos, const Float4 rayDirection, Float &tMin, Float &tMax ) { // by Dan Andersson Float e = axis.Dot( deltaPos ), - f = axis.Dot( rayDirection ); + f = axis.Dot( rayDirection ); if( EqualsZero(f) ) // if axis is not parallell with ray { Float t1 = e + boundingOffset, @@ -51,12 +51,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return false; } - inline bool Contains( const Plane &container, const Float3 &pos ) + inline bool Contains( const Plane &container, const Float4 &pos ) { // by Dan Andersson return EqualsZero( container.normal.Dot( pos ) + container.phasing ); } - inline void Compare( Float &connectOffset, const Plane &plane, const Float3 &pos ) + inline void Compare( Float &connectOffset, const Plane &plane, const Float4 &pos ) { // by Dan Andersson connectOffset = plane.normal.Dot(pos); connectOffset += plane.phasing; @@ -64,7 +64,7 @@ namespace Oyster { namespace Collision3D { namespace Utility void Compare( Float &boxExtend, Float ¢erDistance, const Plane &plane, const BoxAxisAligned &box ) { // by Dan Andersson - Float3 c = (box.maxVertex + box.minVertex) * 0.5f, // box.Center + Float4 c = (box.maxVertex + box.minVertex) * 0.5f, // box.Center h = (box.maxVertex - box.minVertex) * 0.5f; // box.halfSize boxExtend = h.x * Abs(plane.normal.x); // Box max extending towards plane boxExtend += h.y * Abs(plane.normal.y); @@ -81,7 +81,7 @@ namespace Oyster { namespace Collision3D { namespace Utility centerDistance = box.center.Dot(plane.normal) + plane.phasing; // distance between box center and plane } - bool SeperatingAxisTest_AxisAlignedVsTransformedBox( const Float3 &boundingOffsetA, const Float3 &boundingOffsetB, const Float4x4 &rotationB, const Float3 &worldOffset ) + bool SeperatingAxisTest_AxisAlignedVsTransformedBox( const Float4 &boundingOffsetA, const Float4 &boundingOffsetB, const Float4x4 &rotationB, const Float4 &worldOffset ) { // by Dan Andersson /***************************************************************** @@ -103,37 +103,37 @@ namespace Oyster { namespace Collision3D { namespace Utility Float3 absWorldOffset = Abs(worldOffset); // |t|: [absWorldOffset] // s = { 1, 0, 0 } [ RA.v[0] ] - if( absWorldOffset.x > boundingOffsetA.x + boundingOffsetB.Dot(Float3(absRotationB.v[0].x, absRotationB.v[1].x, absRotationB.v[2].x)) ) + if( absWorldOffset.x > boundingOffsetA.x + boundingOffsetB.Dot(Float4(absRotationB.v[0].x, absRotationB.v[1].x, absRotationB.v[2].x, 0.0f)) ) { // |t dot s| > hA dot |s| + hB dot |s * RB| -->> t.x > hA.x + hB dot |{RB.v[0].x, RB.v[1].x, RB.v[2].x}| return false; } // s = { 0, 1, 0 } [ RA.v[1] ] - if( absWorldOffset.y > boundingOffsetA.y + boundingOffsetB.Dot(Float3(absRotationB.v[0].y, absRotationB.v[1].y, absRotationB.v[2].y)) ) + if( absWorldOffset.y > boundingOffsetA.y + boundingOffsetB.Dot(Float4(absRotationB.v[0].y, absRotationB.v[1].y, absRotationB.v[2].y, 0.0f)) ) { // t.y > hA.y + hB dot |{RB.v[0].y, RB.v[1].y, RB.v[2].y}| return false; } // s = { 0, 0, 1 } [ RA.v[2] ] - if( absWorldOffset.z > boundingOffsetA.z + boundingOffsetB.Dot(Float3(absRotationB.v[0].z, absRotationB.v[1].z, absRotationB.v[2].z)) ) + if( absWorldOffset.z > boundingOffsetA.z + boundingOffsetB.Dot(Float4(absRotationB.v[0].z, absRotationB.v[1].z, absRotationB.v[2].z, 0.0f)) ) { // t.z > hA.z + hB dot |{RB.v[0].z, RB.v[1].z, RB.v[2].z}| return false; } // s = RB.v[0].xyz - if( Abs(worldOffset.Dot(rotationB.v[0].xyz)) > boundingOffsetA.Dot(absRotationB.v[0].xyz) + boundingOffsetB.x ) + if( Abs(worldOffset.Dot(rotationB.v[0])) > boundingOffsetA.Dot(absRotationB.v[0]) + boundingOffsetB.x ) { // |t dot s| > hA dot |s| + hB dot |s * RB| -->> |t dot s| > hA dot |s| + hB dot |{1, 0, 0}| -->> |t dot s| > hA dot |s| + hB.x return false; } // s = RB.v[1].xyz - if( Abs(worldOffset.Dot(rotationB.v[1].xyz)) > boundingOffsetA.Dot(absRotationB.v[1].xyz) + boundingOffsetB.y ) + if( Abs(worldOffset.Dot(rotationB.v[1])) > boundingOffsetA.Dot(absRotationB.v[1]) + boundingOffsetB.y ) { // |t dot s| > hA dot |s| + hB.y return false; } // s = RB.v[2].xyz - if( Abs(worldOffset.Dot(rotationB.v[2].xyz)) > boundingOffsetA.Dot(absRotationB.v[2].xyz) + boundingOffsetB.z ) + if( Abs(worldOffset.Dot(rotationB.v[2])) > boundingOffsetA.Dot(absRotationB.v[2]) + boundingOffsetB.z ) { // |t dot s| > hA dot |s| + hB.z return false; } @@ -203,13 +203,187 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; } + + bool SeperatingAxisTest_AxisAlignedVsTransformedBox( const Float4 &boundingOffsetA, const Float4 &boundingOffsetB, const Float4x4 &rotationB, const Float4 &worldOffset, Float4 &worldPointOfContact ) + { // by Dan Andersson + + /***************************************************************** + * Uses the Seperating Axis Theorem + * if( |t dot s| > hA dot |s * RA| + hB dot |s * RB| ) then not intersecting + * |t dot s| > hA dot |s| + hB dot |s * RB| .. as RA = I + * + * t: objectB's offset from objectA [worldOffset] + * s: current comparison axis + * hA: boundingReach vector of objectA. Only absolute values is assumed. [boundingOffsetA] + * hB: boundingReach vector of objectB. Only absolute values is assumed. [boundingOffsetB] + * RA: rotation matrix of objectA. Is identity matrix here, thus omitted. + * RB: rotation matrix of objectB. Is transformed into objectA's view at this point. [rotationB] + * + * Note: s * RB = (RB^T * s)^T = (RB^-1 * s)^T .... vector == vector^T + *****************************************************************/ + + /***************************************************************** + * Distance Alghorithm based on .. something Dan came up with + * pi = si * ( (t dot si) * (hA dot |si|) / (hA dot |si| + hB dot |si * RB|) ) + * p = estimated point of contact + * = ( p1 + p2 + ... + p5 + p6 ) / 2 + *****************************************************************/ + + const Float4 &t = worldOffset, + &hA = boundingOffsetA, + &hB = boundingOffsetB; + Float4 s = Float4::standard_unit_x; + + Float centerSeperation = t.Dot(s), + eA = hA.Dot( Abs(s) ), + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + worldPointOfContact = s * ( centerSeperation * eA / edgeSeperation ); + + s = Float4::standard_unit_y; + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + worldPointOfContact += s * ( centerSeperation * eA / edgeSeperation ); + + s = Float4::standard_unit_z; + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + worldPointOfContact += s * ( centerSeperation * eA / edgeSeperation ); + + s = rotationB.v[0]; + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + worldPointOfContact += s * ( centerSeperation * eA / edgeSeperation ); + + s = rotationB.v[1]; + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + worldPointOfContact += s * ( centerSeperation * eA / edgeSeperation ); + + s = rotationB.v[2]; + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + worldPointOfContact += s * ( centerSeperation * eA / edgeSeperation ); // enough point of contact data gathered for approximative result. + + s = Float4( Float3::standard_unit_x.Cross(rotationB.v[0].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + s = Float4( Float3::standard_unit_x.Cross(rotationB.v[1].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + s = Float4( Float3::standard_unit_x.Cross(rotationB.v[2].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + s = Float4( Float3::standard_unit_y.Cross(rotationB.v[0].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + s = Float4( Float3::standard_unit_y.Cross(rotationB.v[1].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + s = Float4( Float3::standard_unit_y.Cross(rotationB.v[2].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + s = Float4( Float3::standard_unit_z.Cross(rotationB.v[0].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + s = Float4( Float3::standard_unit_z.Cross(rotationB.v[1].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + s = Float4( Float3::standard_unit_z.Cross(rotationB.v[2].xyz), 0.0f ); + centerSeperation = t.Dot(s); + eA = hA.Dot( Abs(s) ); + edgeSeperation = eA + hB.Dot( Abs(s * rotationB) ); + if( Abs(centerSeperation) > edgeSeperation ) + { // no intersection + return false; + } + + worldPointOfContact *= 0.5f; + return true; + } } // PUBLIC BODY ////////////////////////////////////////////////////// void Compare( Float &connectDistance, Float &connectOffsetSquared, const Ray &ray, const Point &point ) { // by Dan Andersson - Float3 dP = point.center - ray.origin; + Float4 dP = point.center - ray.origin; connectDistance = dP.Dot( ray.direction ); connectDistance /= ray.direction.Dot( ray.direction ); @@ -220,7 +394,7 @@ namespace Oyster { namespace Collision3D { namespace Utility void Compare( Float &connectDistanceA, Float &connectDistanceB, Float &connectOffsetSquared, const Ray &rayA, const Ray &rayB ) { // by Dan Andersson - Float3 dP = rayB.origin - rayA.origin; + Float4 dP = rayB.origin - rayA.origin; connectDistanceA = rayA.direction.Dot( dP ); connectDistanceA /= rayA.direction.Dot( rayA.direction ); @@ -249,6 +423,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; // Passed all tests, is in same position } + bool Intersect( const Point &pointA, const Point &pointB, ::Oyster::Math::Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const Ray &ray, const Point &point, Float &connectDistance ) { // by Dan Andersson Float connectOffsetSquared; @@ -264,6 +444,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return false; } + bool Intersect( const Ray &ray, const Point &point, ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const Ray &rayA, const Ray &rayB, Float &connectDistanceA, Float &connectDistanceB ) { // by Dan Andersson Float connectOffsetSquared; @@ -279,6 +465,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return false; } + bool Intersect( const Ray &rayA, const Ray &rayB, ::Oyster::Math::Float &connectDistanceA, ::Oyster::Math::Float &connectDistanceB, ::Oyster::Math::Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const Sphere &sphere, const Point &point ) { // by Dan Andersson Float3 dP = point.center - sphere.center; @@ -287,9 +479,15 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; } + bool Intersect( const Sphere &sphere, const Point &point, ::Oyster::Math::Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const Sphere &sphere, const Ray &ray, Float &connectDistance ) {// by Dan Andersson - Float3 dP = sphere.center - ray.origin; + Float4 dP = sphere.center - ray.origin; Float s = dP.Dot( ray.direction ), dSquared = dP.Dot( dP ), rSquared = sphere.radius * sphere.radius; @@ -307,9 +505,15 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; } + bool Intersect( const Sphere &sphere, const Ray &ray, ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const Sphere &sphereA, const Sphere &sphereB ) { // by Fredrick Johansson - Float3 C = sphereA.center; + Float4 C = sphereA.center; C -= sphereB.center; Float r = (sphereA.radius + sphereB.radius); @@ -320,6 +524,27 @@ namespace Oyster { namespace Collision3D { namespace Utility return false; } + + bool Intersect( const Sphere &sphereA, const Sphere &sphereB, ::Oyster::Math::Float4 &worldPointOfContact ) + { // by Robin Engman + Float4 C = sphereA.center; + C -= sphereB.center; + Float r = sphereA.radius + sphereB.radius; + + if ( r*r >= C.Dot(C) ) + { + Float distance; + Ray ray(sphereB.center, C.Normalize()); + + Intersect( sphereA, ray, distance ); + + worldPointOfContact = ray.origin + ray.direction*distance; + + return true; + } + + return false; + } bool Intersect( const Plane &plane, const Point &point ) { // by Dan Andersson @@ -328,6 +553,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return Private::EqualsZero(connectOffset); } + bool Intersect( const Plane &plane, const Point &point, Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const Plane &plane, const Ray &ray, Float &connectDistance ) { // by Dan Andersson Float c = plane.normal.Dot(ray.direction); @@ -348,6 +579,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return false; } + bool Intersect( const Plane &plane, const Ray &ray, Float &connectDistance, Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const Plane &plane, const Sphere &sphere ) { // by Dan Andersson Float connectOffset; @@ -355,6 +592,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return (connectOffset <= sphere.radius); } + bool Intersect( const Plane &plane, const Sphere &sphere, Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const Plane &planeA, const Plane &planeB ) { // by Dan Andersson if( planeA.normal == planeB.normal ) // they are parallell @@ -364,6 +607,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; // none parallell planes ALWAYS intersects somewhere } + bool Intersect( const Plane &planeA, const Plane &planeB, Float4 &worldPointOfContact ) + { + //! @todo TODO: implement Stub + return false; + } + bool Intersect( const BoxAxisAligned &box, const Point &point ) { // by Dan Andersson if( point.center.x < box.minVertex.x ) return false; @@ -375,31 +624,66 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; } + bool Intersect( const BoxAxisAligned &box, const Point &point, Float4 &worldPointOfContact ) + { // by Dan Andersson + if( Intersect(box, point) ) + { + worldPointOfContact = point.center; + return true; + } + return false; + } + bool Intersect( const BoxAxisAligned &box, const Ray &ray, Float &connectDistance ) { // by Dan Andersson Float tMin = ::std::numeric_limits::max(), tMax = -tMin; // initiating to extremevalues - Float3 boundingOffset = ((box.maxVertex - box.minVertex) * 0.5f), + Float4 boundingOffset = ((box.maxVertex - box.minVertex) * 0.5f), dP = ((box.maxVertex + box.minVertex) * 0.5f) - ray.origin; - if( Private::BoxVsRayPerSlabCheck( Float3::standard_unit_x, boundingOffset.x, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } - if( Private::BoxVsRayPerSlabCheck( Float3::standard_unit_y, boundingOffset.y, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } - if( Private::BoxVsRayPerSlabCheck( Float3::standard_unit_z, boundingOffset.z, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::BoxVsRayPerSlabCheck( Float4::standard_unit_x, boundingOffset.x, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::BoxVsRayPerSlabCheck( Float4::standard_unit_y, boundingOffset.y, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::BoxVsRayPerSlabCheck( Float4::standard_unit_z, boundingOffset.z, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } if( tMin > 0.0f ) connectDistance = tMin; else connectDistance = tMax; return true; } + bool Intersect( const BoxAxisAligned &box, const Ray &ray, Float &connectDistance, Float4 &worldPointOfContact ) + { // by Dan Andersson + if( Intersect(box, ray, connectDistance) ) + { + worldPointOfContact = ray.origin + ray.direction * connectDistance; + return true; + } + return false; + } + bool Intersect( const BoxAxisAligned &box, const Sphere &sphere ) { // by Dan Andersson - Float4 e = Max( Float4(box.minVertex - sphere.center, 0.0f), Float4::null ); - e += Max( Float4(sphere.center - box.maxVertex, 0.0f), Float4::null ); + Float4 e = Max( box.minVertex - sphere.center, Float4::null ); + e += Max( sphere.center - box.maxVertex, Float4::null ); if( e.Dot(e) > (sphere.radius * sphere.radius) ) return false; return true; } + bool Intersect( const BoxAxisAligned &box, const Sphere &sphere, Float4 &worldPointOfContact ) + { // by Robin Engman + if( Intersect(box, sphere) ) + { + Float distance; + Float4 boxMiddle = (box.maxVertex - box.minVertex) * 0.5f; + Ray ray( boxMiddle, (sphere.center - boxMiddle).Normalize() ); + Intersect( sphere, ray, distance ); + worldPointOfContact = ray.origin + ray.direction * distance; + return true; + } + + return false; + } + bool Intersect( const BoxAxisAligned &box, const Plane &plane ) { // by Dan Andersson Float e, d; @@ -409,6 +693,12 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; } + bool Intersect( const BoxAxisAligned &box, const Plane &plane, Float4 &worldPointOfContact ) + { + //! @todo TODO: implement stub + return Intersect( box, plane ); + } + // bool Intersect( const BoxAxisAligned &box, const Triangle &triangle ) // { return false; /* TODO: */ } @@ -425,7 +715,7 @@ namespace Oyster { namespace Collision3D { namespace Utility bool Intersect( const Box &box, const Point &point ) { // by Dan Andersson - Float3 dPos = point.center - box.center; + Float4 dPos = point.center - box.center; Float coordinate = dPos.Dot( box.xAxis ); if( coordinate > box.boundingOffset.x ) return false; @@ -442,12 +732,22 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; } + bool Intersect( const Box &box, const Point &point, Float4 &worldPointOfContact ) + { // by Dan Andersson + if( Intersect(box, point) ) + { + worldPointOfContact = point.center; + return true; + } + return false; + } + bool Intersect( const Box &box, const Ray &ray, Float &connectDistance ) { // by Dan Andersson Float tMin = ::std::numeric_limits::max(), tMax = -tMin; // initiating to extremevalues - Float3 dP = box.center - ray.origin; + Float4 dP = box.center - ray.origin; if( Private::BoxVsRayPerSlabCheck( box.xAxis, box.boundingOffset.x, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } if( Private::BoxVsRayPerSlabCheck( box.yAxis, box.boundingOffset.y, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } if( Private::BoxVsRayPerSlabCheck( box.zAxis, box.boundingOffset.z, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } @@ -457,18 +757,43 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; } + bool Intersect( const Box &box, const Ray &ray, Float &connectDistance, Float4 &worldPointOfContact ) + { // by Dan Andersson + if( Intersect(box, ray, connectDistance) ) + { + worldPointOfContact = ray.origin + ray.direction * connectDistance; + return true; + } + return false; + } + bool Intersect( const Box &box, const Sphere &sphere ) { // by Dan Andersson // center: sphere's center in the box's view space - Float4 center = TransformVector( InverseRotationMatrix(box.rotation), Float4(sphere.center - box.center, 0.0f) ); + Float4 center = TransformVector( InverseRotationMatrix(box.rotation), sphere.center - box.center ); - Float4 e = Max( Float4(-box.boundingOffset, 0.0f) - center, Float4::null ); - e += Max( center - Float4(box.boundingOffset, 0.0f), Float4::null ); + Float4 e = Max( -box.boundingOffset - center, Float4::null ); + e += Max( center - box.boundingOffset, Float4::null ); if( e.Dot(e) > (sphere.radius * sphere.radius) ) return false; return true; } + bool Intersect( const Box &box, const Sphere &sphere, Float4 &worldPointOfContact ) + { // by Robin Engman + if( Intersect(box, sphere) ) + { + Float distance; + Ray ray( box.center, sphere.center - box.center ); + + Intersect( sphere, ray, distance ); + worldPointOfContact = ray.origin + ray.direction*distance; + return true; + } + + return false; + } + bool Intersect( const Box &box, const Plane &plane ) {// by Dan Andersson Float e, d; @@ -478,22 +803,53 @@ namespace Oyster { namespace Collision3D { namespace Utility return true; } + bool Intersect( const Box &box, const Plane &plane, Float4 &worldPointOfContact ) + { + //! @todo TODO: implement stub + return Intersect( box, plane ); + } + bool Intersect( const Box &boxA, const BoxAxisAligned &boxB ) { // by Dan Andersson - Float3 alignedOffsetBoundaries = (boxB.maxVertex - boxB.minVertex) * 0.5f, - offset = boxA.center - Average( boxB.minVertex, boxB.maxVertex ); + Float4 alignedOffsetBoundaries = (boxB.maxVertex - boxB.minVertex) * 0.5f, + offset = boxA.center- Average( boxB.maxVertex, boxB.minVertex ); return Private::SeperatingAxisTest_AxisAlignedVsTransformedBox( alignedOffsetBoundaries, boxA.boundingOffset, boxA.rotation, offset ); } + bool Intersect( const Box &boxA, const BoxAxisAligned &boxB, ::Oyster::Math::Float4 &worldPointOfContact ) + { // by Dan Andersson + Float4 alignedOffsetBoundaries = (boxB.maxVertex - boxB.minVertex) * 0.5f, + offset = boxA.center - Average( boxB.maxVertex, boxB.minVertex ); + + Float4 pointOfContact; + if( Private::SeperatingAxisTest_AxisAlignedVsTransformedBox( alignedOffsetBoundaries, boxA.boundingOffset, boxA.rotation, offset, pointOfContact ) ) + { + worldPointOfContact = pointOfContact.xyz; + return true; + } + else return false; + } + bool Intersect( const Box &boxA, const Box &boxB ) { // by Dan Andersson - Float4x4 orientationA = OrientationMatrix(boxA.rotation, boxA.center), - orientationB = OrientationMatrix(boxB.rotation, boxB.center), - invOrientationA = InverseOrientationMatrix( orientationA ); + Float4x4 rotationB = TransformMatrix( InverseRotationMatrix(boxA.rotation), boxB.rotation ); + Float4 posB = boxB.center - boxA.center; - orientationB = TransformMatrix( invOrientationA, orientationB ); + return Private::SeperatingAxisTest_AxisAlignedVsTransformedBox( boxA.boundingOffset, boxB.boundingOffset, rotationB, posB ); + } - return Private::SeperatingAxisTest_AxisAlignedVsTransformedBox( boxA.boundingOffset, boxB.boundingOffset, ExtractRotationMatrix(orientationB), orientationB.v[3].xyz ); + bool Intersect( const Box &boxA, const Box &boxB, Float4 &worldPointOfContact ) + { + Float4x4 rotationB = TransformMatrix( InverseRotationMatrix(boxA.rotation), boxB.rotation ); + Float4 posB = boxB.center - boxA.center; + + Float4 pointOfContact; + if( Private::SeperatingAxisTest_AxisAlignedVsTransformedBox( boxA.boundingOffset, boxB.boundingOffset, rotationB, posB, pointOfContact ) ) + { + worldPointOfContact = TransformVector( boxA.rotation, pointOfContact, pointOfContact ).xyz; + return true; + } + else return false; } bool Intersect( const Frustrum &frustrum, const Point &point ) diff --git a/Code/OysterPhysics3D/OysterCollision3D.h b/Code/OysterPhysics3D/OysterCollision3D.h index 24d6a568..20a55a18 100644 --- a/Code/OysterPhysics3D/OysterCollision3D.h +++ b/Code/OysterPhysics3D/OysterCollision3D.h @@ -25,18 +25,28 @@ namespace Oyster { namespace Collision3D { namespace Utility void Compare( ::Oyster::Math::Float &connectOffset, const Plane &plane, const Point &point ); bool Intersect( const Point &pointA, const Point &pointB ); + bool Intersect( const Point &pointA, const Point &pointB, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Ray &ray, const Point &point, ::Oyster::Math::Float &connectDistance ); + bool Intersect( const Ray &ray, const Point &point, ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Ray &rayA, const Ray &rayB, ::Oyster::Math::Float &connectDistanceA, ::Oyster::Math::Float &connectDistanceB ); + bool Intersect( const Ray &rayA, const Ray &rayB, ::Oyster::Math::Float &connectDistanceA, ::Oyster::Math::Float &connectDistanceB, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Sphere &sphere, const Point &point ); + bool Intersect( const Sphere &sphere, const Point &point, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Sphere &sphere, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool Intersect( const Sphere &sphere, const Ray &ray, ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Sphere &sphereA, const Sphere &sphereB ); + bool Intersect( const Sphere &sphereA, const Sphere &sphereB, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Plane &plane, const Point &point ); + bool Intersect( const Plane &plane, const Point &point, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Plane &plane, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool Intersect( const Plane &plane, const Ray &ray, ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Plane &plane, const Sphere &sphere ); + bool Intersect( const Plane &plane, const Sphere &sphere, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Plane &planeA, const Plane &planeB ); + bool Intersect( const Plane &planeA, const Plane &planeB, ::Oyster::Math::Float4 &worldPointOfContact ); // bool Intersect( const Triangle &triangle, const Point &point, ? ); // bool Intersect( const Triangle &triangle, const Ray &ray, ? ); @@ -45,19 +55,29 @@ namespace Oyster { namespace Collision3D { namespace Utility // bool Intersect( const Triangle &triangleA, const Triangle &triangleB, ? ); bool Intersect( const BoxAxisAligned &box, const Point &point ); + bool Intersect( const BoxAxisAligned &box, const Point &point, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const BoxAxisAligned &box, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool Intersect( const BoxAxisAligned &box, const Ray &ray, ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const BoxAxisAligned &box, const Sphere &sphere ); + bool Intersect( const BoxAxisAligned &box, const Sphere &sphere, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const BoxAxisAligned &box, const Plane &plane ); + bool Intersect( const BoxAxisAligned &box, const Plane &plane, ::Oyster::Math::Float4 &worldPointOfContact ); // bool Intersect( const BoxAxisAligned &box, const Triangle &triangle ); bool Intersect( const BoxAxisAligned &boxA, const BoxAxisAligned &boxB ); bool Intersect( const Box &box, const Point &point ); + bool Intersect( const Box &box, const Point &point, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Box &box, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool Intersect( const Box &box, const Ray &ray, ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Box &box, const Sphere &sphere ); + bool Intersect( const Box &box, const Sphere &sphere, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Box &box, const Plane &plane ); + bool Intersect( const Box &box, const Plane &plane, ::Oyster::Math::Float4 &worldPointOfContact ); // bool Intersect( const Box &box, const Triangle &triangle, ? ); bool Intersect( const Box &boxA, const BoxAxisAligned &boxB ); + bool Intersect( const Box &boxA, const BoxAxisAligned &boxB, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Box &boxA, const Box &boxB ); + bool Intersect( const Box &boxA, const Box &boxB, ::Oyster::Math::Float4 &worldPointOfContact ); bool Intersect( const Frustrum &frustrum, const Point &point ); bool Intersect( const Frustrum &frustrum, const Ray &ray, ::Oyster::Math::Float &connectDistance ); diff --git a/Code/OysterPhysics3D/OysterPhysics3D.h b/Code/OysterPhysics3D/OysterPhysics3D.h index 614a4a29..f70d228f 100644 --- a/Code/OysterPhysics3D/OysterPhysics3D.h +++ b/Code/OysterPhysics3D/OysterPhysics3D.h @@ -12,6 +12,60 @@ namespace Oyster { namespace Physics3D namespace Formula { /// Library of 3D physics related formulas + /****************************************************************** + * Returns the linear momentum of a mass in motion. + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 LinearMomentum( const ::Oyster::Math::Float &mass, const ::Oyster::Math::Float4 &linearVelocity ) + { + return linearVelocity * mass; + } + + /****************************************************************** + * Returns the linear momentum of a mass in motion. + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 LinearVelocity( const ::Oyster::Math::Float &mass, const ::Oyster::Math::Float4 &linearMomentum ) + { + return linearMomentum / mass; + } + + /****************************************************************** + * Returns the world angular momentum of a mass in rotation. + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 AngularMomentum( const ::Oyster::Math::Float4 linearMomentum, const ::Oyster::Math::Float4 &worldOffset ) + { + return ::Oyster::Math::Float4( worldOffset.xyz.Cross(linearMomentum.xyz), 0.0f ); + } + + /****************************************************************** + * Returns the world angular momentum of a mass in rotation. + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 AngularMomentum( const ::Oyster::Math::Float4x4 &worldMomentOfInertia, const ::Oyster::Math::Float4 &angularVelocity ) + { + return worldMomentOfInertia * angularVelocity; + } + + /****************************************************************** + * Returns the world angular velocity of a mass in rotation. + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 AngularVelocity( const ::Oyster::Math::Float4x4 &worldMomentOfInertiaInversed, const ::Oyster::Math::Float4 &angularMomentum ) + { + return worldMomentOfInertiaInversed * angularMomentum; + } + + /****************************************************************** + * Returns the world tangential momentum at worldPos, of a mass in rotation. + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 TangentialLinearMomentum( const ::Oyster::Math::Float4 &angularMomentum, const ::Oyster::Math::Float4 &worldOffset ) + { + return ::Oyster::Math::Float4( angularMomentum.xyz.Cross(worldOffset.xyz), 0.0f ); + } + /****************************************************************** * Returns the linear kinetic energy of a mass in motion. * @todo TODO: improve doc @@ -138,6 +192,15 @@ namespace Oyster { namespace Physics3D return worldOffset.Cross( linearVelocity ); } + /****************************************************************** + * Returns the world angular velocity of a mass in rotation. + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 AngularVelocity( const ::Oyster::Math::Float4 &linearVelocity, const ::Oyster::Math::Float4 &worldOffset ) + { + return ::Oyster::Math::Float4( worldOffset.xyz.Cross( linearVelocity.xyz ), 0.0f ); + } + /****************************************************************** * Returns the world tangential velocity at worldPos, of a mass in rotation. * @todo TODO: improve doc @@ -183,6 +246,15 @@ namespace Oyster { namespace Physics3D return worldOffset.Cross( impulseForce ); } + /****************************************************************** + * + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 ImpulseTorque( const ::Oyster::Math::Float4 & impulseForce, const ::Oyster::Math::Float4 &worldOffset ) + { + return ::Oyster::Math::Float4( worldOffset.xyz.Cross(impulseForce.xyz), 0.0f ); + } + /****************************************************************** * T = I*a * @todo TODO: improve doc @@ -192,10 +264,13 @@ namespace Oyster { namespace Physics3D return ( momentOfInertia * ::Oyster::Math::Float4(angularImpulseAcceleration, 0.0f) ).xyz; } - inline ::Oyster::Math::Float3 Impulse( ) + /****************************************************************** + * T = I*a + * @todo TODO: improve doc + ******************************************************************/ + inline ::Oyster::Math::Float4 ImpulseTorque( const ::Oyster::Math::Float4x4 & momentOfInertia, const ::Oyster::Math::Float4 &angularImpulseAcceleration ) { - //! @todo TODO: implement calculation for impulse. Hijack Mattias Eriksson - return ::Oyster::Math::Float3::null; + return momentOfInertia * angularImpulseAcceleration; } namespace MomentOfInertia diff --git a/Code/OysterPhysics3D/OysterPhysics3D.vcxproj b/Code/OysterPhysics3D/OysterPhysics3D.vcxproj index f24f23e4..186ea535 100644 --- a/Code/OysterPhysics3D/OysterPhysics3D.vcxproj +++ b/Code/OysterPhysics3D/OysterPhysics3D.vcxproj @@ -163,6 +163,7 @@ + diff --git a/Code/OysterPhysics3D/OysterPhysics3D.vcxproj.filters b/Code/OysterPhysics3D/OysterPhysics3D.vcxproj.filters index e3a8a70d..02919d28 100644 --- a/Code/OysterPhysics3D/OysterPhysics3D.vcxproj.filters +++ b/Code/OysterPhysics3D/OysterPhysics3D.vcxproj.filters @@ -75,6 +75,9 @@ Header Files\Physics + + Header Files\Physics + diff --git a/Code/OysterPhysics3D/Particle.cpp b/Code/OysterPhysics3D/Particle.cpp index 830e13b5..c84b1e31 100644 --- a/Code/OysterPhysics3D/Particle.cpp +++ b/Code/OysterPhysics3D/Particle.cpp @@ -34,7 +34,7 @@ Particle & Particle::operator = ( const Particle &particle ) void Particle::Update_LeapFrog( Float deltaTime ) { // Euler leap frog update when Runga Kutta is not needed this->impulseForceSum *= (deltaTime / this->mass); // is now deltaLinearVelocity ( dt * a = dt * F / m ) - this->sphere.center += deltaTime * ::Utility::Value::AverageWithDelta( Formula::LinearVelocity(this->mass, this->linearMomentum), this->impulseForceSum ); + this->sphere.center.xyz += deltaTime * ::Utility::Value::AverageWithDelta( Formula::LinearVelocity(this->mass, this->linearMomentum), this->impulseForceSum ); this->linearMomentum += Formula::LinearMomentum( this->mass, this->impulseForceSum ); this->impulseForceSum = Float3::null; @@ -66,12 +66,12 @@ void Particle::ApplyLinearImpulseAcceleration( const Float3 &a ) Float3 & Particle::AccessCenter() { - return this->sphere.center; + return this->sphere.center.xyz; } const Float3 & Particle::AccessCenter() const { - return this->sphere.center; + return this->sphere.center.xyz; } Float & Particle::AccessRadius() @@ -91,7 +91,7 @@ const Float & Particle::GetMass() const const Float3 & Particle::GetCenter() const { - return this->sphere.center; + return this->sphere.center.xyz; } const Float & Particle::GetRadius() const diff --git a/Code/OysterPhysics3D/Plane.cpp b/Code/OysterPhysics3D/Plane.cpp index a1a16b14..59ffbc47 100644 --- a/Code/OysterPhysics3D/Plane.cpp +++ b/Code/OysterPhysics3D/Plane.cpp @@ -10,11 +10,11 @@ using namespace ::Oyster::Math; Plane::Plane( ) : ICollideable(Type_plane) { - this->normal = Float3::standard_unit_z; + this->normal = Float4::standard_unit_z; this->phasing = 0.0f; } -Plane::Plane( const Float3 &n, const Float &p ) : ICollideable(Type_plane) +Plane::Plane( const Float4 &n, const Float &p ) : ICollideable(Type_plane) { this->normal = n; this->phasing = p; @@ -30,23 +30,46 @@ Plane & Plane::operator = ( const Plane &plane ) } ::Utility::DynamicMemory::UniquePointer Plane::Clone( ) const -{ return ::Utility::DynamicMemory::UniquePointer( new Plane(*this) ); } +{ + return ::Utility::DynamicMemory::UniquePointer( new Plane(*this) ); +} bool Plane::Intersects( const ICollideable &target ) const { switch( target.type ) { - case Type_universe: return true; - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - case Type_ray: return Utility::Intersect( *this, *(Ray*)&target, ((Ray*)&target)->collisionDistance ); - case Type_sphere: return Utility::Intersect( *this, *(Sphere*)&target ); - case Type_plane: return Utility::Intersect( *this, *(Plane*)&target ); - // case Type_triangle: return false; // TODO: - case Type_box_axis_aligned: return Utility::Intersect( *(BoxAxisAligned*)&target, *this ); - case Type_box: return Utility::Intersect( *(Box*)&target, *this ); - case Type_frustrum: return false; // TODO: - case Type_line: return false; // TODO: - default: return false; + case Type_universe: return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, ((const Ray&)target).collisionDistance ); + case Type_sphere: return Utility::Intersect( *this, (const Sphere&)target ); + case Type_plane: return Utility::Intersect( *this, (const Plane&)target ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( (const BoxAxisAligned&)target, *this ); + case Type_box: return Utility::Intersect( (const Box&)target, *this ); + //case Type_frustrum: return false; // TODO: + //case Type_line: return false; // TODO: + default: return false; + } +} + +bool Plane::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ + switch( target.type ) + { + case Type_universe: + worldPointOfContact = this->normal * this->phasing; + return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target, worldPointOfContact ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, ((const Ray&)target).collisionDistance, worldPointOfContact ); + case Type_sphere: return Utility::Intersect( *this, (const Sphere&)target, worldPointOfContact ); + case Type_plane: return Utility::Intersect( (const Plane&)target, *this, worldPointOfContact ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( (const BoxAxisAligned&)target, *this, worldPointOfContact ); + case Type_box: return Utility::Intersect( (const Box&)target, *this, worldPointOfContact ); + //case Type_frustrum: return false; // TODO: + default: + worldPointOfContact = Float3::null; + return false; } } @@ -54,10 +77,10 @@ bool Plane::Contains( const ICollideable &target ) const { switch( target.type ) { - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - case Type_ray: return Utility::Contains( *this, *(Ray*)&target ); - case Type_plane: return Utility::Contains( *this, *(Plane*)&target ); - // case Type_triangle: return false; // TODO: - default: return false; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + case Type_ray: return Utility::Contains( *this, (const Ray&)target ); + case Type_plane: return Utility::Contains( *this, (const Plane&)target ); + //case Type_triangle: return false; // TODO: + default: return false; } } \ No newline at end of file diff --git a/Code/OysterPhysics3D/Plane.h b/Code/OysterPhysics3D/Plane.h index b69c5c9f..f148ed8e 100644 --- a/Code/OysterPhysics3D/Plane.h +++ b/Code/OysterPhysics3D/Plane.h @@ -16,19 +16,20 @@ namespace Oyster { namespace Collision3D public: union { - struct{ ::Oyster::Math::Float3 normal; ::Oyster::Math::Float phasing; }; - ::Oyster::Math::Float element[4]; - char byte[sizeof(::Oyster::Math::Float3) + sizeof(::Oyster::Math::Float)]; + struct{ ::Oyster::Math::Float4 normal; ::Oyster::Math::Float phasing; }; + ::Oyster::Math::Float element[5]; + char byte[sizeof(::Oyster::Math::Float4) + sizeof(::Oyster::Math::Float)]; }; Plane( ); - Plane( const ::Oyster::Math::Float3 &normal, const ::Oyster::Math::Float &phasing ); + Plane( const ::Oyster::Math::Float4 &normal, const ::Oyster::Math::Float &phasing ); virtual ~Plane( ); Plane & operator = ( const Plane &plane ); virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; } } diff --git a/Code/OysterPhysics3D/Point.cpp b/Code/OysterPhysics3D/Point.cpp index d81c91a3..788ab32d 100644 --- a/Code/OysterPhysics3D/Point.cpp +++ b/Code/OysterPhysics3D/Point.cpp @@ -10,10 +10,15 @@ using namespace ::Oyster::Math3D; Point::Point( ) : ICollideable(Type_point) { - this->center = Float3::null; + this->center = Float4::standard_unit_w; } Point::Point( const Float3 &pos ) : ICollideable(Type_point) +{ + this->center = Float4( pos, 1.0f ); +} + +Point::Point( const Float4 &pos ) : ICollideable(Type_point) { this->center = pos; } @@ -35,16 +40,37 @@ bool Point::Intersects( const ICollideable &target ) const { switch( target.type ) { - case Type_universe: return true; - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - case Type_ray: return Utility::Intersect( *(Ray*)&target, *this, ((Ray*)&target)->collisionDistance ); - case Type_sphere: return Utility::Intersect( *(Sphere*)&target, *this ); - case Type_plane: return Utility::Intersect( *(Plane*)&target, *this ); - //case Type_triangle: return false; // TODO: - case Type_box_axis_aligned: return Utility::Intersect( *(BoxAxisAligned*)&target, *this ); - case Type_box: return Utility::Intersect( *(Box*)&target, *this ); - case Type_frustrum: return false; // TODO: - default: return false; + case Type_universe: return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + case Type_ray: return Utility::Intersect( (const Ray&)target, *this, ((const Ray&)target).collisionDistance ); + case Type_sphere: return Utility::Intersect( (const Sphere&)target, *this ); + case Type_plane: return Utility::Intersect( (const Plane&)target, *this ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( (const BoxAxisAligned&)target, *this ); + case Type_box: return Utility::Intersect( (const Box&)target, *this ); + //case Type_frustrum: return false; // TODO: + default: return false; + } +} + +bool Point::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ + switch( target.type ) + { + case Type_universe: + worldPointOfContact = this->center; + return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target, worldPointOfContact ); + case Type_ray: return Utility::Intersect( (const Ray&)target, *this, ((const Ray&)target).collisionDistance, worldPointOfContact ); + case Type_sphere: return Utility::Intersect( (const Sphere&)target, *this, worldPointOfContact ); + case Type_plane: return Utility::Intersect( (const Plane&)target, *this, worldPointOfContact ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( (const BoxAxisAligned&)target, *this, worldPointOfContact ); + case Type_box: return Utility::Intersect( (const Box&)target, *this, worldPointOfContact ); + case Type_frustrum: return false; // TODO: + default: + worldPointOfContact = Float3::null; + return false; } } @@ -52,7 +78,7 @@ bool Point::Contains( const ICollideable &target ) const { switch( target.type ) { - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - default: return false; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + default: return false; } } \ No newline at end of file diff --git a/Code/OysterPhysics3D/Point.h b/Code/OysterPhysics3D/Point.h index 42561909..60486373 100644 --- a/Code/OysterPhysics3D/Point.h +++ b/Code/OysterPhysics3D/Point.h @@ -16,18 +16,20 @@ namespace Oyster { namespace Collision3D public: union { - struct{ ::Oyster::Math::Float3 center; }; - char byte[sizeof(::Oyster::Math::Float3)]; + struct{ ::Oyster::Math::Float4 center; }; + char byte[sizeof(::Oyster::Math::Float4)]; }; Point( ); Point( const ::Oyster::Math::Float3 &position ); + Point( const ::Oyster::Math::Float4 &position ); virtual ~Point( ); Point & operator = ( const Point &point ); virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; } } diff --git a/Code/OysterPhysics3D/Ray.cpp b/Code/OysterPhysics3D/Ray.cpp index 79e4dbd5..e7f21de8 100644 --- a/Code/OysterPhysics3D/Ray.cpp +++ b/Code/OysterPhysics3D/Ray.cpp @@ -10,12 +10,19 @@ using namespace ::Oyster::Math3D; Ray::Ray( ) : ICollideable(Type_ray) { - this->origin = Float3::null; - this->direction = Float3::standard_unit_z; + this->origin = Float4::standard_unit_w; + this->direction = Float4::standard_unit_z; this->collisionDistance = 0.0f; } -Ray::Ray( const Float3 &o, const ::Oyster::Math::Float3 &d ) : ICollideable(Type_ray) +Ray::Ray( const Float3 &o, const Float3 &d ) : ICollideable(Type_ray) +{ + this->origin = Float4( o, 1.0f ); + this->direction = Float4( d, 0.0f ); + this->collisionDistance = 0.0f; +} + +Ray::Ray( const Float4 &o, const Float4 &d ) : ICollideable(Type_ray) { this->origin = o; this->direction = d; @@ -43,15 +50,37 @@ bool Ray::Intersects( const ICollideable &target ) const case Type_universe: this->collisionDistance = 0.0f; return true; - case Type_point: return Utility::Intersect( *this, *(Point*)&target, this->collisionDistance ); - case Type_ray: return Utility::Intersect( *this, *(Ray*)&target, this->collisionDistance, ((Ray*)&target)->collisionDistance ); - case Type_sphere: return Utility::Intersect( *(Sphere*)&target, *this, this->collisionDistance ); - case Type_plane: return Utility::Intersect( *(Plane*)&target, *this, this->collisionDistance ); - // case Type_triangle: return false; // TODO: - case Type_box_axis_aligned: return Utility::Intersect( *(BoxAxisAligned*)&target, *this, this->collisionDistance ); - case Type_box: return Utility::Intersect( *(Box*)&target, *this, this->collisionDistance ); - case Type_frustrum: return false; // TODO: - default: return false; + case Type_point: return Utility::Intersect( *this, (const Point&)target, this->collisionDistance ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, this->collisionDistance, ((const Ray&)target).collisionDistance ); + case Type_sphere: return Utility::Intersect( (const Sphere&)target, *this, this->collisionDistance ); + case Type_plane: return Utility::Intersect( (const Plane&)target, *this, this->collisionDistance ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( (const BoxAxisAligned&)target, *this, this->collisionDistance ); + case Type_box: return Utility::Intersect( (const Box&)target, *this, this->collisionDistance ); + //case Type_frustrum: return false; // TODO: + default: return false; + } +} + +bool Ray::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ + switch( target.type ) + { + case Type_universe: + this->collisionDistance = 0.0f; + worldPointOfContact = this->origin; + return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target, this->collisionDistance, worldPointOfContact ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, this->collisionDistance, ((const Ray&)target).collisionDistance, worldPointOfContact ); + case Type_sphere: return Utility::Intersect( (const Sphere&)target, *this, this->collisionDistance, worldPointOfContact ); + case Type_plane: return Utility::Intersect( (const Plane&)target, *this, this->collisionDistance, worldPointOfContact ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( (const BoxAxisAligned&)target, *this, this->collisionDistance, worldPointOfContact ); + case Type_box: return Utility::Intersect( (const Box&)target, *this, this->collisionDistance, worldPointOfContact ); + //case Type_frustrum: return false; // TODO: + default: + worldPointOfContact = Float3::null; + return false; } } @@ -59,8 +88,8 @@ bool Ray::Contains( const ICollideable &target ) const { switch( target.type ) { - case Type_point: return Utility::Intersect( *this, *(Point*)&target, this->collisionDistance ); - case Type_ray: return Utility::Contains( *this, *(Ray*)&target ); - default: return false; + case Type_point: return Utility::Intersect( *this, (const Point&)target, this->collisionDistance ); + case Type_ray: return Utility::Contains( *this, (const Ray&)target ); + default: return false; } } \ No newline at end of file diff --git a/Code/OysterPhysics3D/Ray.h b/Code/OysterPhysics3D/Ray.h index 5f24ea81..a85580b3 100644 --- a/Code/OysterPhysics3D/Ray.h +++ b/Code/OysterPhysics3D/Ray.h @@ -10,7 +10,6 @@ #ifndef OYSTER_COLLISION_3D_RAY_H #define OYSTER_COLLISION_3D_RAY_H -#include "OysterMath.h" #include "ICollideable.h" namespace Oyster { namespace Collision3D @@ -22,21 +21,23 @@ namespace Oyster { namespace Collision3D { struct { - ::Oyster::Math::Float3 origin, + ::Oyster::Math::Float4 origin, direction; /// Assumed to be normalized }; - char byte[2*sizeof(::Oyster::Math::Float3)]; + char byte[2*sizeof(::Oyster::Math::Float4)]; }; mutable float collisionDistance; Ray( ); Ray( const ::Oyster::Math::Float3 &origin, const ::Oyster::Math::Float3 &normalizedDirection ); + Ray( const ::Oyster::Math::Float4 &origin, const ::Oyster::Math::Float4 &normalizedDirection ); virtual ~Ray( ); Ray & operator = ( const Ray &ray ); virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; } } diff --git a/Code/OysterPhysics3D/RigidBody.cpp b/Code/OysterPhysics3D/RigidBody.cpp index 182a5a17..3ae48511 100644 --- a/Code/OysterPhysics3D/RigidBody.cpp +++ b/Code/OysterPhysics3D/RigidBody.cpp @@ -8,413 +8,224 @@ using namespace ::Oyster::Collision3D; using namespace ::Oyster::Physics3D; using namespace ::Oyster::Math3D; +using namespace ::Utility::Value; -RigidBody::RigidBody( const Box &b, Float m, const Float4x4 &inertiaTensor ) +RigidBody::RigidBody( ) { // by Dan Andersson - this->box = b; - this->angularMomentum = Float3::null; - this->linearMomentum = Float3::null; - this->impulseTorqueSum = Float3::null; - this->impulseForceSum = Float3::null; - - if( m != 0.0f ) - { - this->mass = m; - } - else - { - this->mass = ::Utility::Value::numeric_limits::epsilon(); - } - - if( inertiaTensor.GetDeterminant() != 0.0f ) - { - this->momentOfInertiaTensor = inertiaTensor; - } - else - { - this->momentOfInertiaTensor = Float4x4::identity; - } + this->centerPos = Float4::standard_unit_w; + this->axis = Float4::null; + this->boundingReach = Float4( 0.5f, 0.5f, 0.5f, 0.0f ); + this->momentum_Linear = Float4::null; + this->momentum_Angular = Float4::null; + this->impulse_Linear = Float4::null; + this->impulse_Angular = Float4::null; + this->restitutionCoeff = 1.0f; + this->frictionCoeff_Static = 0.5f; + this->frictionCoeff_Kinetic = 1.0f; + this->mass = 10; + this->momentOfInertiaTensor = Float4x4::identity; + this->rotation = Quaternion::identity; } RigidBody & RigidBody::operator = ( const RigidBody &body ) { // by Dan Andersson - this->box = body.box; - this->angularMomentum = body.angularMomentum; - this->linearMomentum = body.linearMomentum; - this->impulseTorqueSum = body.impulseTorqueSum; - this->impulseForceSum = body.impulseForceSum; + this->centerPos = body.centerPos; + this->axis = body.axis; + this->boundingReach = body.boundingReach; + this->momentum_Linear = body.momentum_Linear; + this->momentum_Angular = body.momentum_Angular; + this->impulse_Linear = body.impulse_Linear; + this->impulse_Angular = body.impulse_Angular; + this->restitutionCoeff = body.restitutionCoeff; + this->frictionCoeff_Static = body.frictionCoeff_Static; + this->frictionCoeff_Kinetic = body.frictionCoeff_Kinetic; this->mass = body.mass; this->momentOfInertiaTensor = body.momentOfInertiaTensor; + this->rotation = body.rotation; return *this; } -bool RigidBody::operator == ( const RigidBody &body ) -{ - if( this->box.center != body.box.center ) - { - return false; - } - - if( this->box.rotation != body.box.rotation ) - { - return false; - } - - if( this->box.boundingOffset != body.box.boundingOffset ) - { - return false; - } - - if( this->angularMomentum != body.angularMomentum ) - { - return false; - } - - if( this->linearMomentum != body.linearMomentum ) - { - return false; - } - - if( this->impulseTorqueSum != body.impulseTorqueSum ) - { - return false; - } - - if( this->impulseForceSum != body.impulseForceSum ) - { - return false; - } - - return true; -} - -bool RigidBody::operator != ( const RigidBody &body ) -{ - return !this->operator==( body ); -} - -void RigidBody::Update_LeapFrog( Float deltaTime ) +void RigidBody::Update_LeapFrog( Float updateFrameLength ) { // by Dan Andersson: Euler leap frog update when Runga Kutta is not needed - // Important! The member data is all world data except the Inertia tensor. Thus a new InertiaTensor needs to be created to be compatible with the rest of the world data. - Float4x4 wMomentOfInertiaTensor = TransformMatrix( this->box.rotation, this->momentOfInertiaTensor ); // RI - // updating the linear - // dG = F * dt // ds = dt * Formula::LinearVelocity( m, avg_G ) = dt * avg_G / m = (dt / m) * avg_G - Float3 linearImpulse = this->impulseForceSum * deltaTime; // aka deltaLinearMomentum - Float3 deltaPos = ( deltaTime / this->mass ) * ::Utility::Value::AverageWithDelta( this->linearMomentum, linearImpulse ); + this->centerPos += ( updateFrameLength / this->mass ) * AverageWithDelta( this->momentum_Linear, this->impulse_Linear ); // updating the angular - // dH = T * dt + Float4x4 rotationMatrix; ::Oyster::Math3D::RotationMatrix( this->rotation, rotationMatrix ); + // Important! The member data is all world data except the Inertia tensor. Thus a new InertiaTensor needs to be created to be compatible with the rest of the world data. + Float4x4 wMomentOfInertiaTensor = TransformMatrix( rotationMatrix, this->momentOfInertiaTensor ); // RI + // dO = dt * Formula::AngularVelocity( (RI)^-1, avg_H ) = dt * (RI)^-1 * avg_H - Float3 angularImpulse = this->impulseTorqueSum * deltaTime; // aka deltaAngularMomentum - Float3 rotationAxis = Formula::AngularVelocity( wMomentOfInertiaTensor.GetInverse(), - ::Utility::Value::AverageWithDelta(this->angularMomentum, angularImpulse) ); - - Float deltaRadian = rotationAxis.Dot( rotationAxis ); - if( deltaRadian != 0.0f ) - { // branch depending if there is rotation - deltaRadian = ::std::sqrt( deltaRadian ); - rotationAxis /= deltaRadian; + this->axis += Formula::AngularVelocity( wMomentOfInertiaTensor.GetInverse(), AverageWithDelta(this->momentum_Angular, this->impulse_Angular) ); + this->rotation = Rotation( this->axis ); - // using rotationAxis, deltaRadian and deltaPos to create a matrix to update the box - this->box.center += deltaPos; - TransformMatrix( RotationMatrix(deltaRadian, rotationAxis), this->box.rotation, this->box.rotation ); - } - else - { // no rotation, only use deltaPos to translate the RigidBody - this->box.center += deltaPos; - } - - // update momentums and clear impulseForceSum and impulseTorqueSum - this->linearMomentum += linearImpulse; - this->impulseForceSum = Float3::null; - this->angularMomentum += angularImpulse; - this->impulseTorqueSum = Float3::null; + // update momentums and clear impulse_Linear and impulse_Angular + this->momentum_Linear += this->impulse_Linear; + this->impulse_Linear = Float4::null; + this->momentum_Angular += this->impulse_Angular; + this->impulse_Angular = Float4::null; } -void RigidBody::ApplyImpulseForce( const Float3 &worldF ) -{ // by Dan Andersson - this->impulseForceSum += worldF; +void RigidBody::Predict_LeapFrog( Float4 &outDeltaPos, Float4 &outDeltaAxis, const Float4 &actingLinearImpulse, const Float4 &actingAngularImpulse, Float deltaTime ) +{ + // updating the linear + // ds = dt * Formula::LinearVelocity( m, avg_G ) = dt * avg_G / m = (dt / m) * avg_G + outDeltaPos = ( deltaTime / this->mass ) * AverageWithDelta( this->momentum_Linear, actingLinearImpulse ); + + // updating the angular + Float4x4 rotationMatrix; ::Oyster::Math3D::RotationMatrix( this->rotation, rotationMatrix ); + Float4x4 wMomentOfInertiaTensor = TransformMatrix( rotationMatrix, this->momentOfInertiaTensor ); // RI + + // dO = dt * Formula::AngularVelocity( (RI)^-1, avg_H ) = dt * (RI)^-1 * avg_H + outDeltaAxis = Formula::AngularVelocity( wMomentOfInertiaTensor.GetInverse(), AverageWithDelta(this->momentum_Angular, actingAngularImpulse) ); } -void RigidBody::ApplyImpulseForceAt( const Float3 &worldF, const Float3 &worldPos ) +void RigidBody::Move( const Float4 &deltaPos, const Float4 &deltaAxis ) +{ + this->centerPos += deltaPos; + this->axis += deltaAxis; + this->rotation = Rotation( this->axis ); +} + +void RigidBody::ApplyImpulse( const Float4 &worldJ, const Float4 &atWorldPos ) { // by Dan Andersson - Float3 worldOffset = worldPos - this->box.center; - if( worldOffset != Float3::null ) + Float4 worldOffset = atWorldPos - this->centerPos; + if( worldOffset != Float4::null ) { - this->impulseForceSum += VectorProjection( worldF, worldOffset ); - this->impulseTorqueSum += Formula::ImpulseTorque( worldF, worldOffset ); + this->impulse_Linear += VectorProjection( worldJ, atWorldPos ); + this->impulse_Angular += Formula::ImpulseTorque( worldJ, atWorldPos ); } else { - this->impulseForceSum += worldF; + this->impulse_Linear += worldJ; } } -void RigidBody::ApplyLinearImpulseAcceleration( const Float3 &worldA ) -{ // by Dan Andersson - this->impulseForceSum += Formula::ImpulseForce( this->mass, worldA ); -} - -void RigidBody::ApplyLinearImpulseAccelerationAt( const Float3 &worldA, const Float3 &worldPos ) -{ // by Dan Andersson - Float3 worldOffset = worldPos - this->box.center; - if( worldOffset != Float3::null ) - { - this->impulseForceSum += Formula::ImpulseForce( this->mass, VectorProjection(worldA, worldOffset) ); - - // tanAcc = angularAcc x localPosition - // angularAcc = localPosition x tanAcc = localPosition x linearAcc - // T = I * angularAcc - this->impulseTorqueSum += Formula::ImpulseTorque( this->momentOfInertiaTensor, Formula::AngularImpulseAcceleration(worldA, worldOffset) ); - } - else - { - this->impulseForceSum += Formula::ImpulseForce( this->mass, worldA ); - } -} - -void RigidBody::ApplyImpulseTorque( const Float3 &worldT ) -{ // by Dan Andersson - this->impulseTorqueSum += worldT; -} - -void RigidBody::ApplyAngularImpulseAcceleration( const Float3 &worldA ) -{ // by Dan Andersson - this->impulseTorqueSum += Formula::ImpulseTorque( this->momentOfInertiaTensor, worldA ); -} - -Float3 & RigidBody::AccessBoundingReach() -{ // by Dan Andersson - return this->box.boundingOffset; -} - -const Float3 & RigidBody::AccessBoundingReach() const -{ // by Dan Andersson - return this->box.boundingOffset; -} - -Float3 & RigidBody::AccessCenter() -{ // by Dan Andersson - return this->box.center; -} - -const Float3 & RigidBody::AccessCenter() const -{ // by Dan Andersson - return this->box.center; -} - const Float4x4 & RigidBody::GetMomentOfInertia() const { // by Dan Andersson return this->momentOfInertiaTensor; } -const Float & RigidBody::GetMass() const +Float RigidBody::GetMass() const { // by Dan Andersson return this->mass; } -const Float4x4 RigidBody::GetOrientation() const +const Quaternion & RigidBody::GetRotation() const { // by Dan Andersson - return OrientationMatrix( this->box.rotation, this->box.center ); + return this->rotation; +} + +Float4x4 RigidBody::GetRotationMatrix() const +{ // by Dan Andersson + return RotationMatrix( this->rotation ); +} + +Float4x4 RigidBody::GetOrientation() const +{ // by Dan Andersson + return ::Oyster::Math3D::OrientationMatrix( this->rotation, this->centerPos ); } Float4x4 RigidBody::GetView() const { // by Dan Andersson - return InverseOrientationMatrix( this->GetOrientation() ); + return ViewMatrix( this->rotation, this->centerPos ); } -const Float3 & RigidBody::GetBoundingReach() const +Float4 RigidBody::GetVelocity_Linear() const { // by Dan Andersson - return this->box.boundingOffset; + return Formula::LinearVelocity( this->mass, this->momentum_Linear ); } -Float3 RigidBody::GetSize() const +Float4 RigidBody::GetVelocity_Angular() const { // by Dan Andersson - return 2.0f * this->box.boundingOffset; + return Formula::AngularVelocity( this->momentOfInertiaTensor.GetInverse(), this->momentum_Angular ); } -const Float3 & RigidBody::GetCenter() const +Float4 RigidBody::GetLinearMomentum( const Float4 &atWorldPos ) const { // by Dan Andersson - return this->box.center; + return this->momentum_Linear + Formula::TangentialLinearMomentum( this->momentum_Angular, atWorldPos - this->centerPos ); } -const Float3 & RigidBody::GetImpulsTorque() const +void RigidBody::SetMomentOfInertia_KeepVelocity( const Float4x4 &localTensorI ) { // by Dan Andersson - return this->impulseTorqueSum; -} + if( localTensorI.GetDeterminant() != 0.0f ) + { // insanity check! MomentOfInertiaTensor must be invertable + Float4x4 rotationMatrix; RotationMatrix( this->rotation, rotationMatrix ); -const Float3 & RigidBody::GetAngularMomentum() const -{ // by Dan Andersson - return this->angularMomentum; -} - -Float3 RigidBody::GetAngularImpulseAcceleration() const -{ // by Dan Andersson - return Formula::AngularImpulseAcceleration( this->momentOfInertiaTensor.GetInverse(), this->impulseTorqueSum ); -} - -Float3 RigidBody::GetAngularVelocity() const -{ // by Dan Andersson - return Formula::AngularVelocity( this->momentOfInertiaTensor.GetInverse(), this->angularMomentum ); -} - -const Float3 & RigidBody::GetImpulseForce() const -{ // by Dan Andersson - return this->impulseForceSum; -} - -const Float3 & RigidBody::GetLinearMomentum() const -{ // by Dan Andersson - return this->linearMomentum; -} - -Float3 RigidBody::GetLinearImpulseAcceleration() const -{ // by Dan Andersson - return Formula::LinearImpulseAcceleration( this->mass, this->impulseForceSum ); -} - -Float3 RigidBody::GetLinearVelocity() const -{ // by Dan Andersson - return Formula::LinearVelocity( this->mass, this->linearMomentum ); -} - -void RigidBody::GetMomentumAt( const Float3 &worldPos, const Float3 &surfaceNormal, Float3 &normalMomentum, Float3 &tangentialMomentum ) const -{ // by Dan Andersson - Float3 worldOffset = worldPos - this->box.center; - Float3 momentum = Formula::TangentialLinearMomentum( this->angularMomentum, worldOffset ); - momentum += this->linearMomentum; - - normalMomentum = NormalProjection( momentum, surfaceNormal ); - tangentialMomentum = momentum - normalMomentum; -} - -void RigidBody::SetMomentOfInertia_KeepVelocity( const ::Oyster::Math::Float4x4 &localI ) -{ // by Dan Andersson - if( localI.GetDeterminant() != 0.0f ) // insanitycheck! momentOfInertiaTensor must be invertable - { - Float3 w = Formula::AngularVelocity( (this->box.rotation * this->momentOfInertiaTensor).GetInverse(), - this->angularMomentum ); - this->momentOfInertiaTensor = localI; - this->angularMomentum = Formula::AngularMomentum( this->box.rotation*localI, w ); + Float4 w = Formula::AngularVelocity( (rotationMatrix * this->momentOfInertiaTensor).GetInverse(), this->momentum_Angular ); + this->momentOfInertiaTensor = localTensorI; + this->momentum_Angular = Formula::AngularMomentum( rotationMatrix * localTensorI, w ); } } -void RigidBody::SetMomentOfInertia_KeepMomentum( const Float4x4 &localI ) +void RigidBody::SetMomentOfInertia_KeepMomentum( const Float4x4 &localTensorI ) { // by Dan Andersson - if( localI.GetDeterminant() != 0.0f ) // insanitycheck! momentOfInertiaTensor must be invertable - { - this->momentOfInertiaTensor = localI; + if( localTensorI.GetDeterminant() != 0.0f ) + { // insanity check! MomentOfInertiaTensor must be invertable + this->momentOfInertiaTensor = localTensorI; } } void RigidBody::SetMass_KeepVelocity( const Float &m ) { // by Dan Andersson - if( m != 0.0f ) // insanitycheck! mass must be invertable - { - Float3 v = Formula::LinearVelocity( this->mass, this->linearMomentum ); + if( m != 0.0f ) + { // insanity check! Mass must be invertable + Float4 v = Formula::LinearVelocity( this->mass, this->momentum_Linear ); this->mass = m; - this->linearMomentum = Formula::LinearMomentum( this->mass, v ); + this->momentum_Linear = Formula::LinearMomentum( this->mass, v ); } } void RigidBody::SetMass_KeepMomentum( const Float &m ) { // by Dan Anderson - if( m != 0.0f ) // insanitycheck! mass must be invertable - { + if( m != 0.0f ) + { // insanity check! Mass must be invertable this->mass = m; } } void RigidBody::SetOrientation( const Float4x4 &o ) { // by Dan Andersson - ExtractRotationMatrix( o, this->box.rotation ); - this->box.center = o.v[3].xyz; -} - -void RigidBody::SetSize( const Float3 &widthHeight ) -{ // by Dan Andersson - this->box.boundingOffset = 0.5f * widthHeight; -} - -void RigidBody::SetCenter( const Float3 &worldPos ) -{ // by Dan Andersson - this->box.center = worldPos; + this->axis = ExtractAngularAxis( o ); + this->rotation = Rotation( this->axis ); + this->centerPos = o.v[3].xyz; } void RigidBody::SetRotation( const Float4x4 &r ) { // by Dan Andersson - this->box.rotation = r; + this->axis = ExtractAngularAxis( r ); + this->rotation = Rotation( this->axis ); } -void RigidBody::SetImpulseTorque( const Float3 &worldT ) +void RigidBody::SetMomentum_Linear( const Float4 &worldG, const Float4 &atWorldPos ) { // by Dan Andersson - this->impulseTorqueSum = worldT; + Float4 worldOffset = atWorldPos - this->centerPos; + this->momentum_Linear = VectorProjection( worldG, worldOffset ); + this->momentum_Angular = Formula::AngularMomentum( worldG, worldOffset ); } -void RigidBody::SetAngularMomentum( const Float3 &worldH ) +void RigidBody::SetVelocity_Linear( const Float4 &worldV ) { // by Dan Andersson - this->angularMomentum = worldH; + this->momentum_Linear = Formula::LinearMomentum( this->mass, worldV ); } -void RigidBody::SetAngularImpulseAcceleration( const Float3 &worldA ) +void RigidBody::SetVelocity_Linear( const Float4 &worldV, const Float4 &atWorldPos ) { // by Dan Andersson - this->impulseTorqueSum = Formula::ImpulseTorque( this->momentOfInertiaTensor, worldA ); + Float4 worldOffset = atWorldPos - this->centerPos; + this->momentum_Linear = Formula::LinearMomentum( this->mass, VectorProjection(worldV, worldOffset) ); + this->momentum_Angular = Formula::AngularMomentum( RotationMatrix(this->rotation) * this->momentOfInertiaTensor, Formula::AngularVelocity(worldV, worldOffset) ); } -void RigidBody::SetAngularVelocity( const Float3 &worldW ) +void RigidBody::SetVelocity_Angular( const Float4 &worldW ) { // by Dan Andersson - this->angularMomentum = Formula::AngularMomentum( this->momentOfInertiaTensor, worldW ); + this->momentum_Angular = Formula::AngularMomentum( this->momentOfInertiaTensor, worldW ); } -void RigidBody::SetImpulseForce( const Float3 &worldF ) +void RigidBody::SetImpulse_Linear( const Float4 &worldJ, const Float4 &atWorldPos ) { // by Dan Andersson - this->impulseForceSum = worldF; -} - -void RigidBody::SetLinearMomentum( const Float3 &worldG ) -{ // by Dan Andersson - this->linearMomentum = worldG; -} - -void RigidBody::SetLinearImpulseAcceleration( const Float3 &worldA ) -{ // by Dan Andersson - this->impulseForceSum = Formula::ImpulseForce( this->mass, worldA ); -} - -void RigidBody::SetLinearVelocity( const Float3 &worldV ) -{ // by Dan Andersson - this->linearMomentum = Formula::LinearMomentum( this->mass, worldV ); -} - -void RigidBody::SetImpulseForceAt( const Float3 &worldForce, const Float3 &worldPos ) -{ // by Dan Andersson - Float3 worldOffset = worldPos - this->box.center; - this->impulseForceSum = VectorProjection( worldForce, worldOffset ); - this->impulseTorqueSum = Formula::ImpulseTorque( worldForce, worldOffset ); -} - -void RigidBody::SetLinearMomentumAt( const Float3 &worldG, const Float3 &worldPos ) -{ // by Dan Andersson - Float3 worldOffset = worldPos - this->box.center; - this->linearMomentum = VectorProjection( worldG, worldOffset ); - this->angularMomentum = Formula::AngularMomentum( worldG, worldOffset ); -} - -void RigidBody::SetImpulseAccelerationAt( const Float3 &worldA, const Float3 &worldPos ) -{ // by Dan Andersson - Float3 worldOffset = worldPos - this->box.center; - this->impulseForceSum = Formula::ImpulseForce( this->mass, VectorProjection(worldA, worldOffset) ); - this->impulseTorqueSum = Formula::ImpulseTorque( this->box.rotation * this->momentOfInertiaTensor, - Formula::AngularImpulseAcceleration(worldA, worldOffset) ); -} - -void RigidBody::SetLinearVelocityAt( const Float3 &worldV, const Float3 &worldPos ) -{ // by Dan Andersson - Float3 worldOffset = worldPos - this->box.center; - this->linearMomentum = Formula::LinearMomentum( this->mass, VectorProjection(worldV, worldOffset) ); - this->angularMomentum = Formula::AngularMomentum( this->box.rotation * this->momentOfInertiaTensor, - Formula::AngularVelocity(worldV, worldOffset) ); + Float4 worldOffset = atWorldPos - this->centerPos; + this->impulse_Linear = VectorProjection( worldJ, worldOffset ); + this->impulse_Angular = Formula::ImpulseTorque( worldJ, worldOffset ); } \ No newline at end of file diff --git a/Code/OysterPhysics3D/RigidBody.h b/Code/OysterPhysics3D/RigidBody.h index 81c92ae0..a2f44480 100644 --- a/Code/OysterPhysics3D/RigidBody.h +++ b/Code/OysterPhysics3D/RigidBody.h @@ -12,109 +12,76 @@ namespace Oyster { namespace Physics3D { struct RigidBody - { /// A struct of a simple rigid body. + { //! A struct of a simple rigid body. public: - ::Oyster::Collision3D::Box box; /** Contains data representing physical presence. (worldValue) */ - ::Oyster::Math::Float3 angularMomentum, /** The angular momentum H (Nm*s) around an parallell axis. (worldValue) */ - linearMomentum, /** The linear momentum G (kg*m/s). (worldValue) */ - impulseTorqueSum, /** The impulse torque T (Nm) that will be consumed each update. (worldValue) */ - impulseForceSum; /** The impulse force F (N) that will be consumed each update. (worldValue) */ + ::Oyster::Math::Float4 centerPos, //!< Location of the body's center in the world. + axis, //!< Euler rotationAxis of the body. + boundingReach, //!< + momentum_Linear, //!< The linear momentum G (kg*m/s). + momentum_Angular, //!< The angular momentum H (Nm*s) around an parallell axis. + impulse_Linear, //!< The linear impulse sum Jl (kg*m/s) that will be consumed each update. + impulse_Angular; //!< The angular impulse sum Ja (kg*m^2/s) that will be consumed each update. + ::Oyster::Math::Float restitutionCoeff, //!< + frictionCoeff_Static, //!< + frictionCoeff_Kinetic; //!< - RigidBody( const ::Oyster::Collision3D::Box &box = ::Oyster::Collision3D::Box(), - ::Oyster::Math::Float mass = 12.0f, - const ::Oyster::Math::Float4x4 &inertiaTensor = ::Oyster::Math::Float4x4::identity ); + RigidBody(); RigidBody & operator = ( const RigidBody &body ); - bool operator == ( const RigidBody &body ); - bool operator != ( const RigidBody &body ); + void Update_LeapFrog( ::Oyster::Math::Float updateFrameLength ); + void Predict_LeapFrog( ::Oyster::Math::Float4 &outDeltaPos, ::Oyster::Math::Float4 &outDeltaAxis, const ::Oyster::Math::Float4 &actingLinearImpulse, const ::Oyster::Math::Float4 &actingAngularImpulse, ::Oyster::Math::Float deltaTime ); - void Update_LeapFrog( ::Oyster::Math::Float deltaTime ); - void ApplyImpulseForce( const ::Oyster::Math::Float3 &worldF ); - void ApplyImpulseForceAt( const ::Oyster::Math::Float3 &worldF, const ::Oyster::Math::Float3 &worldPos ); - void ApplyLinearImpulseAcceleration( const ::Oyster::Math::Float3 &worldA ); - void ApplyLinearImpulseAccelerationAt( const ::Oyster::Math::Float3 &worldA, const ::Oyster::Math::Float3 &worldPos ); - void ApplyImpulseTorque( const ::Oyster::Math::Float3 &worldT ); - void ApplyAngularImpulseAcceleration( const ::Oyster::Math::Float3 &worldA ); - - // ACCESS METHODS ///////////////////////////// - - ::Oyster::Math::Float3 & AccessBoundingReach(); - const ::Oyster::Math::Float3 & AccessBoundingReach() const; - ::Oyster::Math::Float3 & AccessCenter(); - const ::Oyster::Math::Float3 & AccessCenter() const; + void Move( const ::Oyster::Math::Float4 &deltaPos, const ::Oyster::Math::Float4 &deltaAxis ); + void ApplyImpulse( const ::Oyster::Math::Float4 &worldJ, const ::Oyster::Math::Float4 &atWorldPos ); + void ApplyImpulse_Linear( const ::Oyster::Math::Float4 &worldJ ); + void ApplyImpulse_Angular( const ::Oyster::Math::Float4 &worldJ ); + void ApplyForce( const ::Oyster::Math::Float4 &worldF, ::Oyster::Math::Float updateFrameLength ); + void ApplyForce( const ::Oyster::Math::Float4 &worldF, ::Oyster::Math::Float updateFrameLength, const ::Oyster::Math::Float4 &atWorldPos ); // GET METHODS //////////////////////////////// - const ::Oyster::Math::Float4x4 & GetMomentOfInertia() const; - const ::Oyster::Math::Float & GetMass() const; - - const ::Oyster::Math::Float4x4 GetOrientation() const; - ::Oyster::Math::Float4x4 GetView() const; - const ::Oyster::Math::Float4x4 & GetToWorldMatrix() const; - ::Oyster::Math::Float4x4 GetToLocalMatrix() const; - - const ::Oyster::Math::Float3 & GetBoundingReach() const; - ::Oyster::Math::Float3 GetSize() const; - - const ::Oyster::Math::Float3 & GetCenter() const; - - const ::Oyster::Math::Float3 & GetImpulsTorque() const; - const ::Oyster::Math::Float3 & GetAngularMomentum() const; - ::Oyster::Math::Float3 GetAngularImpulseAcceleration() const; - ::Oyster::Math::Float3 GetAngularVelocity() const; - - const ::Oyster::Math::Float3 & GetImpulseForce() const; - const ::Oyster::Math::Float3 & GetLinearMomentum() const; - ::Oyster::Math::Float3 GetLinearImpulseAcceleration() const; - ::Oyster::Math::Float3 GetLinearVelocity() const; - - void GetMomentumAt( const ::Oyster::Math::Float3 &worldPos, const ::Oyster::Math::Float3 &surfaceNormal, ::Oyster::Math::Float3 &normalMomentum, ::Oyster::Math::Float3 &tangentialMomentum ) const; + const ::Oyster::Math::Float4x4 & GetMomentOfInertia() const; + ::Oyster::Math::Float GetMass() const; + const ::Oyster::Math::Quaternion & GetRotation() const; + ::Oyster::Math::Float4x4 GetRotationMatrix() const; + ::Oyster::Math::Float4x4 GetOrientation() const; + ::Oyster::Math::Float4x4 GetView() const; + ::Oyster::Math::Float4x4 GetToWorldMatrix() const; + ::Oyster::Math::Float4x4 GetToLocalMatrix() const; + ::Oyster::Math::Float4 GetSize() const; + ::Oyster::Math::Float4 GetVelocity_Linear() const; + ::Oyster::Math::Float4 GetVelocity_Angular() const; + ::Oyster::Math::Float4 GetLinearMomentum( const ::Oyster::Math::Float4 &atWorldPos ) const; // SET METHODS //////////////////////////////// - void SetMomentOfInertia_KeepVelocity( const ::Oyster::Math::Float4x4 &localI ); - void SetMomentOfInertia_KeepMomentum( const ::Oyster::Math::Float4x4 &localI ); + void SetMomentOfInertia_KeepVelocity( const ::Oyster::Math::Float4x4 &localTensorI ); + void SetMomentOfInertia_KeepMomentum( const ::Oyster::Math::Float4x4 &localTensorI ); void SetMass_KeepVelocity( const ::Oyster::Math::Float &m ); void SetMass_KeepMomentum( const ::Oyster::Math::Float &m ); void SetOrientation( const ::Oyster::Math::Float4x4 &o ); - void SetSize( const ::Oyster::Math::Float3 &widthHeight ); - void SetCenter( const ::Oyster::Math::Float3 &worldPos ); void SetRotation( const ::Oyster::Math::Float4x4 &r ); - - void SetImpulseTorque( const ::Oyster::Math::Float3 &worldT ); - void SetAngularMomentum( const ::Oyster::Math::Float3 &worldH ); - void SetAngularImpulseAcceleration( const ::Oyster::Math::Float3 &worldA ); - void SetAngularVelocity( const ::Oyster::Math::Float3 &worldW ); - - void SetImpulseForce( const ::Oyster::Math::Float3 &worldF ); - void SetLinearMomentum( const ::Oyster::Math::Float3 &worldG ); - void SetLinearImpulseAcceleration( const ::Oyster::Math::Float3 &worldA ); - void SetLinearVelocity( const ::Oyster::Math::Float3 &worldV ); + void SetSize( const ::Oyster::Math::Float4 &widthHeight ); - void SetImpulseForceAt( const ::Oyster::Math::Float3 &worldF, const ::Oyster::Math::Float3 &worldPos ); - void SetLinearMomentumAt( const ::Oyster::Math::Float3 &worldG, const ::Oyster::Math::Float3 &worldPos ); - void SetImpulseAccelerationAt( const ::Oyster::Math::Float3 &worldA, const ::Oyster::Math::Float3 &worldPos ); - void SetLinearVelocityAt( const ::Oyster::Math::Float3 &worldV, const ::Oyster::Math::Float3 &worldPos ); + void SetMomentum_Linear( const ::Oyster::Math::Float4 &worldG, const ::Oyster::Math::Float4 &atWorldPos ); + + void SetVelocity_Linear( const ::Oyster::Math::Float4 &worldV ); + void SetVelocity_Linear( const ::Oyster::Math::Float4 &worldV, const ::Oyster::Math::Float4 &atWorldPos ); + void SetVelocity_Angular( const ::Oyster::Math::Float4 &worldW ); + + void SetImpulse_Linear( const ::Oyster::Math::Float4 &worldJ, const ::Oyster::Math::Float4 &atWorldPos ); + void SetForce( const ::Oyster::Math::Float4 &worldF, ::Oyster::Math::Float updateFrameLength ); + void SetForce( const ::Oyster::Math::Float4 &worldF, ::Oyster::Math::Float updateFrameLength, const ::Oyster::Math::Float4 &atWorldPos ); private: - ::Oyster::Math::Float mass; /** m (kg) */ - ::Oyster::Math::Float4x4 momentOfInertiaTensor; /** I (Nm*s) Tensor matrix ( only need to be 3x3 matrix, but is 4x4 for future hardware acceleration ) (localValue) */ + ::Oyster::Math::Float mass; //!< m (kg) + ::Oyster::Math::Float4x4 momentOfInertiaTensor; //!< I (Nm*s) Tensor matrix ( only need to be 3x3 matrix, but is 4x4 for future hardware acceleration ) (localValue) + ::Oyster::Math::Quaternion rotation; //!< RotationAxis of the body. }; - - // INLINE IMPLEMENTATIONS /////////////////////////////////////// - - inline const ::Oyster::Math::Float4x4 & RigidBody::GetToWorldMatrix() const - { - return this->GetOrientation(); - } - - inline ::Oyster::Math::Float4x4 RigidBody::GetToLocalMatrix() const - { - return this->GetView(); - } - } } +#include "RigidBody_Inline.h" + #endif diff --git a/Code/OysterPhysics3D/RigidBody_Inline.h b/Code/OysterPhysics3D/RigidBody_Inline.h new file mode 100644 index 00000000..980442dd --- /dev/null +++ b/Code/OysterPhysics3D/RigidBody_Inline.h @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////// +// INLINE IMPLEMENTATIONS +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#ifndef OYSTER_PHYSICS_3D_RIGIDBODY_INLINE_H +#define OYSTER_PHYSICS_3D_RIGIDBODY_INLINE_H + +#include "RigidBody.h" + +namespace Oyster { namespace Physics3D +{ + inline void RigidBody::ApplyImpulse_Linear( const ::Oyster::Math::Float4 &worldJ ) + { + this->impulse_Linear += worldJ; + } + + inline void RigidBody::ApplyImpulse_Angular( const ::Oyster::Math::Float4 &worldJ ) + { + this->impulse_Angular += worldJ; + } + + inline void RigidBody::ApplyForce( const ::Oyster::Math::Float4 &worldF, ::Oyster::Math::Float updateFrameLength ) + { + this->impulse_Linear += worldF * updateFrameLength; + } + + inline void RigidBody::ApplyForce( const ::Oyster::Math::Float4 &worldF, ::Oyster::Math::Float updateFrameLength, const ::Oyster::Math::Float4 &atWorldPos ) + { + this->ApplyImpulse( worldF * updateFrameLength, atWorldPos ); + } + + inline ::Oyster::Math::Float4x4 RigidBody::GetToWorldMatrix() const + { + return this->GetOrientation(); + } + + inline ::Oyster::Math::Float4x4 RigidBody::GetToLocalMatrix() const + { + return this->GetView(); + } + + inline ::Oyster::Math::Float4 RigidBody::GetSize() const + { + return 2.0f * this->boundingReach; + } + + inline void RigidBody::SetSize( const ::Oyster::Math::Float4 &widthHeight ) + { + this->boundingReach = ::Utility::Value::Abs( 0.5f * widthHeight ); + } + + inline void RigidBody::SetForce( const ::Oyster::Math::Float4 &worldF, ::Oyster::Math::Float updateFrameLength ) + { + this->impulse_Linear = worldF * updateFrameLength; + } + + inline void RigidBody::SetForce( const ::Oyster::Math::Float4 &worldF, ::Oyster::Math::Float updateFrameLength, const ::Oyster::Math::Float4 &atWorldPos ) + { + this->SetImpulse_Linear( worldF * updateFrameLength, atWorldPos ); + } + +} } + +#endif \ No newline at end of file diff --git a/Code/OysterPhysics3D/Sphere.cpp b/Code/OysterPhysics3D/Sphere.cpp index 4f6f76f7..c402b2ef 100644 --- a/Code/OysterPhysics3D/Sphere.cpp +++ b/Code/OysterPhysics3D/Sphere.cpp @@ -6,14 +6,20 @@ using namespace ::Oyster::Math; Sphere::Sphere( ) : ICollideable(Type_sphere) { - this->center = Float3::null; + this->center = Float4::standard_unit_w; this->radius = 0.0f; } -Sphere::Sphere( const Float3 &_position, const Float &_radius ) : ICollideable(Type_sphere) +Sphere::Sphere( const Float3 &p, const Float &r ) : ICollideable(Type_sphere) { - this->center = _position; - this->radius = _radius; + this->center = Float4( p, 1.0f ); + this->radius = r; +} + +Sphere::Sphere( const Float4 &p, const Float &r ) : ICollideable(Type_sphere) +{ + this->center = p; + this->radius = r; } Sphere::~Sphere( ) {} @@ -26,22 +32,45 @@ Sphere & Sphere::operator = ( const Sphere &sphere ) } ::Utility::DynamicMemory::UniquePointer Sphere::Clone( ) const -{ return ::Utility::DynamicMemory::UniquePointer( new Sphere(*this) ); } +{ + return ::Utility::DynamicMemory::UniquePointer( new Sphere(*this) ); +} bool Sphere::Intersects( const ICollideable &target ) const { switch( target.type ) { - case Type_universe: return true; - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - case Type_ray: return Utility::Intersect( *this, *(Ray*)&target, ((Ray*)&target)->collisionDistance ); - case Type_sphere: return Utility::Intersect( *this, *(Sphere*)&target ); - case Type_plane: return Utility::Intersect( *(Plane*)&target, *this ); - // case Type_triangle: return false; // TODO: - case Type_box_axis_aligned: return Utility::Intersect( *(BoxAxisAligned*)&target, *this ); - case Type_box: return Utility::Intersect( *(Box*)&target, *this ); - case Type_frustrum: return false; // TODO: - default: return false; + case Type_universe: return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, ((const Ray&)target).collisionDistance ); + case Type_sphere: return Utility::Intersect( *this, (const Sphere&)target ); + case Type_plane: return Utility::Intersect( (const Plane&)target, *this ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( (const BoxAxisAligned&)target, *this ); + case Type_box: return Utility::Intersect( (const Box&)target, *this ); + //case Type_frustrum: return false; // TODO: + default: return false; + } +} + +bool Sphere::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ + switch( target.type ) + { + case Type_universe: + worldPointOfContact = this->center; + return true; + case Type_point: return Utility::Intersect( *this, (const Point&)target, worldPointOfContact ); + case Type_ray: return Utility::Intersect( *this, (const Ray&)target, ((const Ray&)target).collisionDistance, worldPointOfContact ); + case Type_sphere: return Utility::Intersect( *this, (const Sphere&)target, worldPointOfContact ); + case Type_plane: return Utility::Intersect( (const Plane&)target, *this, worldPointOfContact ); + //case Type_triangle: return false; // TODO: + case Type_box_axis_aligned: return Utility::Intersect( (const BoxAxisAligned&)target, *this, worldPointOfContact ); + case Type_box: return Utility::Intersect( (const Box&)target, *this, worldPointOfContact ); + //case Type_frustrum: return false; // TODO: + default: + worldPointOfContact = Float3::null; + return false; } } @@ -49,12 +78,12 @@ bool Sphere::Contains( const ICollideable &target ) const { switch( target.type ) { - case Type_point: return Utility::Intersect( *this, *(Point*)&target ); - case Type_sphere: return Utility::Contains( *this, *(Sphere*)&target ); - // case Type_triangle: return false; // TODO: - case Type_box_axis_aligned: return false; // TODO: - case Type_box: return false; // TODO: - case Type_frustrum: return false; // TODO: - default: return false; + case Type_point: return Utility::Intersect( *this, (const Point&)target ); + case Type_sphere: return Utility::Contains( *this, (const Sphere&)target ); + //case Type_triangle: return false; // TODO: + //case Type_box_axis_aligned: return false; // TODO: + //case Type_box: return false; // TODO: + //case Type_frustrum: return false; // TODO: + default: return false; } } \ No newline at end of file diff --git a/Code/OysterPhysics3D/Sphere.h b/Code/OysterPhysics3D/Sphere.h index 8e73de0b..2f483ecd 100644 --- a/Code/OysterPhysics3D/Sphere.h +++ b/Code/OysterPhysics3D/Sphere.h @@ -16,18 +16,20 @@ namespace Oyster { namespace Collision3D public: union { - struct{ ::Oyster::Math::Float3 center; ::Oyster::Math::Float radius; }; - char byte[sizeof(::Oyster::Math::Float3) + sizeof(::Oyster::Math::Float)]; + struct{ ::Oyster::Math::Float4 center; ::Oyster::Math::Float radius; }; + char byte[sizeof(::Oyster::Math::Float4) + sizeof(::Oyster::Math::Float)]; }; Sphere( ); Sphere( const ::Oyster::Math::Float3 ¢er, const ::Oyster::Math::Float &radius ); + Sphere( const ::Oyster::Math::Float4 ¢er, const ::Oyster::Math::Float &radius ); virtual ~Sphere( ); Sphere & operator = ( const Sphere &sphere ); virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; } } diff --git a/Code/OysterPhysics3D/Universe.cpp b/Code/OysterPhysics3D/Universe.cpp index 725e2839..7eb788ae 100644 --- a/Code/OysterPhysics3D/Universe.cpp +++ b/Code/OysterPhysics3D/Universe.cpp @@ -1,6 +1,8 @@ #include "Universe.h" #include "OysterCollision3D.h" +using namespace ::Utility::Value; +using namespace ::Oyster::Math; using namespace ::Oyster::Collision3D; using namespace ::Utility::DynamicMemory; @@ -8,20 +10,24 @@ Universe::Universe() : ICollideable(Type_universe) {} Universe::~Universe() {} Universe & Universe::operator = ( const Universe &universe ) -{ return *this; } +{ + return *this; +} UniquePointer Universe::Clone( ) const -{ return UniquePointer( new Universe(*this) ); } +{ + return UniquePointer( new Universe(*this) ); +} bool Universe::Intersects( const ICollideable &target ) const { // universe touches everything switch( target.type ) { case Type_ray: - ((Ray*)&target)->collisionDistance = 0.0f; + ((const Ray&)target).collisionDistance = 0.0f; break; case Type_line: - ((Line*)&target)->ray.collisionDistance = 0.0f; + ((const Line&)target).ray.collisionDistance = 0.0f; break; default: break; } @@ -29,6 +35,47 @@ bool Universe::Intersects( const ICollideable &target ) const return true; } -bool Universe::Contains( const ICollideable &target ) const -{ return true; } // universe contains everything +bool Universe::Intersects( const ICollideable &target, Float4 &worldPointOfContact ) const +{ // universe touches everything + switch( target.type ) + { + case Type_point: + worldPointOfContact = ((const Point&)target).center; + break; + case Type_sphere: + worldPointOfContact = ((const Sphere&)target).center; + break; + case Type_plane: + worldPointOfContact = ((const Plane&)target).normal * ((const Plane&)target).phasing; + break; + case Type_box_axis_aligned: + worldPointOfContact = Average( ((const BoxAxisAligned&)target).minVertex, ((const BoxAxisAligned&)target).maxVertex ); + break; + case Type_box: + worldPointOfContact = ((const Box&)target).center; + break; + case Type_frustrum: + worldPointOfContact = Average( ((const Frustrum&)target).leftPlane.normal * ((const Frustrum&)target).leftPlane.phasing, ((const Frustrum&)target).rightPlane.normal * ((const Frustrum&)target).rightPlane.phasing ); + worldPointOfContact = Average( worldPointOfContact, Average( ((const Frustrum&)target).bottomPlane.normal * ((const Frustrum&)target).bottomPlane.phasing, ((const Frustrum&)target).topPlane.normal * ((const Frustrum&)target).topPlane.phasing ) ); + worldPointOfContact = Average( worldPointOfContact, Average( ((const Frustrum&)target).nearPlane.normal * ((const Frustrum&)target).nearPlane.phasing, ((const Frustrum&)target).farPlane.normal * ((const Frustrum&)target).farPlane.phasing ) ); + break; + case Type_ray: + ((const Ray&)target).collisionDistance = 0.0f; + worldPointOfContact = ((const Ray&)target).origin; + break; + case Type_line: + ((const Line&)target).ray.collisionDistance = 0.0f; + worldPointOfContact = ((const Line&)target).ray.origin; + break; + default: + worldPointOfContact = Float3::null; + break; + } + return true; +} + +bool Universe::Contains( const ICollideable &target ) const +{ // universe contains everything + return true; +} \ No newline at end of file diff --git a/Code/OysterPhysics3D/Universe.h b/Code/OysterPhysics3D/Universe.h index ff8366be..5f009e0b 100644 --- a/Code/OysterPhysics3D/Universe.h +++ b/Code/OysterPhysics3D/Universe.h @@ -7,6 +7,7 @@ #define OYSTER_COLLISION_3D_UNIVERSE_H #include "ICollideable.h" +#include "OysterMath.h" namespace Oyster { namespace Collision3D { @@ -20,6 +21,7 @@ namespace Oyster { namespace Collision3D virtual ::Utility::DynamicMemory::UniquePointer Clone( ) const; bool Intersects( const ICollideable &target ) const; + bool Intersects( const ICollideable &target, ::Oyster::Math::Float4 &worldPointOfContact ) const; bool Contains( const ICollideable &target ) const; }; } }