如何计算光线与平面之间的交点? 我一直在访问我能找到的每个可能的网站,这是我迄今取得的成就:
float denom = normal.dot(ray.direction);
if (denom > 0)
{
float t = -((center - ray.origin).dot(normal)) / denom;
if (t >= 0)
{
rec.tHit = t;
rec.anyHit = true;
computeSurfaceHitFields(ray, rec);
return true;
}
}
这不起作用:s
我的功能输入是:
ray:包含原点和方向
rec:用于存储命中信息的容器类(bool,t等)
我的功能可以访问飞机:
point:定义平面的点
normal:定义平面的法线
答案 0 :(得分:15)
如你所评论的那样,你想让分母为负数,否则你会错过与飞机正面的交叉点。但是,您仍然希望测试避免被零除,这表示光线与平面平行。在计算t
时,你也有一个多余的否定。总的来说,它应该是这样的:
float denom = normal.dot(ray.direction);
if (abs(denom) > 0.0001f) // your favorite epsilon
{
float t = (center - ray.origin).dot(normal) / denom;
if (t >= 0) return true; // you might want to allow an epsilon here too
}
return false;
答案 1 :(得分:7)
首先考虑光线平面交点的数学运算:
通常,一个与光线的参数形式相交,与几何的隐式形式相交。
所以给定x = a * t + a0形式的光线,y = b * t + b0,z = c * t + c0;
和形式的平面:A x * B y * C z + D = 0;
现在将x,y和z射线方程代入平面方程,你将得到t中的多项式。然后你用t的实数值求解那个多项式。利用t的这些值,您可以将替代值替换为射线方程,以获得x,y和z的实际值。 这是Maxima:
请注意,答案看起来像两个点积的商! 平面法线是平面方程A,B和C的前三个系数。 您仍然需要D来唯一地确定平面。 然后用您选择的语言对其进行编码,如下所示:
Point3D intersectRayPlane(Ray ray, Plane plane)
{
Point3D point3D;
// Do the dot products and find t > epsilon that provides intersection.
return (point3D);
}
答案 2 :(得分:2)
vwvan答案的实现
Vector3 Intersect(Vector3 planeP, Vector3 planeN, Vector3 rayP, Vector3 rayD)
{
var d = Vector3.Dot(planeP, -planeN);
var t = -(d + rayP.z * planeN.z + rayP.y * planeN.y + rayP.x * planeN.x) / (rayD.z * planeN.z + rayD.y * planeN.y + rayD.x * planeN.x);
return rayP + t * rayD;
}
答案 3 :(得分:1)
让p = p0 + t*v
对起点p0
进行参数化赋予光线,对v
进行方向矢量t >= 0
赋予光线。
让法线向量dot(n, p) + d = 0
和常数n = (a, b, c)
的平面由d
给出。如果r
是平面上的一点,则d = - dot(n, r)
。完全展开后,平面方程也可以写成ax + by + cz + d = 0
。
将射线代入平面方程可得出:
t = - (dot(n, p) + d) / dot(n, v)
示例实现:
std::optional<vec3> intersectRayWithPlane(
vec3 p, vec3 v, // ray
vec3 n, float d // plane
) {
float denom = dot(n, v);
// Prevent divide by zero:
if (abs(denom) <= 1e-4f)
return std::nullopt;
// If you want to ensure the ray reflects off only
// the "top" half of the plane, use this instead:
if (-denom <= 1e-4f)
return std::nullopt;
float t = -(dot(n, p) + d) / dot(n, v);
// Use pointy end of the ray.
// It is technically correct to compare t < 0,
// but that may be undesirable in a raytracer.
if (t <= 1e-4)
return std::nullopt;
return p + t * v;
}