Browse Source

working at convex polygon collision

vlod 1 year ago
parent
commit
199742fa68

+ 21 - 29
Pika/gameplay/containers/physicsTest/physicsTest.h

@@ -39,7 +39,7 @@ struct PhysicsTest: public Container
 	
 		physicsEngine.simulationphysicsSettings.gravity = glm::vec2(0, 9.81) * 100.f;
 
-		for (int i = 0; i < 10; i++)
+		for (int i = 0; i < 0; i++)
 		{
 			//if (i == 1) { mass = 0; }
 
@@ -62,7 +62,6 @@ struct PhysicsTest: public Container
 			}
 		}
 
-
 		glm::vec2 shape[5] = 
 		{
 			{0, -50},
@@ -71,13 +70,15 @@ struct PhysicsTest: public Container
 			{-25, 25},
 			{-40, -10},
 		};
-		//physicsEngine.addBody({500, 200}, ph2d::createConvexPolygonCollider(shape, 5));
+		for (int i = 0; i < 5; i++) { shape[i] *= 2; }
+
+		physicsEngine.addBody({500, 200}, ph2d::createConvexPolygonCollider(shape, 5));
 
 		//physicsEngine.addBody({500, 1100}, 
 		//	ph2d::createBoxCollider({1100, 10}));
 
-		auto body = physicsEngine.addBody({500, 500}, ph2d::createBoxCollider({400, 50}));
-		physicsEngine.bodies[body].flags.setFreezePosition();
+		//auto body = physicsEngine.addBody({500, 500}, ph2d::createBoxCollider({400, 50}));
+		//physicsEngine.bodies[body].flags.setFreezePosition();
 		//physicsEngine.bodies[body].flags.setFreezeRotation();
 
 		//physicsEngine.addBody({1, 800}, ph2d::createBoxCollider({800, 50}));
@@ -91,8 +92,8 @@ struct PhysicsTest: public Container
 		//physicsEngine.addBody({600, 600}, ph2d::createBoxCollider({350, 350}));
 		//physicsEngine.bodies[1].motionState.rotation = glm::radians(30.f);
 
-		//physicsEngine.addBody({500, 500}, ph2d::createCircleCollider({75}));
-		//physicsEngine.addBody({800, 100}, ph2d::createCircleCollider({55}));
+		physicsEngine.addBody({500, 500}, ph2d::createCircleCollider({75}));
+		//physicsEngine.addBody({800, 100}, ph2d::createCircleCollider({25}));
 		//physicsEngine.addBody({900, 500}, ph2d::createCircleCollider({40}));
 		//physicsEngine.addBody({550, 700}, ph2d::createCircleCollider({25}));
 
@@ -171,14 +172,14 @@ struct PhysicsTest: public Container
 
 		ImGui::DragInt("Speed", &simulationSpeed);
 
-		ImGui::SliderAngle("Angle", &physicsEngine.bodies[0].motionState.rotation);
-		ImGui::SliderAngle("angular velocity", &physicsEngine.bodies[0].motionState.angularVelocity);
+		ImGui::SliderAngle("Angle", &physicsEngine.bodies[1].motionState.rotation);
+		ImGui::SliderAngle("angular velocity", &physicsEngine.bodies[1].motionState.angularVelocity);
 		//physicsEngine.bodies[0].motionState.angularVelocity = 1.5;
 
 		ImGui::Text("Mouse pos %d, %d", input.mouseX, input.mouseY);
 
-		ImGui::Text("Y min pos %f", physicsEngine.bodies[0].getAABB().min().y);
-		ImGui::Text("Moment of inertia %f", physicsEngine.bodies[0].motionState.momentOfInertia);
+		ImGui::Text("Y min pos %f", physicsEngine.bodies[1].getAABB().min().y);
+		ImGui::Text("Moment of inertia %f", physicsEngine.bodies[1].motionState.momentOfInertia);
 
 		ImGui::Checkbox("Simulate", &simulate);
 
@@ -188,9 +189,9 @@ struct PhysicsTest: public Container
 		static int selected = -1;
 
 		//mouse
