Browse Source

Fixed bug in ObjectLayerPairFilterTable (#772)

Jorrit Rouwe 1 year ago
parent
commit
194698f37e

+ 6 - 4
Jolt/Physics/Collision/ObjectLayerPairFilterTable.h

@@ -21,9 +21,9 @@ private:
 		JPH_ASSERT(inLayer2 < mNumObjectLayers);
 		JPH_ASSERT(inLayer2 < mNumObjectLayers);
 
 
 		// Calculate at which bit the entry for this pair resides
 		// Calculate at which bit the entry for this pair resides
-		// We use the fact that a row always starts at inLayer2 * inLayer2 / 2
+		// We use the fact that a row always starts at inLayer2 * (inLayer2 + 1) / 2
 		// (this is the amount of bits needed to store a table of inLayer2 entries)
 		// (this is the amount of bits needed to store a table of inLayer2 entries)
-		return (inLayer2 * inLayer2) / 2 + inLayer1;
+		return (inLayer2 * (inLayer2 + 1)) / 2 + inLayer1;
 	}
 	}
 
 
 public:
 public:
@@ -33,8 +33,10 @@ public:
 	explicit				ObjectLayerPairFilterTable(uint inNumObjectLayers) :
 	explicit				ObjectLayerPairFilterTable(uint inNumObjectLayers) :
 		mNumObjectLayers(inNumObjectLayers)
 		mNumObjectLayers(inNumObjectLayers)
 	{
 	{
-		// By default everything collides
-		int table_size = (inNumObjectLayers * inNumObjectLayers / 2 + 7) / 8;
+		// By default nothing collides
+		// For the first layer we only need to store 1 bit, for the second 2 bits, for the third 3 bits, etc.
+		// We use the formula Sum_i=1^N i = N * (N + 1) / 2 to calculate the size of the table
+		int table_size = (inNumObjectLayers * (inNumObjectLayers + 1) / 2 + 7) / 8;
 		mTable.resize(table_size, 0);
 		mTable.resize(table_size, 0);
 	}
 	}
 
 

+ 27 - 0
UnitTests/Physics/ObjectLayerPairFilterTableTests.cpp

@@ -103,4 +103,31 @@ TEST_SUITE("ObjectLayerPairFilterTableTests")
 		CHECK(!obj_vs_bp_filter.ShouldCollide(Layers::SENSOR, BroadPhaseLayers::LQ_DEBRIS));
 		CHECK(!obj_vs_bp_filter.ShouldCollide(Layers::SENSOR, BroadPhaseLayers::LQ_DEBRIS));
 		CHECK(!obj_vs_bp_filter.ShouldCollide(Layers::SENSOR, BroadPhaseLayers::SENSOR));
 		CHECK(!obj_vs_bp_filter.ShouldCollide(Layers::SENSOR, BroadPhaseLayers::SENSOR));
 	}
 	}
+
+	TEST_CASE("ObjectLayerPairFilterTableTest2")
+	{
+		const int n = 10;
+
+		std::pair<ObjectLayer, ObjectLayer> pairs[] = {
+			{ ObjectLayer(0), ObjectLayer(0) },
+			{ ObjectLayer(9), ObjectLayer(9) },
+			{ ObjectLayer(1), ObjectLayer(3) },
+			{ ObjectLayer(3), ObjectLayer(1) },
+			{ ObjectLayer(5), ObjectLayer(7) },
+			{ ObjectLayer(7), ObjectLayer(5) }
+		};
+
+		for (auto &p : pairs)
+		{
+			ObjectLayerPairFilterTable obj_vs_obj_filter(n);
+			obj_vs_obj_filter.EnableCollision(p.first, p.second);
+
+			for (ObjectLayer i = 0; i < n; ++i)
+				for (ObjectLayer j = 0; j < n; ++j)
+				{
+					bool should_collide = (i == p.first && j == p.second) || (i == p.second && j == p.first);
+					CHECK(obj_vs_obj_filter.ShouldCollide(i, j) == should_collide);
+				}
+		}
+	}
 }
 }