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