我有一个 3D 场景,我想在视锥体内随机放置 X 个对象来“乱扔”它。
我尝试使用 3 个随机数:X + Y(视口 0..1),然后是与相机的Z距离,然后使用相机距离进行投影。但是,这不会产生均匀分布,并且靠近相机的物体太多而远离相机的物体太少。
可以选择在立方体内生成一个随机点并过滤视锥体之外的那些点,但我正在生成这些点,我担心性能。
如何以均匀分布的方式在截锥体内生成随机点?
这只是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);
}
在 NDC 空间中分布点,并通过反截锥体变换将它们反向投影,然后将它们划分到视图空间中。
我在一个旧论坛帖子中找到了 gamedev.net 上的解决方案: