给定两个向量A和B,它们形成线段L = AB。此外,给定一个由其左、右、下、上、近和远平面定义的视锥F。
我如何剪辑L反对F?
也就是说,测试一个交叉点以及该交叉点在 L 上的哪个位置?(请记住,如果一条线段在拐角处与两侧相交,则它可以与平截头体有多个交点。)
如果可能,请提供代码示例(首选 C++ 或 Python)。
我现在不想为此编写代码,但如果我正确理解“截锥体”,以下应该可以工作。
但我可能完全误解了。在这种情况下,请详细说明:)
除了上面所说的下士 Touchy 所说的,您还需要知道如何将线段与平面相交。在该页面的描述中, u 表示您的线的参数定义中的参数。首先,使用描述的 2 种方法之一计算 u。如果 u 的值在 0.0 到 1.0 的范围内,则平面会剪裁线段上某处的线。将 u 插回您的直线方程可以为您提供该交点发生的点。
另一种方法是找到每个点到平面的有向距离。如果一个点的距离为正而另一个为负,则它们位于平面的相对两侧。然后,您知道哪个点在您的截锥体之外(基于您的平面法线指向的方式)。使用这种方法,通过基于有向距离的比率进行线性插值,可以更快地找到交点。例如,如果一个点的距离是 +12 而另一个是 -12,那么您知道平面将线段切成两半,并且您的 u 参数是 0.5。
希望这可以帮助。
首先从您的视图矩阵中提取平面。
然后使用您的点将向量和最小值/最大值定义为 (0, 1),然后遍历平面并将它们与线段相交,更新最小值/最大值,如果min > max
.
这是一个纯 Python 函数的示例,没有外部依赖。
def clip_segment_v3_plane_n(p1, p2, planes):
"""
- p1, p2: pair of 3d vectors defining a line segment.
- planes: a sequence of (4 floats): `(x, y, z, d)`.
Returns 2 vector triplets (the clipped segment)
or (None, None) then segment is entirely outside.
"""
dp = sub_v3v3(p2, p1)
p1_fac = 0.0
p2_fac = 1.0
for p in planes:
div = dot_v3v3(p, dp)
if div != 0.0:
t = -plane_point_side_v3(p, p1)
if div > 0.0: # clip p1 lower bounds
if t >= div:
return None, None
if t > 0.0:
fac = (t / div)
if fac > p1_fac:
p1_fac = fac
if p1_fac > p2_fac:
return None, None
elif div < 0.0: # clip p2 upper bounds
if t > 0.0:
return None, None
if t > div:
fac = (t / div)
if fac < p2_fac:
p2_fac = fac
if p1_fac > p2_fac:
return None, None
p1_clip = add_v3v3(p1, mul_v3_fl(dp, p1_fac))
p2_clip = add_v3v3(p1, mul_v3_fl(dp, p2_fac))
return p1_clip, p2_clip
# inline math library
def add_v3v3(v0, v1):
return (
v0[0] + v1[0],
v0[1] + v1[1],
v0[2] + v1[2],
)
def sub_v3v3(v0, v1):
return (
v0[0] - v1[0],
v0[1] - v1[1],
v0[2] - v1[2],
)
def dot_v3v3(v0, v1):
return (
(v0[0] * v1[0]) +
(v0[1] * v1[1]) +
(v0[2] * v1[2])
)
def mul_v3_fl(v0, f):
return (
v0[0] * f,
v0[1] * f,
v0[2] * f,
)
def plane_point_side_v3(p, v):
return dot_v3v3(p, v) + p[3]