Saltar al contenido

Asignar una esfera a un cubo

Miranda, miembro de este equipo de trabajo, nos ha hecho el favor de crear esta reseña porque domina perfectamente dicho tema.

Solución:

Quiero darle crédito a gmatt por esto porque ha hecho mucho del trabajo. La única diferencia en nuestras respuestas es la ecuación de x.

Para hacer el mapeo inverso de esfera a cubo, primero determine la cara del cubo a la que se proyecta el punto de esfera. Este paso es simple: simplemente encuentre el componente del vector de esfera con la mayor longitud así:

// map the given unit sphere position to a unit cube position
void cubizePoint(Vector3& position) 
    double x,y,z;
    x = position.x;
    y = position.y;
    z = position.z;

    double fx, fy, fz;
    fx = fabsf(x);
    fy = fabsf(y);
    fz = fabsf(z);

    if (fy >= fx && fy >= fz) 
        if (y > 0) 
            // top face
            position.y = 1.0;
        
        else 
            // bottom face
            position.y = -1.0;
        
    
    else if (fx >= fy && fx >= fz) 
        if (x > 0) 
            // right face
            position.x = 1.0;
        
        else 
            // left face
            position.x = -1.0;
        
    
    else 
        if (z > 0) 
            // front face
            position.z = 1.0;
        
        else 
            // back face
            position.z = -1.0;
        
    

Para cada cara: tome los componentes restantes del vector cúbico indicados como syt y resuélvalos usando estas ecuaciones, que se basan en los componentes restantes del vector esfera indicados como ayb:

s = sqrt(-sqrt((2 a^2-2 b^2-3)^2-24 a^2)+2 a^2-2 b^2+3)/sqrt(2)
t = sqrt(-sqrt((2 a^2-2 b^2-3)^2-24 a^2)-2 a^2+2 b^2+3)/sqrt(2)

Debería ver que la raíz cuadrada interna se usa en ambas ecuaciones, así que solo haga esa parte una vez.

Aquí está la función final con las ecuaciones incluidas y verifica 0.0 y -0.0 y el código para establecer correctamente el signo del componente del cubo; debe ser igual al signo del componente de la esfera.

void cubizePoint2(Vector3& position)
{
    double x,y,z;
    x = position.x;
    y = position.y;
    z = position.z;

    double fx, fy, fz;
    fx = fabsf(x);
    fy = fabsf(y);
    fz = fabsf(z);

    const double inverseSqrt2 = 0.70710676908493042;

    if (fy >= fx && fy >= fz) 
    else if (fx >= fy && fx >= fz) 
    else  y == -0.0) 
            position.y = 0.0;
        
        else 
            position.y = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
        

        if(position.x > 1.0) position.x = 1.0;
        if(position.y > 1.0) position.y = 1.0;

        if(x < 0) position.x = -position.x;
        if(y < 0) position.y = -position.y;

        if (z > 0) 
            // front face
            position.z = 1.0;
        
        else 
            // back face
            position.z = -1.0;
        
    

Por lo tanto, esta solución no es tan bonita como el mapeo de cubo a esfera, ¡pero hace el trabajo!

Se agradece cualquier sugerencia para mejorar la eficiencia o la capacidad de lectura del código anterior.

— editar — Debo mencionar que he probado esto y hasta ahora en mis pruebas el código parece correcto y los resultados son precisos al menos hasta el séptimo lugar decimal. Y eso fue de cuando estaba usando flotadores, probablemente ahora sea más preciso con dobles.

— editar — Aquí hay una versión optimizada del sombreador de fragmentos glsl de Daniel para mostrar que no tiene por qué ser una función tan aterradora. ¡Daniel usa esto para filtrar el muestreo en mapas de cubos! ¡Gran idea!

const float isqrt2 = 0.70710676908493042;

vec3 cubify(const in vec3 s)

float xx2 = s.x * s.x * 2.0;
float yy2 = s.y * s.y * 2.0;

vec2 v = vec2(xx2 – yy2, yy2 – xx2);

float ii = v.y – 3.0;
ii *= ii;

float isqrt = -sqrt(ii – 12.0 * xx2) + 3.0;

v = sqrt(v + isqrt);
v *= isqrt2;

return sign(s) * vec3(v, 1.0);


