#134 FVector FMath::LinePlaneIntersection   UE4     vector     about a year ago (owner) Document
 inline FVector FMath::LinePlaneIntersection
 	(
 	const FVector &Point1,
 	const FVector &Point2,
 	const FPlane  &Plane
 	)
 {
 	return
 		Point1
 		+	(Point2-Point1)
 		*	((Plane.W - (Point1|Plane))/((Point2 - Point1)|Plane));
 }
该功能还有一个实现,在KismetMathLibrary.h里:
 bool UKismetMathLibrary::LinePlaneIntersection(const FVector& LineStart, const FVector& LineEnd, const FPlane& APlane, float& T, FVector& Intersection)
 {
 	FVector RayDir = LineEnd - LineStart;
 	// Check ray is not parallel to plane
 	if ((RayDir | APlane) == 0.0f)
 	{
 		T = -1.0f;
 		Intersection = FVector::ZeroVector;
 		return false;
 	}
 	T = ((APlane.W - (LineStart | APlane)) / (RayDir | APlane));
 	// Check intersection is not outside line segment
 	if (T < 0.0f || T > 1.0f)
 	{
 		Intersection = FVector::ZeroVector;
 		return false;
 	}
 	// Calculate intersection point
 	Intersection = LineStart + RayDir * T;
 	return true;
 }
这两个实现其实是一样的原理,第二个可以当作第一个实现的详细注释版。
解释一下:其中(Vector | Plane)的操作是合法的,是因为FPlane是FVector的派生类型,因此(Vector | Plane)其实就是向量点乘,具体到这里就是Point点乘(Plane的Normal)。【|】运算符是对FVector.DotProduct的重载
就以Kismet里的蓝图函数来说:
  • RayDir是从LineStart指向LineEnd的方向向量,(RayDir | APlane)是RayDir点乘APlane的Normal,若结果为0,表示RayDir⊥Normal,或说RayDir // APlane。
  • FPlane::PlaneDot 函数的解释可以知道(LineStart | APlane) - APlane.W是LineStart到APlane的有向距离,RayDir | APlane【即RayDir.Dot(APlane.Normal)】是RayDir在Normal上的投影,当RayDir与Normal基本同向时(是指RayDir与Normal正向夹角小于90°),投影值为正,否则为负。
  • 取一种典型情况来分析:当LineStart在APlane分割出来的正空间中,LineEnd在负空间中,此时,LineStart与LineEnd连线与APlane有交点X,比例T=|X - LineStart| / |LineEnd - LineStart|. 这个比例根据比例理论,等于[(LineStart | APlane) - APlane.W] / |[RayDir | APlane]|,因为LineStart与LineEnd分处APlane分割的正负空间中,RayDir | APlane此时为负,所以 |[RayDir | APlane]| = - RayDir | APlane,最终得到比例T = [APlane.W - (LineStart | APlane)] / RayDir | APlane.
  • 还有几种其他情形,比如LineStart与LineEnd分别在负空间和正空间,或都在正空间,或都在负空间,只要分析清楚每种情形下LineStart到APlane的有向距离值的符号,RayDir到APlane.Normal的投影值的符号,最终都会得出上面关于T的结论。
  • 接下来函数检测了T值的范围,只关注了直线<LineStart, LineEnd>与APlane交点在LineStart与LineEnd连线之间的情况,简单点说就是这个函数只关注了线段[LineStart, LineEnd]与APlane有交点的情况,交点可以是两端点。这是这个蓝图函数与FMath::LinePlaneIntersection函数唯一的区别。FMath::LinePlaneIntersection函数也处理T在线段外的情况。因此,准确的说,FMath::LinePlaneIntersection函数名副其实,求解的是直线与平面的交点。而这里的蓝图函数求解的是线段与平面的交点,如果线段与平面没有交点,则返回false。
  • 在FMath::LinePlaneIntersection()的实现中:当从P1出发射向P2的射线与Plane有交点时,T值为正,即((Plane.W - (Point1|Plane))/((Point2 - Point1)|Plane))>0;当从P2出发射向P1的射线与Plane有交点时,T值为负,即((Plane.W - (Point1|Plane))/((Point2 - Point1)|Plane))<0。并有:当P1与P2在Plane同一边时,|T|>1;当P1与P2分属Plane的两边时,|T|<1