chasing down demons in the physics system......
This commit is contained in:
parent
afd04c317e
commit
5cc441bb63
@ -12,7 +12,7 @@ namespace impl {
|
||||
void mergeManifold( pod::Manifold& manifold );
|
||||
void retrieveManifold( pod::Manifold& current, const pod::Manifold& previous, float distanceThreshold = 0.1f, float separationThreshold = 0.1f, float decay = 0.85f );
|
||||
void prepareManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>& cache, const uf::stl::vector<pod::Island>& islands, const uf::stl::vector<pod::PhysicsBody*>& bodies );
|
||||
void updateManifoldCache( const uf::stl::vector<pod::Manifold>& manifolds, uf::stl::unordered_map<size_t, pod::Manifold>& cache );
|
||||
void updateManifoldCache( pod::Island& island, const pod::CollisionEvent::array_t& previous, uf::stl::unordered_map<size_t, pod::Manifold>& cache );
|
||||
void pruneManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>& cache );
|
||||
void warmupContact( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Contact& c, float dt );
|
||||
void warmupManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Manifold& manifold, float dt );
|
||||
@ -20,5 +20,5 @@ namespace impl {
|
||||
void resolveManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt );
|
||||
void solveManifold( uf::stl::vector<pod::Manifold>& manifolds, float dt );
|
||||
|
||||
void dispatchManifold( pod::Manifold& manifold, pod::CollisionEvent::events_t& events, pod::CollisionEvent::map_t& active, const pod::CollisionEvent::map_t& previous );
|
||||
void dispatchManifold( pod::Manifold& manifold, pod::CollisionEvent::events_t& events, pod::CollisionEvent::array_t& active, const pod::CollisionEvent::array_t& previous );
|
||||
}
|
||||
@ -188,6 +188,7 @@ namespace pod {
|
||||
pod::PhysicsBody* a = NULL;
|
||||
pod::PhysicsBody* b = NULL;
|
||||
uf::stl::vector<pod::Contact> points;
|
||||
uint32_t primaryContactID = 0;
|
||||
};
|
||||
|
||||
struct Constraint {
|
||||
@ -281,14 +282,15 @@ namespace pod {
|
||||
const pod::PhysicsBody* invoker = NULL;
|
||||
pod::Contact contact = { pod::Vector3f{}, pod::Vector3f{}, FLT_MAX };
|
||||
};
|
||||
|
||||
struct PairState {
|
||||
size_t pairKey;
|
||||
pod::PhysicsBody* a;
|
||||
pod::PhysicsBody* b;
|
||||
|
||||
struct Island {
|
||||
bool awake = true;
|
||||
uf::stl::vector<uint32_t> indices;
|
||||
pod::BVH::pairs_t pairs;
|
||||
|
||||
uf::stl::vector<pod::Manifold> manifolds;
|
||||
uf::stl::vector<pod::Constraint*> constraints;
|
||||
bool operator<(const PairState& other) const {
|
||||
return pairKey < other.pairKey;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -383,6 +385,7 @@ namespace pod {
|
||||
typedef std::pair<pod::PhysicsBody*, pod::PhysicsBody*> pairs_t;
|
||||
typedef uf::stl::vector<pod::CollisionEvent> events_t;
|
||||
typedef uf::stl::unordered_map<uint64_t, pod::CollisionEvent::pairs_t> map_t;
|
||||
typedef uf::stl::vector<PairState> array_t;
|
||||
|
||||
pod::CollisionState state = {};
|
||||
pod::PhysicsBody* a = NULL;
|
||||
@ -395,6 +398,17 @@ namespace pod {
|
||||
uint32_t featureA = (uint32_t)(-1);
|
||||
uint32_t featureB = (uint32_t)(-1);
|
||||
};
|
||||
|
||||
struct Island {
|
||||
bool awake = true;
|
||||
uf::stl::vector<uint32_t> indices;
|
||||
pod::BVH::pairs_t pairs;
|
||||
|
||||
uf::stl::vector<pod::Manifold> manifolds;
|
||||
uf::stl::vector<pod::Constraint*> constraints;
|
||||
uf::stl::vector<pod::PairState> active;
|
||||
uf::stl::vector<pod::CollisionEvent> events;
|
||||
};
|
||||
}
|
||||
|
||||
namespace pod {
|
||||
@ -419,6 +433,8 @@ namespace pod {
|
||||
pod::Vector3f pseudoVelocity = {};
|
||||
pod::Vector3f pseudoAngularVelocity = {};
|
||||
|
||||
pod::Vector3f linearFactor = { 1.0f, 1.0f, 1.0f }; // probably better to just have a bitmask for these.......
|
||||
pod::Vector3f angularFactor = { 1.0f, 1.0f, 1.0f };
|
||||
pod::Vector3f inverseInertiaTensor = { 1, 1, 1 };
|
||||
|
||||
pod::Vector3f gravity = { NAN, NAN, NAN }; // an invalid gravity will fallback to world gravity
|
||||
@ -504,7 +520,7 @@ namespace pod {
|
||||
pod::BVH staticBvh;
|
||||
|
||||
pod::CollisionEvent::events_t collisionEvents;
|
||||
pod::CollisionEvent::map_t activeCollisions;
|
||||
pod::CollisionEvent::array_t activeCollisions;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -176,6 +176,9 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
if ( metadataJsonPhysics["inertia"].is<bool>() && !metadataJsonPhysics["inertia"].as<bool>() ) {
|
||||
body.inverseInertiaTensor = { 0.0f, 0.0f, 0.0f };
|
||||
}
|
||||
|
||||
body.linearFactor = uf::vector::decode( metadataJsonPhysics["linearFactor"], body.linearFactor );
|
||||
body.angularFactor = uf::vector::decode( metadataJsonPhysics["angularFactor"], body.angularFactor );
|
||||
}
|
||||
|
||||
UF_BEHAVIOR_METADATA_BIND_SERIALIZER_HOOKS(metadata, metadataJson);
|
||||
|
||||
@ -1540,7 +1540,7 @@ namespace impl {
|
||||
|
||||
// bind physics
|
||||
PropertyPhysType physType;
|
||||
// to-do: optimize this as it cuts my FPS by ~30% with lots of small physics objects
|
||||
// to-do: optimize this as it incurs ~1.5ms even with everything being marked as static
|
||||
if ( ctx.findInheritedProperty( objectID, ctx.properties.physType, physType ) && physType.type != impl::PropertyPhysType::NONE ) {
|
||||
auto& physMeta = node.metadata["physics"];
|
||||
|
||||
@ -1555,7 +1555,10 @@ namespace impl {
|
||||
|
||||
PropertyPhysAttr physAttr;
|
||||
if ( ctx.findInheritedProperty( objectID, ctx.properties.physAttr, physAttr ) ) {
|
||||
physMeta["mass"] = 0.0f; // (physType.type == impl::PropertyPhysType::OBB || physAttr.edge_trigger != 0) ? 0.0f : physAttr.mass;
|
||||
bool isStaticOBB = (physType.type == impl::PropertyPhysType::OBB || physAttr.edge_trigger != 0);
|
||||
bool isCompletelyResting = (physAttr.rest_axes & 0x7);
|
||||
|
||||
physMeta["mass"] = (isStaticOBB || isCompletelyResting) ? 0.0f : physAttr.mass;
|
||||
physMeta["friction"] = physAttr.base_friction;
|
||||
physMeta["restitution"] = physAttr.elasticity;
|
||||
physMeta["gravity"] = uf::vector::encode( pod::Vector3f{0.0f, -0.0981f * physAttr.gravity, 0.0f} );
|
||||
@ -1564,6 +1567,22 @@ namespace impl {
|
||||
physMeta["category"] = "trigger";
|
||||
physMeta["inertia"] = false;
|
||||
}
|
||||
|
||||
pod::Vector3f linearFactor = { 1.0f, 1.0f, 1.0f };
|
||||
if ( physAttr.rest_axes & 0x1 ) linearFactor.x = 0.0f;
|
||||
if ( physAttr.rest_axes & 0x2 ) linearFactor.y = 0.0f;
|
||||
if ( physAttr.rest_axes & 0x4 ) linearFactor.z = 0.0f;
|
||||
|
||||
pod::Vector3f angularFactor = { 1.0f, 1.0f, 1.0f };
|
||||
if ( !(physAttr.rot_axes & 0x1) ) angularFactor.x = 0.0f;
|
||||
if ( !(physAttr.rot_axes & 0x2) ) angularFactor.y = 0.0f;
|
||||
if ( !(physAttr.rot_axes & 0x4) ) angularFactor.z = 0.0f;
|
||||
|
||||
pod::Vector3f linFactor = uf::vector::abs( impl::convertPos_NewDark( linearFactor ) );
|
||||
pod::Vector3f angFactor = uf::vector::abs( impl::convertPos_NewDark( angularFactor ) );
|
||||
|
||||
physMeta["linearFactor"] = uf::vector::encode(linearFactor);
|
||||
physMeta["angularFactor"] = uf::vector::encode(angularFactor);
|
||||
}
|
||||
|
||||
PropertyPhysDims physDims;
|
||||
|
||||
@ -92,7 +92,7 @@ void impl::buildIslands( const pod::BVH::pairs_t& pairs, const uf::stl::vector<p
|
||||
pod::BVH::index_t dynamicIndex = bodies[a]->inverseMass == 0.0f ? b : a;
|
||||
if ( bodies[a]->inverseMass == 0.0f && bodies[b]->inverseMass == 0.0f ) continue;
|
||||
|
||||
pod::BVH::index_t root = unionizer.find(a);
|
||||
pod::BVH::index_t root = unionizer.find(dynamicIndex);
|
||||
if ( rootToIsland.find(root) != rootToIsland.end() ) {
|
||||
pod::BVH::index_t islandID = rootToIsland[root];
|
||||
|
||||
|
||||
@ -44,8 +44,12 @@ void impl::updateActivity( pod::PhysicsBody& body, float dt ) {
|
||||
// already asleep
|
||||
if ( !body.activity.awake ) return;
|
||||
|
||||
// check if body is moving
|
||||
float linSpeed2 = uf::vector::magnitude( body.velocity );
|
||||
// undo gravity
|
||||
pod::Vector3f gravity = uf::vector::isValid( body.gravity ) ? body.gravity : body.world->gravity;
|
||||
pod::Vector3f velocity = body.velocity - (gravity * dt);
|
||||
|
||||
// check if body is moving using the test velocity!
|
||||
float linSpeed2 = uf::vector::magnitude( velocity );
|
||||
float angSpeed2 = uf::vector::magnitude( body.angularVelocity );
|
||||
|
||||
// body is nearly still
|
||||
@ -57,7 +61,9 @@ void impl::updateActivity( pod::PhysicsBody& body, float dt ) {
|
||||
if ( body.activity.sleepTimer > threshold ) impl::sleepBody( body );
|
||||
}
|
||||
// body is moving, reset timer
|
||||
else impl::wakeBody( body );
|
||||
else {
|
||||
impl::wakeBody( body );
|
||||
}
|
||||
}
|
||||
|
||||
// returns an absolute transform while also allowing offsetting the collision body
|
||||
|
||||
@ -292,11 +292,48 @@ void impl::prepareManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>&
|
||||
}
|
||||
}
|
||||
|
||||
void impl::updateManifoldCache( const uf::stl::vector<pod::Manifold>& manifolds, uf::stl::unordered_map<size_t, pod::Manifold>& cache ) {
|
||||
for ( const auto& m : manifolds ) {
|
||||
auto it = cache.find( impl::makePairKey( *m.a, *m.b ) );
|
||||
if ( it == cache.end() ) continue; // assert
|
||||
it->second = m;
|
||||
void impl::updateManifoldCache( pod::Island& island, const pod::CollisionEvent::array_t& previous, uf::stl::unordered_map<size_t, pod::Manifold>& cache ) {
|
||||
auto& manifolds = island.manifolds;
|
||||
auto& active = island.active;
|
||||
auto& events = island.events;
|
||||
|
||||
auto cacheLifetime = uf::physics::settings.manifoldCacheLifetime ? uf::physics::settings.manifoldCacheLifetime : MAX(1, uf::physics::settings.substeps) * 2;
|
||||
|
||||
for ( auto& m : manifolds ) {
|
||||
if ( m.points.empty() ) continue;
|
||||
m.primaryContactID = 0;
|
||||
|
||||
if ( m.points.size() > 1 ) {
|
||||
float maxImpulse = -1.0f;
|
||||
float maxPen = -FLT_MAX;
|
||||
for ( size_t i = 0; i < m.points.size(); ++i ) {
|
||||
if ( m.points[i].accumulatedNormalImpulse > maxImpulse ) {
|
||||
m.primaryContactID = i;
|
||||
maxImpulse = m.points[i].accumulatedNormalImpulse;
|
||||
}
|
||||
if ( m.points[i].penetration > maxPen ) {
|
||||
maxPen = m.points[i].penetration;
|
||||
m.primaryContactID = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl::dispatchManifold( m, events, active, previous );
|
||||
|
||||
if ( uf::physics::settings.warmupSolver ) {
|
||||
auto it = uf::physics::settings.manifoldsCache.find( impl::makePairKey( *m.a, *m.b ) );
|
||||
if ( it != uf::physics::settings.manifoldsCache.end() ) {
|
||||
it->second = m;
|
||||
|
||||
auto& cachedPoints = it->second.points;
|
||||
auto newEnd = std::remove_if(cachedPoints.begin(), cachedPoints.end(),
|
||||
[cacheLifetime](pod::Contact& c) {
|
||||
c.lifetime++;
|
||||
return c.lifetime > cacheLifetime;
|
||||
});
|
||||
cachedPoints.erase(newEnd, cachedPoints.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,18 +342,26 @@ void impl::pruneManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>& ca
|
||||
if ( !cacheLifetime ) {
|
||||
cacheLifetime = MAX(1, uf::physics::settings.substeps) * 2;
|
||||
}
|
||||
|
||||
for ( auto itCache = cache.begin(); itCache != cache.end(); ) {
|
||||
auto& manifold = itCache->second;
|
||||
|
||||
// prune points that are too old
|
||||
for ( auto it = manifold.points.begin(); it != manifold.points.end(); ) {
|
||||
if ( it->lifetime > cacheLifetime ) it = manifold.points.erase(it);
|
||||
else ++it;
|
||||
if ( manifold.a && manifold.b && !manifold.a->activity.awake && !manifold.b->activity.awake ) {
|
||||
++itCache;
|
||||
continue;
|
||||
}
|
||||
|
||||
// prune points that are too old
|
||||
auto newEnd = std::remove_if(manifold.points.begin(), manifold.points.end(),
|
||||
[cacheLifetime](const pod::Contact& c) { return c.lifetime > cacheLifetime; });
|
||||
manifold.points.erase(newEnd, manifold.points.end());
|
||||
|
||||
// empty manifold, kill it
|
||||
if ( manifold.points.empty() ) itCache = cache.erase(itCache);
|
||||
else ++itCache;
|
||||
if ( manifold.points.empty() ) {
|
||||
itCache = cache.erase(itCache);
|
||||
} else {
|
||||
++itCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,37 +401,23 @@ void impl::solveManifold( uf::stl::vector<pod::Manifold>& manifolds, float dt )
|
||||
for ( auto i = 0; i < uf::physics::settings.solverIterations; ++i ) for ( auto& manifold : manifolds ) impl::resolveManifold( *manifold.a, *manifold.b, manifold, dt );
|
||||
}
|
||||
|
||||
void impl::dispatchManifold( pod::Manifold& manifold, pod::CollisionEvent::events_t& events, pod::CollisionEvent::map_t& active, const pod::CollisionEvent::map_t& previous ) {
|
||||
// mark as an active collision
|
||||
void impl::dispatchManifold( pod::Manifold& manifold, pod::CollisionEvent::events_t& events, pod::CollisionEvent::array_t& active, const pod::CollisionEvent::array_t& previous ) {
|
||||
auto pairKey = impl::makePairKey( *manifold.a, *manifold.b );
|
||||
active[pairKey] = { manifold.a, manifold.b };
|
||||
// find largest impulse
|
||||
size_t primaryID = 0;
|
||||
float maxImpulse = -1.0f;
|
||||
for ( auto i = 0; i < manifold.points.size(); ++i ) {
|
||||
auto& c = manifold.points[i];
|
||||
if ( c.accumulatedNormalImpulse <= maxImpulse ) continue;
|
||||
primaryID = i;
|
||||
maxImpulse = c.accumulatedNormalImpulse;
|
||||
}
|
||||
if ( maxImpulse <= EPS ) {
|
||||
float maxPen = -FLT_MAX;
|
||||
for ( int i = 0; i < manifold.points.size(); ++i ) {
|
||||
auto& c = manifold.points[i];
|
||||
if ( c.penetration <= maxPen ) continue;
|
||||
maxPen = c.penetration;
|
||||
primaryID = i;
|
||||
}
|
||||
}
|
||||
auto& contact = manifold.points[primaryID];
|
||||
// dispatch
|
||||
|
||||
active.push_back({ pairKey, manifold.a, manifold.b });
|
||||
|
||||
auto it = std::lower_bound(previous.begin(), previous.end(), pod::PairState{pairKey, nullptr, nullptr});
|
||||
bool isNew = (it == previous.end() || it->pairKey != pairKey);
|
||||
|
||||
auto& contact = manifold.points[manifold.primaryContactID];
|
||||
|
||||
events.emplace_back(pod::CollisionEvent{
|
||||
.state = previous.count( pairKey ) == 0 ? pod::CollisionState::ENTER : pod::CollisionState::SUSTAIN,
|
||||
.state = isNew ? pod::CollisionState::ENTER : pod::CollisionState::SUSTAIN,
|
||||
.a = manifold.a,
|
||||
.b = manifold.b,
|
||||
.point = contact.point,
|
||||
.normal = contact.normal,
|
||||
.impulse = maxImpulse,
|
||||
.impulse = contact.accumulatedNormalImpulse,
|
||||
.featureA = contact.featureA,
|
||||
.featureB = contact.featureB,
|
||||
});
|
||||
|
||||
@ -56,6 +56,7 @@ void uf::physics::tick( pod::World& world, float dt ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//UF_TIMER_MULTITRACE_START("Tick Step Begin");
|
||||
static float accumulator = 0;
|
||||
accumulator += dt;
|
||||
|
||||
@ -65,7 +66,9 @@ void uf::physics::tick( pod::World& world, float dt ) {
|
||||
if ( uf::physics::settings.substeps > 0 ) uf::physics::substep( world, timestep, uf::physics::settings.substeps );
|
||||
else uf::physics::step( world, timestep );
|
||||
accumulator -= timestep;
|
||||
//UF_TIMER_MULTITRACE("Tick Accumulation Step");
|
||||
}
|
||||
//UF_TIMER_MULTITRACE_END("Tick Step Complete");
|
||||
|
||||
if ( uf::physics::settings.debugDraw.mask != pod::Collider::CATEGORY_NONE ) impl::draw( world, dt );
|
||||
}
|
||||
@ -87,6 +90,7 @@ void uf::physics::substep( pod::World& world, float dt, int32_t substeps ) {
|
||||
}
|
||||
}
|
||||
void uf::physics::step( pod::World& world, float dt ) {
|
||||
//UF_TIMER_MULTITRACE_START("Physics Step Begin");
|
||||
auto& bodies = world.bodies;
|
||||
auto& constraints = world.constraints;
|
||||
auto& dynamicBvh = world.dynamicBvh;
|
||||
@ -95,7 +99,7 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
auto& collisionEvents = world.collisionEvents;
|
||||
|
||||
STATIC_THREAD_LOCAL(pod::CollisionEvent::events_t, previousCollisionEvents);
|
||||
STATIC_THREAD_LOCAL(pod::CollisionEvent::map_t, previousCollisions);
|
||||
STATIC_THREAD_LOCAL(pod::CollisionEvent::array_t, previousCollisions);
|
||||
|
||||
std::swap( previousCollisions, activeCollisions );
|
||||
std::swap( previousCollisionEvents, collisionEvents );
|
||||
@ -104,6 +108,8 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
|
||||
++uf::physics::settings.frameCounter;
|
||||
|
||||
activeCollisions.reserve(previousCollisions.size());
|
||||
|
||||
// flatten all transforms into a contiguous buffer
|
||||
static thread_local uf::stl::vector<pod::Transform<>*> originalTransforms; // stores the pointer to the original transform
|
||||
static thread_local uf::stl::vector<pod::Transform<>> flattenedTransforms; // stores the flattened transforms
|
||||
@ -132,6 +138,7 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
for ( auto* body : bodies ) {
|
||||
impl::integrate( *body, dt );
|
||||
}
|
||||
//UF_TIMER_MULTITRACE("Integration & Flattening");
|
||||
|
||||
// rebuild static bvh if dirty
|
||||
if ( staticBvh.dirty && uf::physics::settings.useSplitBvhs ) {
|
||||
@ -151,6 +158,8 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
} break;
|
||||
}
|
||||
|
||||
//UF_TIMER_MULTITRACE("BVH Updates");
|
||||
|
||||
// query for overlaps
|
||||
pod::BVH::pairs_t pairs;
|
||||
impl::queryOverlaps( dynamicBvh, pairs );
|
||||
@ -158,19 +167,33 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
impl::queryOverlaps( dynamicBvh, staticBvh, pairs );
|
||||
}
|
||||
|
||||
//UF_TIMER_MULTITRACE("Broadphase Overlap Queries");
|
||||
|
||||
// build islands from overlaps
|
||||
STATIC_THREAD_LOCAL(uf::stl::vector<pod::Island>, islands);
|
||||
impl::buildIslands( pairs, bodies, constraints, islands );
|
||||
|
||||
//UF_TIMER_MULTITRACE("Island Generation");
|
||||
|
||||
if ( uf::physics::settings.warmupSolver ) impl::prepareManifoldCache( uf::physics::settings.manifoldsCache, islands, bodies );
|
||||
|
||||
std::atomic<long long> timeNarrowphase{0};
|
||||
std::atomic<long long> timeVelocitySolver{0};
|
||||
std::atomic<long long> timePositionSolver{0};
|
||||
std::atomic<long long> timeConstraints{0};
|
||||
std::atomic<long long> timeCache{0};
|
||||
|
||||
// iterate islands
|
||||
//#pragma omp parallel for schedule(dynamic)
|
||||
auto tasks = uf::thread::schedule(true);
|
||||
for ( auto& island : islands ) tasks.queue([&]{
|
||||
auto& manifolds = island.manifolds;
|
||||
auto& constraints = island.constraints;
|
||||
auto& active = island.active;
|
||||
auto& events = island.events;
|
||||
manifolds.clear();
|
||||
active.clear();
|
||||
events.clear();
|
||||
|
||||
// sleeping island, skip (asleep islands shouldn't ever be in here)
|
||||
if ( !island.awake ) return;
|
||||
@ -183,6 +206,7 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
}
|
||||
|
||||
// iterate overlap pairs
|
||||
//auto tStart = TIMER_TRACE.elapsed().asMicroseconds();
|
||||
for ( auto& [ ia, ib ] : island.pairs ) {
|
||||
auto& a = *bodies[ia];
|
||||
auto& b = *bodies[ib];
|
||||
@ -235,38 +259,85 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
// store manifold
|
||||
manifolds.emplace_back( manifold );
|
||||
}
|
||||
//timeNarrowphase += (TIMER_TRACE.elapsed().asMicroseconds() - tStart);
|
||||
// pass manifolds to solver
|
||||
//tStart = TIMER_TRACE.elapsed().asMicroseconds();
|
||||
impl::solveManifold( manifolds, dt );
|
||||
//timeVelocitySolver += (TIMER_TRACE.elapsed().asMicroseconds() - tStart);
|
||||
// do position correction
|
||||
//tStart = TIMER_TRACE.elapsed().asMicroseconds();
|
||||
impl::solvePositions( manifolds, dt );
|
||||
//timePositionSolver += (TIMER_TRACE.elapsed().asMicroseconds() - tStart);
|
||||
// solve constraints
|
||||
//tStart = TIMER_TRACE.elapsed().asMicroseconds();
|
||||
impl::solveConstraints( constraints, dt );
|
||||
//timeConstraints += (TIMER_TRACE.elapsed().asMicroseconds() - tStart);
|
||||
// cache manifold positions
|
||||
if ( uf::physics::settings.warmupSolver ) impl::updateManifoldCache( manifolds, uf::physics::settings.manifoldsCache );
|
||||
//tStart = TIMER_TRACE.elapsed().asMicroseconds();
|
||||
impl::updateManifoldCache( island, previousCollisions, uf::physics::settings.manifoldsCache );
|
||||
//timeCache += (TIMER_TRACE.elapsed().asMicroseconds() - tStart);
|
||||
});
|
||||
uf::thread::execute( tasks );
|
||||
//UF_TIMER_MULTITRACE("Narrowphase & Solvers (Threaded)");
|
||||
//UF_MSG_DEBUG(" -> Manifold Gen: {} us", timeNarrowphase.load());
|
||||
//UF_MSG_DEBUG(" -> Vel Solver : {} us", timeVelocitySolver.load());
|
||||
//UF_MSG_DEBUG(" -> Pos Solver : {} us", timePositionSolver.load());
|
||||
//UF_MSG_DEBUG(" -> Constraints : {} us", timeConstraints.load());
|
||||
//UF_MSG_DEBUG(" -> Cache : {} us", timeCache.load());
|
||||
|
||||
// prune expired manifolds in the cache
|
||||
if ( uf::physics::settings.warmupSolver ) impl::pruneManifoldCache( uf::physics::settings.manifoldsCache );
|
||||
{
|
||||
activeCollisions.clear();
|
||||
size_t totalActive = 0;
|
||||
size_t totalEvents = 0;
|
||||
for ( const auto& island : islands ) {
|
||||
totalActive += island.active.size();
|
||||
totalEvents += island.events.size();
|
||||
}
|
||||
|
||||
for ( auto& island : islands ) for ( auto& manifold : island.manifolds ) {
|
||||
// dispatch collision events
|
||||
impl::dispatchManifold( manifold, collisionEvents, activeCollisions, previousCollisions );
|
||||
// draw collision events
|
||||
if ( uf::physics::settings.debugDraw.contacts ) impl::drawManifold( manifold );
|
||||
}
|
||||
// dispatch exiting collisions
|
||||
for ( auto& [ key, pair ] : previousCollisions ) {
|
||||
// sustained collision
|
||||
if ( activeCollisions.count( key ) > 0 ) continue;
|
||||
// mark as exiting
|
||||
collisionEvents.emplace_back(pod::CollisionEvent{
|
||||
.state = pod::CollisionState::EXIT,
|
||||
.a = pair.first,
|
||||
.b = pair.second,
|
||||
});
|
||||
activeCollisions.clear();
|
||||
activeCollisions.reserve(totalActive);
|
||||
collisionEvents.reserve(collisionEvents.size() + totalEvents);
|
||||
|
||||
for ( auto& island : islands ) {
|
||||
activeCollisions.insert(activeCollisions.end(), island.active.begin(), island.active.end());
|
||||
collisionEvents.insert(collisionEvents.end(), island.events.begin(), island.events.end());
|
||||
}
|
||||
//UF_TIMER_MULTITRACE("Event Dispatch (Insert)");
|
||||
|
||||
std::sort(activeCollisions.begin(), activeCollisions.end());
|
||||
|
||||
//UF_TIMER_MULTITRACE("Sort Active Array");
|
||||
|
||||
auto itPrev = previousCollisions.begin();
|
||||
auto itAct = activeCollisions.begin();
|
||||
|
||||
while ( itPrev != previousCollisions.end() ) {
|
||||
// mark as exiting
|
||||
if ( itAct == activeCollisions.end() || itPrev->pairKey < itAct->pairKey ) {
|
||||
collisionEvents.emplace_back(pod::CollisionEvent{
|
||||
.state = pod::CollisionState::EXIT,
|
||||
.a = itPrev->a,
|
||||
.b = itPrev->b,
|
||||
});
|
||||
|
||||
if ( uf::physics::settings.warmupSolver ) uf::physics::settings.manifoldsCache.erase(itPrev->pairKey);
|
||||
++itPrev;
|
||||
}
|
||||
// sustained collision
|
||||
else if ( itPrev->pairKey == itAct->pairKey ) {
|
||||
++itPrev;
|
||||
++itAct;
|
||||
}
|
||||
// new collision
|
||||
else {
|
||||
++itAct;
|
||||
}
|
||||
}
|
||||
|
||||
//UF_TIMER_MULTITRACE("Event Dispatch (Sweep & Exit)");
|
||||
}
|
||||
|
||||
|
||||
// snap velocities of bodies
|
||||
for ( auto* b : bodies ) impl::snapVelocity( *b, dt );
|
||||
|
||||
@ -304,6 +375,9 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//UF_TIMER_MULTITRACE("Transform Unflattening");
|
||||
//UF_TIMER_MULTITRACE_END("Physics Step Complete");
|
||||
}
|
||||
|
||||
void uf::physics::setMass( pod::PhysicsBody& body, float mass ) {
|
||||
@ -611,7 +685,7 @@ void uf::physics::destroy( uf::Object& object ) {
|
||||
auto* current = &root;
|
||||
while ( current != NULL ) {
|
||||
auto* next = current->next;
|
||||
uf::physics::destroy( *current );
|
||||
uf::physics::destroy( *current );
|
||||
if ( current != &root ) delete current;
|
||||
current = next;
|
||||
}
|
||||
|
||||
@ -188,18 +188,24 @@ void impl::integrate( pod::PhysicsBody& body, float dt ) {
|
||||
auto& world = *body.world;
|
||||
auto& transform = *body.transform;
|
||||
auto fT = uf::transform::flatten( transform );
|
||||
auto gravity = uf::physics::getGravity( body );
|
||||
|
||||
// linear integration
|
||||
pod::Vector3f acceleration = body.forceAccumulator * body.inverseMass;
|
||||
acceleration += uf::physics::getGravity( body ); // apply gravity
|
||||
pod::Vector3f acceleration = (body.forceAccumulator * body.inverseMass);
|
||||
acceleration += gravity; // apply gravity
|
||||
|
||||
acceleration = acceleration * body.linearFactor;
|
||||
body.velocity += acceleration * dt;
|
||||
body.velocity = body.velocity * body.linearFactor;
|
||||
|
||||
// angular integration
|
||||
{
|
||||
pod::Matrix3f R = uf::quaternion::matrix3( fT.orientation );
|
||||
pod::Vector3f localTorque = uf::matrix::multiply( uf::matrix::transpose(R), body.torqueAccumulator );
|
||||
pod::Vector3f localAngAccel = localTorque * body.inverseInertiaTensor; // element-wise
|
||||
|
||||
pod::Vector3f localAngAccel = (localTorque * body.inverseInertiaTensor) * body.angularFactor;
|
||||
body.angularVelocity += uf::matrix::multiply( R, localAngAccel ) * dt;
|
||||
body.angularVelocity = body.angularVelocity * body.angularFactor;
|
||||
}
|
||||
|
||||
// update position
|
||||
|
||||
Loading…
Reference in New Issue
Block a user