首页 > 技术文章 > 光线求交-面、三角形、球 (Ray intersection)

yoyo-sincerely 2018-02-02 21:52 原文

光线求交

  • 光线定义:position \(a(t)\) = \(o\) + \(t\vec{d}\);
  • 球定义: center p, radius r;
  • 平面定义:normal \(\vec{n}\) , offset t;
  • 三角形定义:position \(a_1\), \(a_2\), \(a_3\), normal \(\vec{n}\);

光线与球相交 (Ray/Sphere Intersection)


c++代码 :

bool HitTest(const Ray& ray, HitTestResult* result)
{
	Vector eo = Center - ray.Position;
	float v = eo * ray.Direction;
	auto disc = Radius * Radius - (eo * eo) + v * v;
	if (disc < 0) return false;
	disc = v - sqrt(disc);
	if (disc < 0.001f || disc >= ray.MaxDistance) return false;
	result->Shape = const_cast<Sphere*>(this);
	result->Normal = (disc * ray.Direction - eo).Normalize();
	result->Distance = disc;
	return true;
}

光线与平面相交 (Ray / Plane Intersection)

线与平面相交 Ray/Plane Intersection
平面在空间几何中可以用一个向量(法向量)和平面中的一点P0来表示。

平面就是满足下式的点集:\(\vec{n}(\vec{P}-\vec{P_0})= 0\)

得到:\(\vec{n}\cdot\vec{P}=d\); \(d=\vec{n}\cdot\vec{P_0}\);

给定射线r(t) = o +td,平面方程为n.p+d=0,将p(t)带入到平面方程,最后求得t:

\(t = (-d-(\vec{n}\cdot\vec{p_0}))/(\vec{n}\cdot\vec{d})\)


c++代码:

bool HitTest(const Ray& ray, HitTestResult* result)
{
	auto denom = Normal * ray.Direction;
	if (denom > 0) return false;
	auto d = (Normal * ray.Position + Offset) / (-denom);
	if (d >= ray.MaxDistance) return false;
	result->Shape = const_cast<Plane*>(this);
	result->Normal = Normal;
	result->Distance = d;
	return true;
}

光线与三角形相交 (Ray/Triangle Intersection)

  • 判断射线是否与平面相交
  • 判断点是否在三角形内
//构造函数:
Triangle(const Vector& Point1, const Vector& Point2, const Vector& Point3)
		: Point1(Point1), Point2(Point2), Point3(Point3)
{
	auto n1 = Point2 - Point1;
	auto n2 = Point3 - Point1;
	normal = Vector::Cross((Point2 - Point1), (Point3 - Point1)).Normalize();
}
	
bool HitTest(const Ray& ray, HitTestResult* result)
{
	float eo;
	if (normal.Length() != 0 && (eo = ray.Direction * normal) < 0)
	{
		auto S = (Point1 - ray.Position) * normal / eo;
		if (S < 0.001f || S >= ray.MaxDistance)
			return false;

		auto V = S * ray.Direction + ray.Position;

		if (IsInner(V))
		{
			result->Shape = const_cast<Triangle*>(this);
			result->Normal = normal;
			result->Distance = S;
			return true;
		}
		return false;
	}
	return false;
}

另一种方法:[用三角形重心求交

推荐阅读