-		if (!simulate && input.rMouse.pressed())
+		if (!simulate && input.rMouse.held())
 		{
-			physicsEngine.bodies[0].motionState.setPos({input.mouseX, input.mouseY});
+			physicsEngine.bodies[1].motionState.setPos({input.mouseX, input.mouseY});
 		}
 
 		static glm::vec2 pressedPosition = {};
@@ -199,22 +200,22 @@ struct PhysicsTest: public Container
 		{
 			selected = -1;
 
-			for (int i = 0; i < physicsEngine.bodies.size(); i++)
+			for (auto b : physicsEngine.bodies)
 			{
-				if (physicsEngine.bodies[i].intersectPoint({input.mouseX, input.mouseY}))
+				if (b.second.intersectPoint({input.mouseX, input.mouseY}))
 				{
-					selected = i;
+					selected = b.first;
 					pressedPosition = {input.mouseX, input.mouseY};
 				}
 			}
 		}
 
-		if (selected >= 0)
+		if (selected > 0)
 		{
 			renderer.renderLine(pressedPosition, {input.mouseX, input.mouseY}, Colors_Blue, 4);
 		}
 
-		if (input.lMouse.released() && selected >= 0)
+		if (input.lMouse.released() && selected > 0)
 		{
 
 			glm::vec2 force = pressedPosition - glm::vec2({input.mouseX, input.mouseY});
@@ -314,22 +315,13 @@ struct PhysicsTest: public Container
 		glm::vec2 tangentA = {};
 		glm::vec2 tangentB = {};
 
-		if (ph2d::BodyvsBody(physicsEngine.bodies[0],
-			physicsEngine.bodies[1],
+		if (ph2d::BodyvsBody(physicsEngine.bodies[1],
+			physicsEngine.bodies[2],
 			p, n, contactPoint, tangentA, tangentB))
 		{
 			penetrated = true;
 		}
 
-		//if (ph2d::OBBvsOBB(physicsEngine.bodies[0].getAABB(),
-		//	physicsEngine.bodies[0].motionState.rotation,
-		//	physicsEngine.bodies[1].getAABB(),
-		//	physicsEngine.bodies[1].motionState.rotation,
-		//	p, n, contactPoint))
-		//{
-		//	penetrated = true;
-		//}
-
 		//auto a = physicsEngine.bodies[0].getAABB();
 		//auto b = physicsEngine.bodies[1].getAABB();
 		//ph2d::Circle a1 = glm::vec3{a.center(),a.size.x / 2};

+ 37 - 2
Pika/resources/logs.txt

@@ -1,2 +1,37 @@
-#2024-11-25 18:06:52: Created container: AngryBirds
-#2024-11-25 18:10:29: Destroyed continer: AngryBirds #1
+#2024-11-28 15:01:42: Created container: PhysicsTest
+#2024-11-28 15:05:50: Reloaded dll
+#2024-11-28 15:06:06: Reloaded dll
+#2024-11-28 15:09:43: Reloaded dll
+#2024-11-28 15:12:49: Reloaded dll
+#2024-11-28 15:13:46: Reloaded dll
+#2024-11-28 15:17:39: Reloaded dll
+#2024-11-28 15:26:56: Reloaded dll
+#2024-11-28 15:27:31: Reloaded dll
+#2024-11-28 15:28:55: Reloaded dll
+#2024-11-28 15:29:54: Reloaded dll
+#2024-11-28 15:30:09: Reloaded dll
+#2024-11-28 15:32:52: Reloaded dll
+#2024-11-28 15:33:16: Reloaded dll
+#2024-11-28 15:36:51: Reloaded dll
+#2024-11-28 15:37:35: Reloaded dll
+#2024-11-28 15:38:05: Reloaded dll
+#2024-11-28 15:38:29: Reloaded dll
+#2024-11-28 15:38:49: Reloaded dll
+#2024-11-28 15:39:28: Reloaded dll
+#2024-11-28 15:42:39: Reloaded dll
+#2024-11-28 15:43:19: Reloaded dll
+#2024-11-28 15:52:27: Reloaded dll
+#2024-11-28 15:53:37: Reloaded dll
+#2024-11-28 15:54:16: Reloaded dll
+#2024-11-28 15:54:34: Reloaded dll
+#2024-11-28 15:55:35: Reloaded dll
+#2024-11-28 15:56:00: Reloaded dll
+#2024-11-28 15:56:46: Reloaded dll
+#2024-11-28 15:57:27: Reloaded dll
+#2024-11-28 15:58:17: Reloaded dll
+#2024-11-28 16:01:08: Reloaded dll
+#2024-11-28 16:02:22: Reloaded dll
+#2024-11-28 16:03:03: Reloaded dll
+#2024-11-28 16:04:42: Reloaded dll
+#2024-11-28 16:04:49: Reloaded dll
+#2024-11-28 16:06:51: Destroyed continer: PhysicsTest #1

+ 4 - 0
Pika/thirdparty/ph2d/include/ph2d/ph2d.h

@@ -254,6 +254,10 @@ namespace ph2d
 		unsigned char vertexCount;
 
 		void getCornersRotated(glm::vec2 corners[PH2D_MAX_CONVEX_SHAPE_POINTS], float angle) const;
+
+		void getCornersRotatedInWorlSpace(glm::vec2 corners[PH2D_MAX_CONVEX_SHAPE_POINTS], float angle,
+			glm::vec2 centerPos) const;
+
 	};
 
 	struct Collider

+ 148 - 3
Pika/thirdparty/ph2d/src/ph2d.cpp

@@ -121,6 +121,17 @@ namespace ph2d
 		}
 	}
 
