如何根据截锥体剪裁线段?

发布于 2024-07-05 13:07:36 字数 341 浏览 8 评论 0原文

给定两个向量AB,它们形成线段L = AB。 此外,还给出了一个视锥体F,它由其左、右、下、上、近和远平面定义。

如何将 L 剪辑到 F 上?

也就是说,测试交集,该交集发生在 L 上的什么位置? (请记住,如果一条线段在一个角处与两侧相交,那么它可以与截锥体有多个交点。)

如果可能,请提供一个代码示例(首选 C++ 或 Python)。

Given two vectors A and B which form the line segment L = A-B.
Furthermore given a view frustum F which is defined by its left, right, bottom, top, near and far planes.

How do I clip L against F?

That is, test for an intersection and where on L that intersection occurs?
(Keep in mind that a line segment can have more than one intersection with the frustum if it intersects two sides at a corner.)

If possible, provide a code example please (C++ or Python preferred).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

☆獨立☆ 2024-07-12 13:07:36

首先从视图矩阵中提取平面

然后使用您的点将向量和最小/最大定义为 (0, 1),然后迭代平面并将它们与线段相交,更新最小/最大,如果 min > 则尽早退出。 最大

这是一个纯 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]

First extract the planes from your view matrix.

Then use your points to define a vector and min/max as (0, 1), then iterate over the planes and intersect them with the segment, updating the min/max, bailing out early if the min > max.

Here's an example of a pure Python function, no external deps.

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]
呆头 2024-07-12 13:07:36

我现在不想为此编写代码,但如果我正确理解“平截头体”,以下应该可以工作。

  1. 使直线与所有给定平面相交
  2. 如果有两个交点,则完成。
  3. 如果只有一个交点,请计算前平面并相交。
  4. 如果仍然只有一个交点,请计算背平面并相交。

但我可能完全误解了。 在这种情况下,请详细说明:)

I don't want to get into writing code for this now but if I understand "frustum" correctly the following should work.

  1. Intersect the Line with all given planes
  2. If you have two intersections you're done.
  3. If you have only one intersection calculate the front plane and intersect.
  4. If you still have only one intersection calculate the back plane and intersect.

But I may have completely misunderstood. In that case please elaborate :)

听风念你 2024-07-12 13:07:36

除了上面 Touchy 下士所说的之外,您还需要知道如何线段与平面相交。 在该页面的说明中,u 代表线路参数定义中的参数。 首先,使用所描述的 2 种方法之一计算 u。 如果 u 的值在 0.0 到 1.0 的范围内,则平面会在线段上的某处剪裁该线。 将 u 代入直线方程即可得出交点发生的点。

另一种方法是找到每个点到平面的定向距离。 如果一个点的距离为正,另一个点的距离为负,则它们位于平面的相对两侧。 然后您就知道哪个点在您的视锥体之外(基于您的平面法线点的方向)。 使用这种方法,通过基于有向距离的比率进行线性插值,可以更快地找到交点。 例如,如果一个点的距离为 +12,另一个点的距离为 -12,则您知道平面将线段切成两半,并且您的 u 参数为 0.5。

希望这可以帮助。

Adding to what Corporal Touchy said above, you'll need to know how to intersect a line segment with a plane. In the description on that page, u represents the parameter in the parametric definition of your line. First, calculate u using one of the 2 methods described. If the value of u falls in the range of 0.0 to 1.0, then the plane clips the line somewhere on your segment. Plugging u back into your line equation gives you the point where that intersection occurs.

Another approach is to find the directed distance of each point to a plane. If the distance of one point is positive and the other is negative, then they lie on opposite sides of the plane. You then know which point is outside your frustum (based on which way your plane normal points). Using this approach, finding the intersection point can be done faster by doing a linear interpolation based on the ratio of the directed distances. E.g. if the distance of one point is +12 and the other is -12, you know the plane cuts the segment in half, and your u parameter is 0.5.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文