Come posso trovare la sfera più grande che si adatta all'interno di un frustum?


12

Come trovi la sfera più grande che puoi disegnare in prospettiva?

Visto dall'alto, sarebbe questo:

inserisci qui la descrizione dell'immagine

Aggiunto: sul frustum a destra, ho segnato quattro punti di cui sappiamo qualcosa. Possiamo non proiettare tutti gli otto angoli del frusum e i centri delle estremità vicine e lontane. Quindi conosciamo i punti 1, 3 e 4. Sappiamo anche che il punto 2 è la stessa distanza da 3 come 4 è da 3. Quindi possiamo quindi calcolare il punto più vicino sulla linea da 1 a 4 al punto 2 per ottenere il centro? Ma la matematica e il codice attuali mi sfuggono.

Voglio disegnare modelli (che sono approssimativamente sferici e per i quali ho una sfera di delimitazione miniball) il più grande possibile.

Aggiornamento: ho provato ad implementare l'approccio incircle su due piani come suggerito da bobobobo e 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;
}

Ammetto che lo sto alando; Sto cercando di adattare il codice 2D estendendolo in 3 dimensioni. Non calcola correttamente l'insfera; il punto centrale della sfera sembra essere ogni volta sulla linea tra la telecamera e l'angolo in alto a sinistra, ed è troppo grande (o troppo vicino). Ci sono errori evidenti nel mio codice? L'approccio, se risolto, funziona?


La sfera deve essere interamente dall'altra parte del piano lontano come nell'immagine?
Mikael Högström,

@ MikaelHögström Immagino che sarebbero stati, per essere il più grande possibile?
Sarà il

Hmm immagino che dipenda dal tuo scopo ... Se disegni una sfera con la metà oltre il piano lontano, allora sarebbe più grande ma forse va contro il tuo scopo?
Mikael Högström,

@ MikaelHögström aha capisco la tua domanda; Sì, desidero disegnare l'intero modello, senza che un piano lontano lo attraversi.
Sarà il

Risposte:


12

Presumo che il tuo frustum sia simmetrico, poiché il tuo disegno sembra suggerirlo. Esistono tre vincoli (due se il tuo frustum è in 2D):

A. la sfera non può essere più grande della distanza tra i piani vicino e lontano

Se Dè la distanza quasi lontana, il primo vincolo è semplicemente:

R  D / 2

B. la sfera non può allargarsi più dei piani laterali

Ora per l'altro vincolo, diciamo che αè il mezzo angolo del tronco ed Lè la mezza larghezza del piano lontano, come mostrato in questo disegno:

tronco

La prima formula è data dalla trigonometria nel triangolo. Il secondo deriva dalla somma degli angoli di un triangolo. Il che ci dà il secondo vincolo:

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

Se il tuo frustum è 3D, avrai un terzo vincolo con nuovi Le αvalori.

Risultato finale

Il Rvalore che stai cercando è il mindei tre limiti.

Come ottenere i parametri

Se riesci a proiettare il frustum in vista o nello spazio mondiale, puoi calcolare L, D e α nel modo seguente, dove i Ppunti provengono dal piano vicino e i Qpunti provengono dal piano lontano:

formula2

Le frecce indicano vettori, "." è il prodotto punto e || indica la lunghezza di un vettore. Sostituire Q2con Q3e P2con P3per ottenere L e α nella dimensione verticale.


Come, dal frustum (calcolato non proiettando i punti di vista per avvicinarsi e allontanarsi), si determina il campo visivo? E in 3D ci sono solo due scelte, non tre, giusto? I miei tentativi di inserire il tuo algoritmo in codice mi danno sempre un grande R.
Will

@Will Ho aggiunto un secondo disegno con formule che si spera possano aiutare.
Sam Hocevar,

2

In 2D: considera il frustum come un triangolo (2D)

inserisci qui la descrizione dell'immagine

Quindi vuoi trovare il cerchio del triangolo.

Come problema 3D, devi trovare l' atmosfera di una piramide a base quadrata.

Se avessi la formula la stamperei qui, ma purtroppo non conosco la formula.


2
Probabilmente è sufficiente trovare l'incertezza della frustum verticale o orizzontale in 2D, a seconda di quale sia il FOV più piccolo, almeno per la frusta "standard" (non tranciata o altro).
Nathan Reed,

1

La sfera più grande possibile dovrebbe toccare il piano più lontano (usando i termini qui per frustrare la vista) proprio al centro. Toccerebbe anche i piani superiore / inferiore o sinistro / destro, a seconda dell'angolo FoV più piccolo. Devo dire che non ho una prova matematica effettiva per questi presupposti, ma dovrebbero avere ragione. Forse qualcuno ha un'idea su come provare questo.

Una Sfera può essere definita dal suo punto centrale e da un raggio. Cx e Cy sono gli stessi del centro del farplane.

Cz e il raggio possono essere ottenuti risolvendo un sistema di equazioni basato sulle ipotesi sopra elencate.

T è uno dei piani inferiore / superiore o sinistro / destro (vedi sopra) con t1, t2 e t3 come vettore normale normalizzato e t4 come distanza dall'origine. f è il centro del farplane.

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 viene quindi calcolato inserendo cz in questo: -fz + cz = r

È possibile ottenere tutti gli aerei dalla matrice di proiezione che si sta utilizzando. (Non ViewProjection in questo caso)

successivamente devi spostare la sfera nello spazio giusto: C '= inverso (Visualizza) * C


1

Sto tentando di fare qualcosa di simile, e nel mio caso, la velocità è più cruciale della precisione fintanto che la sfera non esiste al di fuori dei limiti del frustum.

Se si calcola la distanza più breve tra le lineegs (o le facce in 3d), la distanza più breve trovata potrebbe essere utilizzata come diametro di un cerchio / atmosfera che si trova completamente all'interno del tronco. L'origine dell'incircle / insfera potrebbe semplicemente la media di tutti i vertici (somma e divisione). Sarebbe abbastanza veloce e funzionerebbe anche per tutti i tipi di poliedri convessi.

L'unico inconveniente è che il cerchio o la sfera non saranno necessariamente il più grande cerchio o atmosfera possibile. Per un frustum con molto volume e un bordo molto corto, il cerchio / sfera condividerebbe molto meno spazio del frustum del possibile.

Un'altra idea

Se vuoi l'atmosfera di un frustum di vista 3D e hai la matrice prospettica usata per costruire questo frustum, allora potresti semplicemente usare quella matrice nell'atmosfera di un cubo unitario, e quella dovrebbe essere una perfetta atmosfera per il frustum. (Il diametro dell'insfera di un cubo è la lunghezza di uno dei bordi del cubo, il centro è il centro del cubo che è la media dei vertici del cubo)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.