0

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

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

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

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

4

3 回答 3

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);
}
于 2021-08-01T19:41:30.607 回答
0

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

于 2012-06-16T15:11:28.063 回答
0

我在一个旧论坛帖子中找到了 gamedev.net 上的解决方案:

http://www.gamedev.net/topic/254550-geometryrandomnessuniform-filling/page_p_2539021_hl_+random%20+frustum#entry2539021 _ _ _ _

于 2012-06-17T01:25:12.247 回答