Optimization of the islands computation
This commit is contained in:
parent
5cf8cb7445
commit
98ac47cbad
|
@ -46,10 +46,14 @@ struct Islands {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// -------------------- Attributes -------------------- //
|
/// Number of islands in the previous frame
|
||||||
|
uint32 mNbIslandsPreviousFrame;
|
||||||
|
|
||||||
/// Reference to the memory allocator
|
/// Maximum number of bodies in a single island in the previous frame
|
||||||
MemoryAllocator& memoryAllocator;
|
uint32 mNbMaxBodiesInIslandPreviousFrame;
|
||||||
|
|
||||||
|
/// Maximum number of bodies in a single island in the current frame
|
||||||
|
uint32 mNbMaxBodiesInIslandCurrentFrame;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -62,15 +66,22 @@ struct Islands {
|
||||||
/// For each island, number of contact manifolds in the island
|
/// For each island, number of contact manifolds in the island
|
||||||
List<uint> nbContactManifolds;
|
List<uint> nbContactManifolds;
|
||||||
|
|
||||||
/// For each island, list of all the entities of the bodies in the island
|
/// List of all the entities of the bodies in the islands (stored sequentially)
|
||||||
List<List<Entity>> bodyEntities;
|
List<Entity> bodyEntities;
|
||||||
|
|
||||||
|
/// For each island we store the starting index of the bodies of that island in the "bodyEntities" array
|
||||||
|
List<uint32> startBodyEntitiesIndex;
|
||||||
|
|
||||||
|
/// For each island, total number of bodies in the island
|
||||||
|
List<uint32> nbBodiesInIsland;
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
Islands(MemoryAllocator& allocator)
|
Islands(MemoryAllocator& allocator)
|
||||||
:memoryAllocator(allocator), contactManifoldsIndices(allocator), nbContactManifolds(allocator),
|
:mNbIslandsPreviousFrame(10), mNbMaxBodiesInIslandPreviousFrame(0), mNbMaxBodiesInIslandCurrentFrame(0),
|
||||||
bodyEntities(allocator) {
|
contactManifoldsIndices(allocator), nbContactManifolds(allocator),
|
||||||
|
bodyEntities(allocator), startBodyEntitiesIndex(allocator), nbBodiesInIsland(allocator) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +89,7 @@ struct Islands {
|
||||||
~Islands() = default;
|
~Islands() = default;
|
||||||
|
|
||||||
/// Assignment operator
|
/// Assignment operator
|
||||||
Islands& operator=(const Islands& island) = default;
|
Islands& operator=(const Islands& island) = delete;
|
||||||
|
|
||||||
/// Copy-constructor
|
/// Copy-constructor
|
||||||
Islands(const Islands& island) = default;
|
Islands(const Islands& island) = default;
|
||||||
|
@ -91,21 +102,62 @@ struct Islands {
|
||||||
/// Add an island and return its index
|
/// Add an island and return its index
|
||||||
uint32 addIsland(uint32 contactManifoldStartIndex) {
|
uint32 addIsland(uint32 contactManifoldStartIndex) {
|
||||||
|
|
||||||
uint32 islandIndex = contactManifoldsIndices.size();
|
const uint32 islandIndex = contactManifoldsIndices.size();
|
||||||
|
|
||||||
contactManifoldsIndices.add(contactManifoldStartIndex);
|
contactManifoldsIndices.add(contactManifoldStartIndex);
|
||||||
nbContactManifolds.add(0);
|
nbContactManifolds.add(0);
|
||||||
bodyEntities.add(List<Entity>(memoryAllocator));
|
startBodyEntitiesIndex.add(bodyEntities.size());
|
||||||
|
nbBodiesInIsland.add(0);
|
||||||
|
|
||||||
|
if (islandIndex > 0 && nbBodiesInIsland[islandIndex-1] > mNbMaxBodiesInIslandCurrentFrame) {
|
||||||
|
mNbMaxBodiesInIslandCurrentFrame = nbBodiesInIsland[islandIndex-1];
|
||||||
|
}
|
||||||
|
|
||||||
return islandIndex;
|
return islandIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addBodyToIsland(Entity bodyEntity) {
|
||||||
|
|
||||||
|
const uint32 islandIndex = contactManifoldsIndices.size();
|
||||||
|
assert(islandIndex > 0);
|
||||||
|
|
||||||
|
bodyEntities.add(bodyEntity);
|
||||||
|
nbBodiesInIsland[islandIndex - 1]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reserve memory for the current frame
|
||||||
|
void reserveMemory() {
|
||||||
|
|
||||||
|
contactManifoldsIndices.reserve(mNbIslandsPreviousFrame);
|
||||||
|
nbContactManifolds.reserve(mNbIslandsPreviousFrame);
|
||||||
|
startBodyEntitiesIndex.reserve(mNbIslandsPreviousFrame);
|
||||||
|
nbBodiesInIsland.reserve(mNbIslandsPreviousFrame);
|
||||||
|
|
||||||
|
bodyEntities.reserve(mNbMaxBodiesInIslandPreviousFrame);
|
||||||
|
}
|
||||||
|
|
||||||
/// Clear all the islands
|
/// Clear all the islands
|
||||||
void clear() {
|
void clear() {
|
||||||
|
|
||||||
|
const uint32 nbIslands = nbContactManifolds.size();
|
||||||
|
|
||||||
|
if (nbIslands > 0 && nbBodiesInIsland[nbIslands-1] > mNbMaxBodiesInIslandCurrentFrame) {
|
||||||
|
mNbMaxBodiesInIslandCurrentFrame = nbBodiesInIsland[nbIslands-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
mNbIslandsPreviousFrame = nbContactManifolds.size();
|
||||||
|
mNbIslandsPreviousFrame = mNbMaxBodiesInIslandCurrentFrame;
|
||||||
|
mNbMaxBodiesInIslandCurrentFrame = 0;
|
||||||
|
|
||||||
contactManifoldsIndices.clear(true);
|
contactManifoldsIndices.clear(true);
|
||||||
nbContactManifolds.clear(true);
|
nbContactManifolds.clear(true);
|
||||||
bodyEntities.clear(true);
|
bodyEntities.clear(true);
|
||||||
|
startBodyEntitiesIndex.clear(true);
|
||||||
|
nbBodiesInIsland.clear(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 getNbMaxBodiesInIslandPreviousFrame() const {
|
||||||
|
return mNbMaxBodiesInIslandPreviousFrame;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -756,11 +756,14 @@ void PhysicsWorld::createIslands() {
|
||||||
mJointsComponents.mIsAlreadyInIsland[i] = false;
|
mJointsComponents.mIsAlreadyInIsland[i] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reserve memory for the islands
|
||||||
|
mIslands.reserveMemory();
|
||||||
|
|
||||||
// Create a stack for the bodies to visit during the Depth First Search
|
// Create a stack for the bodies to visit during the Depth First Search
|
||||||
Stack<Entity> bodyEntityIndicesToVisit(mMemoryManager.getSingleFrameAllocator());
|
Stack<uint32> bodyEntityIndicesToVisit(mMemoryManager.getSingleFrameAllocator(), mIslands.getNbMaxBodiesInIslandPreviousFrame());
|
||||||
|
|
||||||
// List of static bodies added to the current island (used to reset the isAlreadyInIsland variable of static bodies)
|
// List of static bodies added to the current island (used to reset the isAlreadyInIsland variable of static bodies)
|
||||||
List<Entity> staticBodiesAddedToIsland(mMemoryManager.getSingleFrameAllocator());
|
List<uint32> staticBodiesAddedToIsland(mMemoryManager.getSingleFrameAllocator());
|
||||||
|
|
||||||
uint nbTotalManifolds = 0;
|
uint nbTotalManifolds = 0;
|
||||||
|
|
||||||
|
@ -778,7 +781,7 @@ void PhysicsWorld::createIslands() {
|
||||||
|
|
||||||
// Add the body into the stack of bodies to visit
|
// Add the body into the stack of bodies to visit
|
||||||
mRigidBodyComponents.mIsAlreadyInIsland[b] = true;
|
mRigidBodyComponents.mIsAlreadyInIsland[b] = true;
|
||||||
bodyEntityIndicesToVisit.push(mRigidBodyComponents.mBodiesEntities[b]);
|
bodyEntityIndicesToVisit.push(b);
|
||||||
|
|
||||||
// Create the new island
|
// Create the new island
|
||||||
uint32 islandIndex = mIslands.addIsland(nbTotalManifolds);
|
uint32 islandIndex = mIslands.addIsland(nbTotalManifolds);
|
||||||
|
@ -787,20 +790,26 @@ void PhysicsWorld::createIslands() {
|
||||||
while (bodyEntityIndicesToVisit.size() > 0) {
|
while (bodyEntityIndicesToVisit.size() > 0) {
|
||||||
|
|
||||||
// Get the next body to visit from the stack
|
// Get the next body to visit from the stack
|
||||||
const Entity bodyToVisitEntity = bodyEntityIndicesToVisit.pop();
|
const uint32 bodyToVisitIndex = bodyEntityIndicesToVisit.pop();
|
||||||
|
|
||||||
|
// Get the body entity
|
||||||
|
const Entity bodyToVisitEntity = mRigidBodyComponents.mBodiesEntities[bodyToVisitIndex];
|
||||||
|
|
||||||
// Add the body into the island
|
// Add the body into the island
|
||||||
mIslands.bodyEntities[islandIndex].add(bodyToVisitEntity);
|
mIslands.addBodyToIsland(bodyToVisitEntity);
|
||||||
|
|
||||||
RigidBody* rigidBodyToVisit = static_cast<RigidBody*>(mCollisionBodyComponents.getBody(bodyToVisitEntity));
|
RigidBody* rigidBodyToVisit = mRigidBodyComponents.mRigidBodies[bodyToVisitIndex];
|
||||||
|
|
||||||
// Awake the body if it is sleeping
|
// Awake the body if it is sleeping (note that this called might change the body index in the mRigidBodyComponents array)
|
||||||
rigidBodyToVisit->setIsSleeping(false);
|
rigidBodyToVisit->setIsSleeping(false);
|
||||||
|
|
||||||
// If the current body is static, we do not want to perform the DFS search across that body
|
// If the current body is static, we do not want to perform the DFS search across that body
|
||||||
if (rigidBodyToVisit->getType() == BodyType::STATIC) {
|
if (rigidBodyToVisit->getType() == BodyType::STATIC) {
|
||||||
|
|
||||||
staticBodiesAddedToIsland.add(bodyToVisitEntity);
|
// Get the new body index in the mRigidBodyComponents (this index might have changed due to the call to rigidBodyToVisite->setIsSleeping(false))
|
||||||
|
const uint32 newBodyIndex = mRigidBodyComponents.getEntityIndex(bodyToVisitEntity);
|
||||||
|
|
||||||
|
staticBodiesAddedToIsland.add(newBodyIndex);
|
||||||
|
|
||||||
// Go to the next body
|
// Go to the next body
|
||||||
continue;
|
continue;
|
||||||
|
@ -831,13 +840,14 @@ void PhysicsWorld::createIslands() {
|
||||||
pair.isAlreadyInIsland = true;
|
pair.isAlreadyInIsland = true;
|
||||||
|
|
||||||
const Entity otherBodyEntity = pair.body1Entity == bodyToVisitEntity ? pair.body2Entity : pair.body1Entity;
|
const Entity otherBodyEntity = pair.body1Entity == bodyToVisitEntity ? pair.body2Entity : pair.body1Entity;
|
||||||
|
const uint32 otherBodyIndex = mRigidBodyComponents.getEntityIndex(otherBodyEntity);
|
||||||
|
|
||||||
// Check if the other body has already been added to the island
|
// Check if the other body has already been added to the island
|
||||||
if (mRigidBodyComponents.getIsAlreadyInIsland(otherBodyEntity)) continue;
|
if (mRigidBodyComponents.mIsAlreadyInIsland[otherBodyIndex]) continue;
|
||||||
|
|
||||||
// Insert the other body into the stack of bodies to visit
|
// Insert the other body into the stack of bodies to visit
|
||||||
bodyEntityIndicesToVisit.push(otherBodyEntity);
|
bodyEntityIndicesToVisit.push(otherBodyIndex);
|
||||||
mRigidBodyComponents.setIsAlreadyInIsland(otherBodyEntity, true);
|
mRigidBodyComponents.mIsAlreadyInIsland[otherBodyIndex] = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
|
@ -861,12 +871,14 @@ void PhysicsWorld::createIslands() {
|
||||||
const Entity body2Entity = mJointsComponents.getBody2Entity(joints[i]);
|
const Entity body2Entity = mJointsComponents.getBody2Entity(joints[i]);
|
||||||
const Entity otherBodyEntity = body1Entity == bodyToVisitEntity ? body2Entity : body1Entity;
|
const Entity otherBodyEntity = body1Entity == bodyToVisitEntity ? body2Entity : body1Entity;
|
||||||
|
|
||||||
|
const uint32 otherBodyIndex = mRigidBodyComponents.getEntityIndex(otherBodyEntity);
|
||||||
|
|
||||||
// Check if the other body has already been added to the island
|
// Check if the other body has already been added to the island
|
||||||
if (mRigidBodyComponents.getIsAlreadyInIsland(otherBodyEntity)) continue;
|
if (mRigidBodyComponents.mIsAlreadyInIsland[otherBodyIndex]) continue;
|
||||||
|
|
||||||
// Insert the other body into the stack of bodies to visit
|
// Insert the other body into the stack of bodies to visit
|
||||||
bodyEntityIndicesToVisit.push(otherBodyEntity);
|
bodyEntityIndicesToVisit.push(otherBodyIndex);
|
||||||
mRigidBodyComponents.setIsAlreadyInIsland(otherBodyEntity, true);
|
mRigidBodyComponents.mIsAlreadyInIsland[otherBodyIndex] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,8 +886,8 @@ void PhysicsWorld::createIslands() {
|
||||||
// can also be included in the other islands
|
// can also be included in the other islands
|
||||||
for (uint j=0; j < staticBodiesAddedToIsland.size(); j++) {
|
for (uint j=0; j < staticBodiesAddedToIsland.size(); j++) {
|
||||||
|
|
||||||
assert(mRigidBodyComponents.getBodyType(staticBodiesAddedToIsland[j]) == BodyType::STATIC);
|
assert(mRigidBodyComponents.mBodyTypes[staticBodiesAddedToIsland[j]] == BodyType::STATIC);
|
||||||
mRigidBodyComponents.setIsAlreadyInIsland(staticBodiesAddedToIsland[j], false);
|
mRigidBodyComponents.mIsAlreadyInIsland[staticBodiesAddedToIsland[j]] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
staticBodiesAddedToIsland.clear();
|
staticBodiesAddedToIsland.clear();
|
||||||
|
@ -900,30 +912,29 @@ void PhysicsWorld::updateSleepingBodies(decimal timeStep) {
|
||||||
decimal minSleepTime = DECIMAL_LARGEST;
|
decimal minSleepTime = DECIMAL_LARGEST;
|
||||||
|
|
||||||
// For each body of the island
|
// For each body of the island
|
||||||
for (uint b=0; b < mIslands.bodyEntities[i].size(); b++) {
|
for (uint b=0; b < mIslands.nbBodiesInIsland[i]; b++) {
|
||||||
|
|
||||||
const Entity bodyEntity = mIslands.bodyEntities[i][b];
|
const Entity bodyEntity = mIslands.bodyEntities[mIslands.startBodyEntitiesIndex[i] + b];
|
||||||
|
const uint32 bodyIndex = mRigidBodyComponents.getEntityIndex(bodyEntity);
|
||||||
|
|
||||||
// Skip static bodies
|
// Skip static bodies
|
||||||
if (mRigidBodyComponents.getBodyType(bodyEntity) == BodyType::STATIC) continue;
|
if (mRigidBodyComponents.mBodyTypes[bodyIndex] == BodyType::STATIC) continue;
|
||||||
|
|
||||||
// If the body is velocity is large enough to stay awake
|
// If the body is velocity is large enough to stay awake
|
||||||
if (mRigidBodyComponents.getLinearVelocity(bodyEntity).lengthSquare() > sleepLinearVelocitySquare ||
|
if (mRigidBodyComponents.mLinearVelocities[bodyIndex].lengthSquare() > sleepLinearVelocitySquare ||
|
||||||
mRigidBodyComponents.getAngularVelocity(bodyEntity).lengthSquare() > sleepAngularVelocitySquare ||
|
mRigidBodyComponents.mAngularVelocities[bodyIndex].lengthSquare() > sleepAngularVelocitySquare ||
|
||||||
!mRigidBodyComponents.getIsAllowedToSleep(bodyEntity)) {
|
!mRigidBodyComponents.mIsAllowedToSleep[bodyIndex]) {
|
||||||
|
|
||||||
// Reset the sleep time of the body
|
// Reset the sleep time of the body
|
||||||
mRigidBodyComponents.setSleepTime(bodyEntity, decimal(0.0));
|
mRigidBodyComponents.mSleepTimes[bodyIndex] = decimal(0.0);
|
||||||
minSleepTime = decimal(0.0);
|
minSleepTime = decimal(0.0);
|
||||||
}
|
}
|
||||||
else { // If the body velocity is below the sleeping velocity threshold
|
else { // If the body velocity is below the sleeping velocity threshold
|
||||||
|
|
||||||
// Increase the sleep time
|
// Increase the sleep time
|
||||||
decimal sleepTime = mRigidBodyComponents.getSleepTime(bodyEntity);
|
mRigidBodyComponents.mSleepTimes[bodyIndex] += timeStep;
|
||||||
mRigidBodyComponents.setSleepTime(bodyEntity, sleepTime + timeStep);
|
if (mRigidBodyComponents.mSleepTimes[bodyIndex] < minSleepTime) {
|
||||||
sleepTime = mRigidBodyComponents.getSleepTime(bodyEntity);
|
minSleepTime = mRigidBodyComponents.mSleepTimes[bodyIndex];
|
||||||
if (sleepTime < minSleepTime) {
|
|
||||||
minSleepTime = sleepTime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -934,9 +945,9 @@ void PhysicsWorld::updateSleepingBodies(decimal timeStep) {
|
||||||
if (minSleepTime >= mTimeBeforeSleep) {
|
if (minSleepTime >= mTimeBeforeSleep) {
|
||||||
|
|
||||||
// Put all the bodies of the island to sleep
|
// Put all the bodies of the island to sleep
|
||||||
for (uint b=0; b < mIslands.bodyEntities[i].size(); b++) {
|
for (uint b=0; b < mIslands.nbBodiesInIsland[i]; b++) {
|
||||||
|
|
||||||
const Entity bodyEntity = mIslands.bodyEntities[i][b];
|
const Entity bodyEntity = mIslands.bodyEntities[mIslands.startBodyEntitiesIndex[i] + b];
|
||||||
RigidBody* body = mRigidBodyComponents.getRigidBody(bodyEntity);
|
RigidBody* body = mRigidBodyComponents.getRigidBody(bodyEntity);
|
||||||
body->setIsSleeping(true);
|
body->setIsSleeping(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ void ContactSolverSystem::initializeForIsland(uint islandIndex) {
|
||||||
|
|
||||||
RP3D_PROFILE("ContactSolver::initializeForIsland()", mProfiler);
|
RP3D_PROFILE("ContactSolver::initializeForIsland()", mProfiler);
|
||||||
|
|
||||||
assert(mIslands.bodyEntities[islandIndex].size() > 0);
|
assert(mIslands.nbBodiesInIsland[islandIndex] > 0);
|
||||||
assert(mIslands.nbContactManifolds[islandIndex] > 0);
|
assert(mIslands.nbContactManifolds[islandIndex] > 0);
|
||||||
|
|
||||||
// For each contact manifold of the island
|
// For each contact manifold of the island
|
||||||
|
|
Loading…
Reference in New Issue
Block a user