【问题标题】:Uniformly distributed random point inside a frustum平截头体内均匀分布的随机点
【发布时间】:2012-06-16 15:08:44
【问题描述】:

我有一个 3D 场景,我想在视锥体内随机放置 X 个对象来“乱扔”它。

我尝试使用 3 个随机数:X + Y(视口 0..1),然后与相机的距离为 Z,然后投影使用相机距离。但是,这不会产生均匀分布,并且靠近相机的物体太多而远离相机的物体太少。

可以选择在立方体内生成一个随机点并过滤视锥体之外的那些点,但我正在生成大量这些点并且我担心性能。

如何以均匀分布的方式在截锥体内生成随机点?

【问题讨论】:

    标签: random 3d polygon


    【解决方案1】:

    这只是来自Amir Abiri 答案中链接中最终解决方案的格式良好的代码,因为链接中的代码具有糟糕的格式质量。

    在 java 中,因为这就是我正在使用的,并且更改了一些变量名(此外,测试通过了;它工作得很好)

    请注意,这可以通过多种方式变得更好,具体取决于应用程序(例如,正如Amir Abiri 的答案中的链接站点中提到的那样,一些变量可以计算一次并多次使用,只要相同正在使用截锥体)

    public static final double ONE_THIRD = 1d / 3, EPSILON = 0.0000001;
    
    public static double getUniformRandZInFrustum(Random random, double nearW, double nearH, double farW, double farH, double depth)
    {
        double a = (farW - nearW) * (farH - nearH) / (depth * depth);
        double b = (nearH * (farW - nearW) + nearW * (farH - nearH)) / depth;
    
        if (Math.abs(a) < EPSILON)
        {
            if (Math.abs(b) < EPSILON)
            {
                //Rectangular prism
                return (random.nextDouble(depth));
            }
    
            //Trapezoidal prism
            double c = nearW * nearH;
            double area = depth * (c + depth * 0.5 * b);
            double r = random.nextDouble(area);
            return (-c + Math.sqrt(c * c + 2 * b * r)) / b;
        }
    
        //General case
        double c = nearW * nearH;
        double area = depth * (c + depth * (0.5 * b + depth * ONE_THIRD * a));
        double r = random.nextDouble(area);
        double det = b * b - 4 * a * c;
        double part1 = b * (b * b - 6 * a * c) - 12 * a * a * r;
        double part2 = Math.sqrt(part1 * part1 - det * det * det);
        if (part1 < 0.0) part2 = -part2;
        double part3 = part1 + part2;
        if (part3 < 0.0) part3 = -Math.pow(-part3, ONE_THIRD);
        else part3 = Math.pow(part3, ONE_THIRD);
        return -(b + det / part3 + part3) / (2 * a);
    }
    

    【讨论】:

      【解决方案2】:

      在 NDC 空间中分布点,并通过反截锥体变换将它们反向投影并划分到视图空间中。

      【讨论】:

      • 很抱歉你弄丢了我...我了解剪辑空间部分和反投影,但是如果到目前为止我没有弄错,那会产生不均匀的结果吗?我不明白您所说的 w-divide into view space 是什么意思?
      • @AmirAbiri:看看典型的转换管道。首先,将视图空间坐标与投影矩阵 P 相乘:r_clip = P * r,然后,为了引入透视效果,应用 w 除以达到 NDC r_NDC.{x,y,z,w} = r_clip.{x,y,z,w} / r_clip.w。你必须走完全相反的方向。我建议看一下gluUnProject 的源代码(你可以在 Mesa3D 源代码中找到它)。
      • 所以如果我理解正确的话,我们实际上是在 {0..1, 0..1, 0..1} 中选择随机点,其中 X 和 Y 代表标准化的屏幕坐标,而Z分量是近剪辑和远剪辑之间的归一化距离,然后将其反向投影回世界坐标?
      • 如果我错了,请纠正我,但这不会在产生的截锥体内产生均匀分布?对象出现在 z=0 处的机会应该比出现在 z=h 处的机会少。
      • @AmirAbiri:确实,距离您的近剪裁平面越远的对象,点的密度越高。这正是您想要的,因为您在抱怨“靠近摄像头的物体太多”。
      【解决方案3】:

      【讨论】:

        猜你喜欢
        • 2011-07-21
        • 2020-04-04
        • 1970-01-01
        • 1970-01-01
        • 2011-08-08
        • 2021-07-20
        • 2021-12-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多