vec3 sphere2cube(const in vec3 sphere)

vec3 f = abs(sphere);

bool a = f.y >= f.x && f.y >= f.z;
bool b = f.x >= f.z;

return a ? cubify(sphere.xzy).xzy : b ? cubify(sphere.yzx).zxy : cubify(sphere);

Después de un poco de reorganización, puede obtener los formularios “agradables”

(1)   1/2 z^2 = (alpha) / ( y^2 - x^2) + 1
(2)   1/2 y^2 = (beta)  / ( z^2 - x^2) + 1
(3)   1/2 x^2 = (gamma) / ( y^2 - z^2) + 1

dónde alpha = sx^2-sy^2 , beta = sx^2 - sz^2 y gamma = sz^2 - sy^2. Verifíquelo usted mismo.

Ahora no tengo la motivación ni el tiempo, pero a partir de este punto es bastante sencillo de resolver:

  1. Sustituya (1) en (2). Reorganice (2) hasta obtener una ecuación polinomial (raíz) de la forma

    (4)    a(x) * y^4  + b(x) * y^2 + c(x) = 0
    

    esto se puede resolver usando la fórmula cuadrática para y^2. Tenga en cuenta que a(x),b(x),c(x) son algunas funciones de x. La fórmula cuadrática produce 2 raíces para (4) que tendrás que tener en cuenta.

  2. Usando (1), (2), (4) calcule una expresión para z^2 en términos de solo x^2.

  3. Usando (3) escriba una ecuación de raíz polinomial de la forma:

    (5)    a * x^4  + b * x^2 + c = 0
    

    dónde a,b,c no son funciones sino constantes. Resuelve esto usando la fórmula cuadrática. En total, tendrá 2 * 2 = 4 posibles soluciones para x^2,y^2,z^2 par, lo que significa que tendrá 4 * 2 = 8 soluciones totales para posibles x,y,z pares que satisfacen estas ecuaciones. Consultar condiciones en cada x,y,z emparejar y (con suerte) eliminar todos menos uno (de lo contrario, no existe un mapeo inverso).

Buena suerte.

PD. Bien puede ser que el mapeo inverso no exista, piensa en la geometría: la esfera tiene superficie 4*pi*r^2 mientras que el cubo tiene un área de superficie 6*d^2=6*(2r)^2=24r^2 así que intuitivamente tienes muchos más puntos en el cubo que se asignan a la esfera. Esto significa un mapeo de muchos a uno, y dicho mapeo no es inyectivo y por lo tanto no es biyectivo (es decir, el mapeo no tiene inverso). Lo siento, pero creo que no tienes suerte.

—– editar ————–

si sigue los consejos de MO, establezca z=1 significa que estás mirando el cuadrado sólido en el plano z=1.

Utilice sus dos primeras ecuaciones para resolver para x, y, wolfram alfa da el resultado:


x = (sqrt(6) s^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(6) t^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(3/2) sqrt((2 s^2-2 t^2-3)^2-24 t^2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)+3 sqrt(3/2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3))/(6 s)

y


y = sqrt(-sqrt((2 s^2-2 t^2-3)^2-24 t^2)-2 s^2+2 t^2+3)/sqrt(2)

donde arriba yo uso s=sx y t=sy, y usaré u=sz. Entonces puedes usar la tercera ecuación que tienes para u=sz. Es decir, digamos que desea mapear la parte superior de la esfera al cubo. Entonces para cualquier 0 <= s,t <= 1 (dónde s,t están en el marco de coordenadas de la esfera) luego la tupla (s,t,u) mapas a (x,y,1) (aquí x,y están en el marco de coordenadas de los cubos.) Lo único que queda es que averigües qué u es. Puedes resolver esto usando s,t para resolver x,y luego usando x,y para resolver u.

Tenga en cuenta que esto solo mapeará la parte superior del cubo a solamente el plano superior del cubo z=1. Tendrá que hacer esto para los 6 lados (x=1, y=1, z=0 ... etc). Sugiero usar wolfram alfa para resolver las ecuaciones resultantes que obtienes para cada sub-caso, porque serán tan feos o más feos como los anteriores.

Si te gusta el tema, tienes la libertad de dejar una división acerca de qué te ha gustado de este enunciado.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *