gpt4 book ai didi

c++ - 射线界平面相交

转载 作者:行者123 更新时间:2023-11-28 04:17:15 26 4
gpt4 key购买 nike

我正在尝试在空闲时间编写光线追踪器。目前正在尝试进行射线 - 有界平面相交。

我的程序已经可以处理无限平面了。我正在尝试计算非无限平面的数学。试图谷歌,但所有资源都只谈论无限平面。

我的平面有一个角点(称为位置),两个 vector (u 和 v)从该点延伸(它们的长度对应于边的长度)。光线有起点和方向。

首先我用公式计算与无限平面的交点

t = normal * (position - origin)/(normal * direction)

法线计算为 u 和 v 的叉积。然后用公式

原点 + 方向 * t

我得到交点本身。

下一步是检查这个点是否在矩形的边界内,这就是我遇到问题的地方。

我的想法是获取从平面角延伸到交点的相对 vector intersection - position,然后将其转换为新的 u、normal 和 v 基础,然后检查如果变换后的 vector 的长度比 u 和 v vector 短。

bool BoundedPlane::intersect(const Vec3f &origin, const Vec3f &direction, float &t) const {
t = normal * (position - origin) / (normal * direction);
Vec3f relative = (origin + direction * t) - position;

Mat3f transform{
Vec3f(u.x, normal.x, v.x),
Vec3f(u.y, normal.y, v.y),
Vec3f(u.z, normal.z, v.z)
};

Vec3f local = transform.mul(relative);
return t > 0 && local.x >= 0 && local.x <= u.x && local.z <= 0 && local.z <= v.z;

}

最后我检查 t 是否大于 0,这意味着交点在相机前面,以及 vector 的长度是否在边界内。这给了我一条奇怪的线:

weird line .

平面应该像这样出现在球体下方:

like this

(如果数字正确,这使用手动检查以查看它是否正确显示)。

我不确定我做错了什么,也不知道是否有更简单的方法来检查边界。提前致谢。

编辑1:

我将转换矩阵计算移到了构造函数中,所以现在相交测试是:

bool BoundedPlane::intersect(const Vec3f &origin, const Vec3f &direction, float &t) const {
if (!InfinitePlane::intersect(origin, direction, t)) {
return false;
}

Vec3f local = transform.mul((origin + direction * t) - position);

return local.x >= 0 && local.x <= 1 && local.z >= 0 && local.z <= 1;
}

变换成员是变换矩阵的逆。

最佳答案

我可以建议另一种方法吗?考虑有原点的框架 position和基础 vector

u = { u.x, u.y, u.z }  
v = { v.x, v.y, v.z }
direction = { direction.x, direction.y, direction.z}

第 1 步:形成矩阵

M = {
{u.x, v.x, direction.x},
{u.y, v.y, direction.y},
{u.z, v.z, direction.z}
}

第 2 步:计算 vector w , 这是 3 x 3 线性方程组的解

M * w = origin - position , 即

w = inverse(M) * (origin - position);

确保direction不与 u, v 共面,否则没有交集和inverse(M)不存在。

第 3 步:如果 0.0 <= w.x && w.x <= 1.0 && 0.0 <= w.y && w.y <= 1.0然后该线与 vector u, v 所张成的平行四边形相交交点是

w0 = { w.x, w.y , 0 };

intersection = position + M * w0;

否则,直线不与 vector u, v 所张成的平行四边形相交

这个算法的思想是考虑(非正交)坐标系position, u, v, direction .然后矩阵M更改此新框架坐标中的所有内容。在这个框架中,线是垂直的,平行于“z-”轴,点 origin有坐标w , 以及通过 w 的垂直线与平面相交于 w0 .

编辑 1:这是 3x3 矩阵逆的模板公式:

如果原始矩阵M是

a  b  c

d e f

g h i

逆是

(1 / det(M)) * { 
{e*i - f*h, c*h - b*i, b*f - c*e},

{f*g - d*i, a*i - c*g, c*d - a*f},

{d*h - e*g, b*g - a*h, a*e - b*d},
}

在哪里

det(M) = a*(e*i - f*h) + b*(f*g - d*i) + c*(d*h - e*h)

是 M 的行列式。

所以反演算法可以如下:

给定

M = {
{a, b, c},
{d, e, f},
{g, h, i},
}
  1. 计算
inv_M = { 
{e*i - f*h, c*h - b*i, b*f - c*e},

{f*g - d*i, a*i - c*g, c*d - a*f},

{d*h - e*g, b*g - a*h, a*e - b*d},
};
  1. 计算
det_M = a*inv_M[1][1] + b*inv_M[2][1] + c*inv_M[3][1]; 
  1. 返回M的逆矩阵
inv_M = (1/det_M) * inv_M;

编辑 2: 让我们尝试另一种方法来加快速度。

第 1 步:对于每个平面,由点 position 确定和两个 vector uv , 预先计算以下 quatntities:

normal = cross(u, v); 

u_dot_u = dot(u, u);

u_dot_v = dot(u, v);

v_dot_v = dot(v, v); // all these need to be computed only once for the u and v vectors

det = u_dot_u * v_dot_v - u_dot_v * u_dot_v; // again only once per u and v

第 2 步:现在,对于带有点 origin 的给定线和方向direction ,和之前一样,计算交点int_point飞机跨越 uv :

t = dot(normal,  position - origin) / dot(normal, direction);

int_point = origin + t * direction;

rhs = int_point - position;

第 3 步:计算

u_dot_rhs = dot(u, rhs);

v_dot_rhs = dot(v, rhs);

w1 = (v_dot_v * u_dot_rhs - u_dot_v * v_dot_rhs) / det;

w2 = (- u_dot_v * u_dot_rhs + u_dot_u * v_dot_rhs) / det;

第 4 步:

if (0 < = w1 && w1 <= 1 && 0 < = w2 && w2 <= 1 ){
int_point is in the parallelogram;
}
else{
int_point is not in the parallelogram;
}

所以我在这里所做的基本上是找到线的交点 origin, directionposition, u, v 给出的飞机并将自己限制在飞机上,这让我可以在 2D 而不是 3D 中工作。我代表

int_point = position + w1 * u + w2 * v;

rhs = int_point - position = w1 * u + w2 * v

并找到 w1w2通过将该 vector 表达式与基 vector 点乘 uv ,这将导致我直接求解的 2x2 线性系统。

关于c++ - 射线界平面相交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56316509/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com