Beispiel #1
0
int TestSphereTriangle(Sphere& s, glm::vec3& a, glm::vec3& b, glm::vec3& c, glm::vec3 &p) {
    // Find point P on triangle ABC closest to sphere center
    p = ClosestPointTriangle(s.c, a, b, c);

    // Sphere and triangle intersect if the (squared) distance from sphere
    // center to point p is less than the (squared) sphere radius
    glm::vec3 v = p - s.c;
    return glm::dot(v, v) <= s.r * s.r;
}
///
//Performs a dynamic collision check between a moving sphere and a triangle
//
//Overview:
//	Uses a plethora of different algorithms to detect collision between a sphere and a triangle, including:
//	Line segment - Sphere
//	Line segment - Cylinder
//	Point - Triangle
//	and Sphere - Point
//
//Parameters:
//	s: The moving sphere
//	tri: The static triangle
//	mvmt: The relative movement vector of sphere from an observer on triangle
//	tStart: The start of the interval, 0.0f <= tStart < 1.0f
//	tEnd: The end of the interval, 0.0f < tEnd <= 1.0f
//
//Returns:
//	a t value between 0 and 1 indicating the "relative time" since the start of this frame that the collision occurred.
//	a t value of 0.0f would indicate the very start of this frame, a t value of 1.0f would indicate the very end of this frame.
//	This function will return a negative number if no collision was registered.
float CheckDynamicCollision(const struct Sphere& s, const Triangle &tri, const glm::vec3 &mvmt, float tStart, float tEnd)
{
	//Get the three edge vectors of the triangle
	glm::vec3 AB = tri.b - tri.a;
	glm::vec3 BC = tri.c - tri.b;
	glm::vec3 CA = tri.a - tri.c;

	//Get normal of plane which triangle lies in
	glm::vec3 triangleNormal = glm::normalize(glm::cross(AB, -CA));

	//Determine if sphere is travelling parallel to triangle plane
	if (fabs(glm::dot(mvmt, triangleNormal)) > FLT_EPSILON)
	{
		//Not travelling parallel to plane
	
		//Find the point on the sphere which will hit the triangle first
		glm::vec3 pointOnSphere = s.center;
		//Determine which side of plane triangle is on
		glm::vec3 triToSphere = s.center - tri.center;
		if (glm::dot(triToSphere, triangleNormal) < 0.0f)
		{
			pointOnSphere += s.radius * triangleNormal;
		}
		else
		{
			pointOnSphere -= s.radius * triangleNormal;
		}

		//Consider the line segment this point creates over the movement vector
		struct Line circleMvmt;
		circleMvmt.start = pointOnSphere;
		circleMvmt.direction = mvmt;

		//Find the time which this line segment collides with the triangle's plane
		float dist = glm::dot(triangleNormal, tri.a);
		float t = (dist - glm::dot(triangleNormal, circleMvmt.start)) / glm::dot(triangleNormal, circleMvmt.direction);
		
		//If t is not within this timestep, there cannot be a collision
		if (t < 0.0f || t > 1.0f) return -1.0f;

		//Else, determine the point along the line which collides with the plane
		glm::vec3 pointOfPossibleCollision = circleMvmt.start + t * circleMvmt.direction;

		//If this point is contained within the triangle there is a collision
		if (checkPointTriangleCollision(tri, pointOfPossibleCollision)) return t;

		//Else, we can still have a collision. We must raycast from the closest point on the triangle to the sphere along -mvmt and see if it hits.
		//Determine the closest point on triangle t to sphere
		glm::vec3 closestPoint = ClosestPointTriangle(s.center, tri.a, tri.b, tri.c);
		struct Line ray;
		ray.start = closestPoint;
		ray.direction = -circleMvmt.direction;

		return checkSphereLineSegmentCollision(s, ray.start, ray.direction);
	}
	else
	{
		//Travelling parallel to plane

		//Create a line segment which represents the path travelled by the center of the circle
		struct Line circleMvmt;
		circleMvmt.start = s.center;
		circleMvmt.direction = mvmt;

		//Create A cylinder at each triangle edge with a radius of the sphere
		struct Cylinder cyl;
		cyl.start = tri.a + tri.center;
		cyl.direction = AB;
		cyl.radius = s.radius;

		//Determine if the sphere's movement line segment intersects the cylinder
		float minTimeOfIntersection = CheckCylinderSegmentCollision(cyl, circleMvmt);

		//Cylinder along BC
		cyl.start = tri.b + tri.center;
		cyl.direction = BC;

		//Determine if the sphere's movement line segment intersects the cylinder
		float timeOfIntersection = CheckCylinderSegmentCollision(cyl, circleMvmt);
		if (timeOfIntersection != -1.0f && (timeOfIntersection < minTimeOfIntersection || minTimeOfIntersection == -1.0f)) minTimeOfIntersection = timeOfIntersection;

		//Cylinder along CA
		cyl.start = tri.b + tri.center;
		cyl.direction = CA;


		//Determine if the sphere's movement line segment intersects the cylinder
		timeOfIntersection = CheckCylinderSegmentCollision(cyl, circleMvmt);
		if (timeOfIntersection != -1.0f && (timeOfIntersection < minTimeOfIntersection || minTimeOfIntersection == -1.0f)) minTimeOfIntersection = timeOfIntersection;

		//Create spheres at each one of the triangle vertices matching the circle
		Sphere vertexSphere;
		vertexSphere.radius = s.radius;

		vertexSphere.center = tri.center + tri.a;
		timeOfIntersection = checkSphereLineSegmentCollision(vertexSphere, circleMvmt.start, circleMvmt.direction);
		if (timeOfIntersection != -1.0f && (timeOfIntersection < minTimeOfIntersection || minTimeOfIntersection == -1.0f)) minTimeOfIntersection = timeOfIntersection;

		vertexSphere.center = tri.center + tri.b;
		timeOfIntersection = checkSphereLineSegmentCollision(vertexSphere, circleMvmt.start, circleMvmt.direction);
		if (timeOfIntersection != -1.0f && (timeOfIntersection < minTimeOfIntersection || minTimeOfIntersection == -1.0f)) minTimeOfIntersection = timeOfIntersection;

		vertexSphere.center = tri.center + tri.c;
		timeOfIntersection = checkSphereLineSegmentCollision(vertexSphere, circleMvmt.start, circleMvmt.direction);
		if (timeOfIntersection != -1.0f && (timeOfIntersection < minTimeOfIntersection || minTimeOfIntersection == -1.0f)) minTimeOfIntersection = timeOfIntersection;

		return minTimeOfIntersection;
	}
	
}