我如何找到适合于平截头体的最大球体?


12

您如何找到可以透视的最大球体?

从顶部看,是这样的:

在此处输入图片说明

补充:在右边的视锥台上,我已经指出了四点,我认为我们对此有所了解。我们可以投影出截头圆锥体的所有八个角以及近端和远端的中心。因此我们知道点1、3和4。我们也知道点2与3之间的距离与4与点3之间的距离相同。因此,我们可以计算线1到4到点2的最近点,以获得中央?但是实际的数学和代码使我无所适从。

我想绘制尽可能大的模型(大约是球形的,我有一个微型球的边界球)。

更新:我已经尝试按照 bobobobo和Nathan Reed的建议实施“在两个平面上作圆”方法:

function getFrustumsInsphere(viewport,invMvpMatrix) {
    var midX = viewport[0]+viewport[2]/2,
        midY = viewport[1]+viewport[3]/2,
        centre = unproject(midX,midY,null,null,viewport,invMvpMatrix),
        incircle = function(a,b) {
            var c = ray_ray_closest_point_3(a,b);
            a = a[1]; // far clip plane
            b = b[1]; // far clip plane
            c = c[1]; // camera
            var A = vec3_length(vec3_sub(b,c)),
                B = vec3_length(vec3_sub(a,c)),
                C = vec3_length(vec3_sub(a,b)),
                P = 1/(A+B+C),
                x = ((A*a[0])+(B*a[1])+(C*a[2]))*P,
                y = ((A*b[0])+(B*b[1])+(C*b[2]))*P,
                z = ((A*c[0])+(B*c[1])+(C*c[2]))*P;
            c = [x,y,z]; // now the centre of the incircle
            c.push(vec3_length(vec3_sub(centre[1],c))); // add its radius
            return c;
        },
        left = unproject(viewport[0],midY,null,null,viewport,invMvpMatrix),
        right = unproject(viewport[2],midY,null,null,viewport,invMvpMatrix),
        horiz = incircle(left,right),
        top = unproject(midX,viewport[1],null,null,viewport,invMvpMatrix),
        bottom = unproject(midX,viewport[3],null,null,viewport,invMvpMatrix),
        vert = incircle(top,bottom);
    return horiz[3]<vert[3]? horiz: vert;
}

我承认我在飞翔。我正在尝试通过将二维代码扩展到3维来适应它。它无法正确计算非球面度;球的中心点似乎每次都在相机和左上角之间的线上,并且太大(或太靠近)。我的代码中是否有任何明显的错误?该方法(如果固定)是否有效?


如图所示,球体是否必须完全位于远平面的上侧?
的MikaelHögström

@MikaelHögström我想他们会做到的,以便变得更大?
2013年

嗯,我想这取决于您的目的...如果您绘制的球体超出了远平面的一半,那会更大,但也许与您的目的背道而驰?
MikaelHögström'13年

@MikaelHögströmaha我明白您的问题;是的,我要绘制整个模型,没有远平面穿过它。

Answers:


12

我认为您的视锥是对称的,因为您的图纸似乎暗示了这一点。存在三个约束(如果您的视锥为2D,则有两个约束):

A.球体不能大于近平面和远平面之间的距离

如果D是近距离,则第一个约束条件就是:

R  D / 2

B.球体的宽度不能超过侧面

现在,对于另一个约束,假设α是平截头体L的半角和远平面的半角,如下图所示:

视锥

第一个公式由三角形中的三角函数给出。第二个来自三角形的角度之和。这给了我们第二个约束:

R  L tan((π - 2α) / 4)

如果您的平截头体是3D,则将具有new Lαvalues 的第三个约束。

最后结果

R您正在寻找的值是min三个界限中的一个。

如何获取参数

如果可以在视域或世界空间中取消平截头体的投影,则可以通过以下方式计算L,D和α,其中P点来自近平面,而Q点来自远平面:

公式2

箭头表示矢量“。” 是点积,|| 指示向量的长度。更换Q2Q3P2P3获得L和α在垂直方向上。


如何从平截头体(通过将视口点未投影到近处和远处进行计算)确定视场?在3D中只有两个选择,而不是三个,对吗?我尝试把你的算法转换成代码总是给我非常大的R.
威尔

@Will我将添加第二个带有公式的图形,希望会对您有所帮助。
sam hocevar

2

在2D模式下:将视锥视为一个三角形(2D)

在此处输入图片说明

然后,您想找到三角形的

作为3D问题,您需要找到基于正方形的金字塔的非球面

如果我有公式,可以在这里打印,但是a,我不知道该公式。


2
至少对于“标准”平截头体(未剪切或任何东西),在2D中找到垂直或水平的平截头体的内圆(以FOV较小者为准)可能就足够了。
内森·里德

1

可能的最大球面应该在中心处接触远平面(使用此处的视锥关系术语)。它还会触摸上/下平面或左/右平面,具体取决于哪个FoV角度较小。我必须说,我没有这些假设的实际数学证明,但它们应该是正确的。也许有人对如何证明这一点有想法。

球体可以通过其中心点和半径来定义。Cx和Cy与远端平面的中心相同。

Cz和半径可以通过根据上面列出的假设求解方程组来获得。

T是底/顶平面或左/右平面之一(请参见上文),其中t1,t2和t3为归一化法向矢量,t4为距原点的距离。f是远平面的中心。

t1 * cx + t2 * cy + t3 * cz-t4 = r

-fz + cz = r

t1 * cx + t2 * cy + t3 * cz-t4 = -fz + cz

t1 * cx + t2 * cy + fz-t2 = + cz-t3 * cz

t1 * cx + t2 * cy-fz-t2 = cz *(1-t3)

cz =(t1 * cx + t2 * cy-fz-t2)/(1-t3)

然后通过在其中插入cz来计算r:-fz + cz = r

您可以使用从投影矩阵中获取所有平面。(在这种情况下,不是ViewProjection)

之后,您必须将球体移动到正确的空间:C'=逆(视图)* C


1

我正在尝试做类似的事情,就我而言,只要球体不存在于任何平截头体范围之内,速度就比精度更为关键。

如果计算线段(或3d中的面)之间的最短距离,则找到的最短距离可用作完全位于视锥内部的圆/非球面的直径。圆/非球面的原点可以是所有顶点的平均值(总和与除)。这将非常快,并且也适用于所有类型的凸多面体。

唯一的缺点是,圆形或球形不一定是最大的圆形或非球形。对于具有大量体积和一个非常短的边缘的平截头体,圆/球形将共享尽可能少的平截头体空间。

另一个想法

如果需要3D视图视锥的非球面,并且具有用于构造此视锥的透视矩阵,则可以简单地在单位立方体的非球面上使用该矩阵,并且该矩阵应该是视锥的理想非球面。(一个立方体的非球面直径是一个立方体的边缘之一的长度,中心是该立方体的中间,是立方体顶点的平均值)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.