+	void ConvexPolygon::getCornersRotatedInWorlSpace(glm::vec2 corners[PH2D_MAX_CONVEX_SHAPE_POINTS], float angle, glm::vec2 centerPos) const
+	{
+		int c = std::min((unsigned char)vertexCount, (unsigned char)PH2D_MAX_CONVEX_SHAPE_POINTS);
+		for (int i = 0; i < c; i++)
+		{
+			corners[i] = vertexesObjectSpace[i];
+			corners[i] = rotateAroundCenter(corners[i], angle);
+			corners[i] += centerPos;
+		}
+	}
+
 	//The second is the circle
 	bool AABBvsCircle(AABB abox, AABB bbox, float &penetration,
 		glm::vec2 &normal, glm::vec2 &contactPoint)
@@ -266,6 +277,10 @@ namespace ph2d
 		return rez;
 	}
 
+	float orientationTest(const glm::vec2 &A, const glm::vec2 &B, const glm::vec2 &C)
+	{
+		return (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x);
+	}
 
 	bool CirclevsConvexPolygon(AABB circle, const ConvexPolygon &convexPolygon,
 		glm::vec2 convexPolygonCenter,
@@ -275,13 +290,143 @@ namespace ph2d
 		penetration = 0;
 		normal = {0, 0};
 
-		glm::vec2 corners[PH2D_MAX_CONVEX_SHAPE_POINTS] = {};
+		glm::vec2 corners[PH2D_MAX_CONVEX_SHAPE_POINTS] = {}; //object space
 		convexPolygon.getCornersRotated(corners, rotation);
 		int vertexCount = convexPolygon.vertexCount;
 
 		glm::vec2 circleCenter = circle.center();
-		float circleRadius = circle.size.x/2.f;
-		
+		float circleRadius = circle.size.x / 2.f;
+
+		glm::vec2 vectorToCircle = circleCenter - convexPolygonCenter;
+
+		normalizeSafe(vectorToCircle);
+
+		int supportPoint = 0;
+		float closestValue = glm::dot(corners[0], vectorToCircle);
+
+		for (int i = 1; i < convexPolygon.vertexCount; i++)
+		{
+			float value = glm::dot(corners[i], vectorToCircle);
+
+			if (value > closestValue)
+			{
+				closestValue = value;
+				supportPoint = i;
+			}
+		}
+
+		int closestSupportPoint = supportPoint;
+
+		int secondSupportPoint = 0;
+
+		//find the other vertex
+		{
+			glm::vec2 vertexInWorldSpace = corners[supportPoint] + convexPolygonCenter;
+			glm::vec2 directionToCircle = circleCenter - vertexInWorldSpace;
+
+			//no intersection
+			//if (glm::length(directionToCircle) > circleRadius) { return false; }
+
+			contactPoint = vertexInWorldSpace;
+
+			int vertexLeftIndex = supportPoint - 1; if (vertexLeftIndex < 0) { vertexLeftIndex = convexPolygon.vertexCount - 1; }
+			int vertexRightIndex = (supportPoint + 1) % convexPolygon.vertexCount;
+
+			glm::vec2 leftVertex = corners[vertexLeftIndex];
+			glm::vec2 rightVertex = corners[vertexRightIndex];
+
+			glm::vec2 directionToLeft = leftVertex - corners[supportPoint];
+			glm::vec2 directionToRight = rightVertex - corners[supportPoint];
+			normalizeSafe(directionToLeft);
+			normalizeSafe(directionToRight);
+
+			if (glm::dot(directionToLeft, directionToCircle) > glm::dot(directionToRight, directionToCircle))
+			{
+				secondSupportPoint = vertexLeftIndex;
+			}
+			else
+			{
+				secondSupportPoint = vertexRightIndex;
+			}
+		}
+
+		//make sure the 2 vertexes are always in a consistent order relative to the center of the object
+		{
+
+			if (orientationTest({}, corners[supportPoint], corners[secondSupportPoint]) < 0)
+			{
+				std::swap(supportPoint, secondSupportPoint);
+			}
+		}
+
+		glm::vec2 lineVector = corners[supportPoint] - corners[secondSupportPoint];
+		normalizeSafe(lineVector);
+
+		normal = glm::vec2(lineVector.y, -lineVector.x);
+
+		LineEquation contactLine;
+		contactLine.createFromNormalAndPoint(-normal, corners[supportPoint] + convexPolygonCenter);
+
+		//no intersection
+		if (contactLine.getDistanceToPoint(circleCenter) > circleRadius) { return false; }
+
+
+		//check if only the corner is touching the circle
+		{
+			glm::vec2 dir1 = corners[supportPoint] - corners[secondSupportPoint];
+			glm::vec2 dir2 = (corners[supportPoint] + convexPolygonCenter) - circleCenter;
+
+			glm::vec2 dir3 = corners[secondSupportPoint] - corners[supportPoint];
+			glm::vec2 dir4 = (corners[secondSupportPoint] + convexPolygonCenter) - circleCenter;
+			if (glm::dot(dir1, dir2) < 0 || glm::dot(dir3, dir4) < 0)
+			{
+
+				if (glm::distance(corners[closestSupportPoint] + convexPolygonCenter, 
+					circleCenter) > circleRadius)
+				{
+					//extra check for corectness
+					return 0;
+				}
+
+				glm::vec2 vertexInWorldSpace = corners[closestSupportPoint] + convexPolygonCenter;
+				normal = vertexInWorldSpace - circleCenter;
+				float distanceToRadius = glm::length(normal);
+				
+				if (distanceToRadius == 0)
+				{
+					normal = glm::vec2(lineVector.y, -lineVector.x);
+				}
+				else
+				{
+					normal /= distanceToRadius;
+				}
+
+				//compute penetration
+				{
+					glm::vec2 vertexAtTheEdgeOfTheCircle = circleCenter + normal * circleRadius;
+					contactPoint = (vertexAtTheEdgeOfTheCircle + vertexInWorldSpace) / 2.f;
+					penetration = glm::distance(vertexAtTheEdgeOfTheCircle, vertexInWorldSpace);
+					
+				}
+
+			}
+			else
+			{
+				//todo propper clipping here
+
+
+				//compute penetration
+				glm::vec2 vertexAtTheEdgeOfTheCircle = circleCenter + normal * circleRadius;
+				penetration = contactLine.getDistanceToPoint(vertexAtTheEdgeOfTheCircle);
+				contactPoint = vertexAtTheEdgeOfTheCircle + (normal * (penetration * 0.5f));
+
+				//penetration = 0.001;
+
+			}
+
+		}
+
+		normalizeSafe(normal);
 
 		return true;
 	}