【问题标题】:How do I clip a line segment against a frustum?如何在平截头体上剪裁线段?
【发布时间】:2010-09-09 19:42:51
【问题描述】:

给定两个向量 AB 形成线段 L = A-B。 此外,给定一个视锥 F,它由其左、右、底、顶、近和远平面定义。

如何将 LF 进行剪辑?

也就是说,测试一个交叉点在 L 上的哪个交叉点出现? (请记住,如果一条线段在一个拐角处与两侧相交,则它与平截头体的交点可能更多。)

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

【问题讨论】:

  • 我是否遗漏了什么,或者您可以将 L 与所有平面相交吗?到底什么是截锥体? :)
  • 啊,我看到它有正面和背面,但它们是隐含的。
  • 我们为什么要给这个孩子做作业?
  • 它已经被标记为作业,如果你不喜欢它,请投下它。我认为没有任何理由认为是淫秽标签。

标签: math clipping


【解决方案1】:

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

  1. 将直线与所有给定平面相交
  2. 如果您有两个十字路口,您就完成了。
  3. 如果您只有一个交点,请计算前平面并相交。
  4. 如果您仍然只有一个交点,请计算背板并相交。

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

【讨论】:

  • 嗯。实际上我想要的是线段在视锥体之外。所以如果我有两个交叉点,我必须移动 A 和 B 以匹配相交边界。唉,我不知道它是如何工作的。
【解决方案2】:

除了上面所说的下士 Touchy,您还需要 know how to intersect a line segment with a plane。在该页面的描述中, u 表示您的行的参数定义中的参数。首先,使用描述的 2 种方法之一计算 u。如果 u 的值在 0.0 到 1.0 的范围内,则平面会剪裁线段上的某处。将 u 代入您的直线方程,即可得到该交点发生的点。

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

希望这会有所帮助。

【讨论】:

    【解决方案3】:

    第一个extract the planes from your view matrix

    然后使用您的点定义一个向量并将最小/最大值定义为 (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]
    

    【讨论】:

      猜你喜欢
      • 2010-10-10
      • 2021-07-17
      • 2013-10-20
      • 2021-07-02
      • 2014-03-11
      • 2015-01-31
      • 1970-01-01
      • 1970-01-01
      • 2012-08-11
      相关资源
      最近更新 更多