Frustuma uyan en büyük küreyi nasıl bulabilirim?


12

Perspektifte çizebileceğiniz en büyük küreyi nasıl buluyorsunuz?

Üstten bakıldığında, bu şöyle olurdu:

resim açıklamasını buraya girin

Eklendi: sağdaki frustumda, hakkında bir şeyler bildiğimizi düşünüyorum dört nokta işaretledim. Frizumun sekiz köşesinin tamamını ve yakın ve uzak uçların merkezlerini çıkarabiliriz. Bu yüzden nokta 1, 3 ve 4'ü biliyoruz. Ayrıca nokta 2'nin 4'ten 3'e 3 ile aynı mesafe olduğunu biliyoruz. Böylece, 1'den 4'e kadar olan en yakın noktayı, merkez? Ama asıl matematik ve kod benden kaçıyor.

Mümkün olduğunca büyük modeller (yaklaşık olarak küresel ve miniball sınırlayıcı bir küreye sahip olduğum) çizmek istiyorum.

Güncelleme: Bobobobo ve Nathan Reed tarafından önerilen iki düzlemli incircle-on yaklaşımını uygulamaya çalıştım :

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;
}

Kanatlıyorum itiraf ediyorum; 2D kodu 3 boyuta genişleterek uyarlamaya çalışıyorum . İçkileri doğru hesaplamaz; kürenin merkez noktası her seferinde kamera ile sol üst arasındaki çizgi üzerinde ve çok büyük (veya çok yakın) gibi görünüyor. Kodumda bariz hatalar var mı? Yaklaşım düzeltilmişse işe yarar mı?


Kürenin görüntüdeki gibi tamamen uzak düzlemin yan tarafında olması gerekir mi?
Mikael Högström

@ MikaelHögström Mümkün olduğunca büyük olabilmeleri için olabileceğini düşünüyor muyum?
Will

Hmm Sanırım amacınıza bağlı ... Eğer uzak düzlemin yarısından daha fazla bir küre çizerseniz, bu daha büyük olurdu ama belki de amacınıza aykırıdır?
Mikael Högström

@ MikaelHögström aha Sorunuzu anlıyorum; Evet bütün modelin çizilmesini istiyorum.
Will

Yanıtlar:


12

Çiziminizin öne sürdüğü için, frustumunuzun simetrik olduğunu varsayacağım. Üç kısıtlama vardır (frustum'unuz 2D ise iki):

A. küre yakın ve uzak uçaklar arasındaki mesafeden daha büyük olamaz

Eğer Dyakın-uzak mesafe, birinci kısıt basitçe:

R  D / 2

B. küre yan düzlemlerden daha geniş olamaz

Şimdi diğer kısıtlama için, diyelim ki α, frustumun yarı açısı ve Lbu çizimde gösterildiği gibi uzak düzlemin yarı genişliği:

frustum

İlk formül üçgendeki trigonometri ile verilir. İkincisi, bir üçgenin açılarının toplamından gelir. Bu bize ikinci kısıtı verir:

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

Frustum'unuz 3D ise, yeni Lveα değerlerle .

Son sonuç

RAradığınız değerdirmin üç aut.

Parametreleri alma

Görünüşte veya dünya uzayında frustum'u kaldırabiliyorsanız, Pnoktaların yakın düzlemden ve Qnoktaların uzak düzlemden olduğu aşağıdaki şekilde L, D ve α'yı hesaplayabilirsiniz :

formula2

Oklar vektörler anlamına gelir. nokta ürünü ve || bir vektörün uzunluğunu belirtir. Değiştir Q2ile Q3ve P2ile P3dikey boyutta L ve a olsun.


Frustum'dan (yaklaşmak ve uzaklaşmak için bakış açısı noktalarını çıkartarak hesaplanır), görüş alanını nasıl belirliyorsunuz? Ve 3D'de üç değil sadece iki seçenek var, değil mi? Koduna senin algoritma koymak denemelerim hep bana çok büyük R. vermek
Will

@ Umarım yardımcı olacak formüllerle ikinci bir çizim ekleyeceğim.
sam hocevar

2

2D'de: frustum'u bir üçgen (2D) olarak düşünün

resim açıklamasını buraya girin

Sonra üçgenin incircle'ını bulmak istersiniz .

3D bir problem olarak, insphere'i bulmanız gerekir kare tabanlı bir piramidin .

Formüle sahip olsaydım buraya basardım, ama ne yazık ki, formülü bilmiyorum.


2
Muhtemelen en azından "standart" frusta (kesilmemiş veya herhangi bir şey) için daha küçük FOV'a sahip olan dikey veya yatay frustumun incircle'ını bulmak yeterlidir.
Nathan Reed

1

Mümkün olan En Büyük Küre, merkezdeki uzak düzleme (burada görünüm hayal kırıklığı terimlerini kullanarak) dokunmalıdır. Hangi FoV açısının daha küçük olduğuna bağlı olarak üst / alt veya sol / sağ düzlemlere de dokunacaktır. Bu varsayımlar için gerçek bir matematiksel kanıtımın olmadığını söylemeliyim, ama doğru olmalılar. Belki birinin bunu nasıl kanıtlayacağı konusunda bir fikri vardır.

Küre merkez noktası ve yarıçapı ile tanımlanabilir. Cx ve Cy, uzak düzlemin merkezi ile aynıdır.

Cz ve yarıçap, yukarıda listelenen varsayımlara dayalı bir denklem sistemi çözülerek elde edilebilir.

T, normalize edilmiş normal vektör olarak t1, t2 ve t3 ve başlangıç ​​noktasına olan mesafe t4 olan alt / üst düzlem veya sol / sağ düzlemden (yukarıya bakın) biridir. f, uzak düzlemin merkezidir.

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)

r daha sonra buna cz eklenerek hesaplanır: -fz + cz = r

Kullandığınız Projeksiyon Matrisinden tüm düzlemleri elde edebilirsiniz. (Bu durumda ViewProjection değil)

daha sonra küreyi doğru boşluğa hareket ettirmelisiniz: C '= ters (Görünüm) * C


1

Benzer bir şey yapmaya çalışıyorum ve benim durumumda, kürenin frustum'un sınırlarının dışında olmadığı sürece hız doğruluktan daha önemlidir.

Linesegs (veya 3d olarak yüzler) arasındaki en kısa mesafeyi hesaplarsanız, bulunan en kısa mesafe, tam olarak frustumun içinde bulunan bir kesici / insphere çapı olarak kullanılabilir. İnsircle / insphere'in kökeni basitçe tüm köşelerin ortalaması olabilir (toplam ve böl). Oldukça hızlı olurdu ve her türlü dışbükey polihedra için de işe yarar.

Tek dezavantajı, daire veya kürenin mutlaka mümkün olan en büyük kesici veya insphere olmayacağıdır. Çok fazla hacme ve çok kısa bir kenara sahip bir frustum için, daire / küre mümkün olduğunca çok frustum uzayını paylaşır.

Diğer bir fikir

Bir 3D görünüm frustumunun insphereini istiyorsanız ve bu frustumu oluşturmak için kullanılan perspektif matrisiniz varsa, o zaman bu matrisi bir birim küpün insphereinde kullanabilirsiniz ve bu frustum için mükemmel bir insphere olmalıdır. (Bir küpün iç yüzeyinin çapı küpün kenarlarından birinin uzunluğudur, merkez küpün köşelerinin ortalaması olan küpün ortasıdır)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.