¿Cómo puedo encontrar la esfera más grande que cabe dentro de un tronco?

12

¿Cómo encuentras la esfera más grande que puedes dibujar en perspectiva?

Visto desde arriba, sería esto:

ingrese la descripción de la imagen aquí

Agregado: en el centro de la derecha, he marcado cuatro puntos, creo que sabemos algo. Podemos desproyectar las ocho esquinas del frusum y los centros de los extremos cercano y lejano. Entonces sabemos los puntos 1, 3 y 4. También sabemos que el punto 2 es la misma distancia de 3 que 4 es de 3. Entonces podemos calcular el punto más cercano en la línea 1 a 4 al punto 2 para obtener el ¿centrar? Pero las matemáticas y el código real se me escapan.

Quiero dibujar modelos (que son aproximadamente esféricos y para los que tengo una esfera delimitadora de miniball) lo más grandes posible.

Actualización: He intentado implementar el enfoque de incircle-on-two-planes como lo sugieren bobobobo y 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;
}

Admito que estoy volando; Estoy tratando de adaptar el código 2D extendiéndolo en 3 dimensiones. No calcula la insfera correctamente; El punto central de la esfera parece estar en la línea entre la cámara y la esquina superior izquierda cada vez, y es demasiado grande (o demasiado cerca). ¿Hay algún error obvio en mi código? ¿El enfoque, si es fijo, funciona?

Será
fuente
¿La esfera tiene que estar completamente en el lado opuesto del plano lejano como en la imagen?
Mikael Högström
@ MikaelHögström Me imagino que lo habrían sido, para ser lo más grande posible.
Será el
Hmm, supongo que depende de tu propósito ... Si dibujas una esfera con la mitad más allá del plano lejano, entonces eso sería más grande, pero ¿tal vez eso va en contra de tu propósito?
Mikael Högström
@ MikaelHögström aha Entiendo tu pregunta; sí, quiero dibujar todo el modelo, sin que el plano lejano lo recorte.
Será el

Respuestas:

12

Asumiré que su frustum es simétrico, ya que su dibujo parece sugerirlo. Hay tres restricciones (dos si su tronco es 2D):

A. la esfera no puede ser mayor que la distancia entre los planos cercano y lejano

Si Des la distancia casi lejana, la primera restricción es simplemente:

R  D / 2

B. la esfera no puede ensancharse más que los planos laterales

Ahora para la otra restricción, digamos que αes el medio ángulo del tronco y Les el ancho medio del plano lejano, como se muestra en este dibujo:

tronco

La primera fórmula está dada por trigonometría en el triángulo. El segundo proviene de la suma de los ángulos de un triángulo. Lo que nos da la segunda restricción:

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

Si su frustum es 3D, tendrá una tercera restricción con nuevos Ly αvalores.

Resultado final

El Rvalor que está buscando es el minde los tres límites.

Cómo obtener los parámetros

Si puede desproyectar el tronco de visión o el espacio mundial, puede calcular L, D y α de la siguiente manera, donde los Ppuntos son del plano cercano y los Qpuntos son del plano lejano:

formula2

Las flechas significan vectores, "." es el producto escalar y || indica la longitud de un vector. Reemplace Q2con Q3y P2con P3para obtener L y α en la dimensión vertical.

sam hocevar
fuente
¿Cómo, a partir del frustum (calculado al no proyectar los puntos de vista para acercarse y alejarse), determina el campo de visión? Y en 3D solo hay dos opciones, no tres, ¿verdad? Mis intentos de poner su algoritmo en código siempre me dan una gran R.
Será el
@ ¿Agregué un segundo dibujo con fórmulas que con suerte ayudarán?
sam hocevar
2

En 2D: considere el tronco como un triángulo (2D)

ingrese la descripción de la imagen aquí

Luego quieres encontrar el círculo del triángulo.

Como un problema 3D, necesitas encontrar la esfera de una pirámide de base cuadrada.

Si tuviera la fórmula, la imprimiría aquí, pero, por desgracia, no sé la fórmula.

bobobobo
fuente
2
Probablemente sea suficiente encontrar el círculo del tronco vertical u horizontal en 2D, lo que tenga el campo de visión más pequeño, al menos para el frusta "estándar" (no cortado ni nada).
Nathan Reed
1

La Esfera más grande posible debería tocar el plano lejano (usando los términos para ver frustrums aquí) justo en el centro. También tocaría los planos superior / inferior o izquierdo / derecho, según el ángulo de FoV que sea más pequeño. Tengo que decir que no tengo una prueba matemática real para esos supuestos, pero deberían estar en lo cierto. Tal vez alguien tenga una idea sobre cómo probar esto.

Una esfera se puede definir por su punto central y un radio. Cx y Cy es lo mismo que el centro del plano lejano.

Cz y el radio pueden obtenerse resolviendo un sistema de ecuaciones basado en los supuestos enumerados anteriormente.

T es uno de los planos inferior / superior o izquierdo / derecho (ver arriba) con t1, t2 y t3 como vector normal normalizado y t4 como distancia desde el origen. f es el centro del plano lejano.

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 entonces se calcula insertando cz en esto: -fz + cz = r

Puede obtener todos los planos de la Matriz de proyección que está utilizando. (No ViewProjection en este caso)

luego debe mover la esfera al espacio correcto: C '= inverso (Ver) * C

Luis W
fuente
1

Estoy tratando de hacer algo similar, y en mi caso, la velocidad es más crucial que la precisión, siempre y cuando la esfera no exista fuera de los límites del tronco.

Si calcula la distancia más corta entre linesegs (o caras en 3d), la distancia más corta encontrada podría usarse como el diámetro de un círculo / insfera que se encuentra completamente dentro del tronco. El origen del incircle / insphere podría simplemente el promedio de todos los vértices (suma y división). Sería bastante rápido y también funcionaría para todo tipo de poliedros convexos.

El único inconveniente es que el círculo o la esfera no serán necesariamente el mayor círculo o insfera posible. Para un tronco con mucho volumen y un borde muy corto, el círculo / esfera compartiría mucho menos espacio del tronco que sea posible.

Otra idea

Si desea la insfera de un frustum de vista 3D y tiene la matriz de perspectiva utilizada para construir este frustum, entonces simplemente podría usar esa matriz en la insfera de un cubo unitario, y esa debería ser una insfera perfecta para el frustum. (El diámetro de la esfera de un cubo es la longitud de uno de los bordes del cubo, el centro es el centro del cubo, que es el promedio de los vértices del cubo)

zeroth
fuente