Saltar al contenido

¿Dibujar Esfera en OpenGL sin usar gluSphere ()?

Esta división ha sido evaluado por expertos para garantizar la exactitud de nuestro contenido.

Solución:

Una forma de hacerlo es comenzar con un sólido platónico con lados triangulares, por ejemplo, un octaedro. Luego, toma cada triángulo y divídelo recursivamente en triángulos más pequeños, así:

triángulos dibujados recursivamente

Una vez que tenga una cantidad suficiente de puntos, normalice sus vectores para que todos estén a una distancia constante del centro del sólido. Esto hace que los lados se abulten en una forma que se asemeja a una esfera, con una mayor suavidad a medida que aumenta el número de puntos.

La normalización aquí significa mover un punto para que su ángulo en relación con otro punto sea el mismo, pero la distancia entre ellos sea diferente. He aquí un ejemplo bidimensional.

ingrese la descripción de la imagen aquí

A y B están a 6 unidades de distancia. Pero supongamos que queremos encontrar un punto en la línea AB que esté a 12 unidades de distancia de A.

ingrese la descripción de la imagen aquí

Podemos decir que C es la forma normalizada de B con respecto a A, con distancia 12. Podemos obtener C con código como este:

#returns a point collinear to A and B, a given distance away from A. 
function normalize(a, b, length):
    #get the distance between a and b along the x and y axes
    dx = b.x - a.x
    dy = b.y - a.y
    #right now, sqrt(dx^2 + dy^2) = distance(a,b).
    #we want to modify them so that sqrt(dx^2 + dy^2) = the given length.
    dx = dx * length / distance(a,b)
    dy = dy * length / distance(a,b)
    point c =  new point
    c.x = a.x + dx
    c.y = a.y + dy
    return c

Si hacemos este proceso de normalización en muchos puntos, todos con respecto al mismo punto A y con la misma distancia R, entonces los puntos normalizados estarán todos en el arco de un círculo con centro A y radio R.

segmento de línea abultado

Aquí, los puntos negros comienzan en una línea y “sobresalen” en un arco.

Este proceso se puede extender a tres dimensiones, en cuyo caso se obtiene una esfera en lugar de un círculo. Simplemente agregue un componente dz a la función de normalización.

polígonos normalizados

octaedro abultado de nivel 1octaedro abultado de nivel 3

Si miras la esfera en Epcot, puedes ver esta técnica en funcionamiento. es un dodecaedro con caras abultadas para que parezca más redondo.

Explicaré con más detalle una forma popular de generar una esfera utilizando la latitud y la longitud (otra forma, icosferasya se explicó en la respuesta más popular en el momento de escribir este artículo).

Una esfera se puede expresar mediante la siguiente ecuación paramétrica:

F(tu, v) = [ cos(u)*sin(v)*r, cos(v)*r, sin(u)*sin(v)*r ]

Donde:

  • r es el radio;
  • tu es la longitud, que va de 0 a 2π; y
  • v es la latitud, que va de 0 a π.

Entonces, generar la esfera implica evaluar la función paramétrica a intervalos fijos.

Por ejemplo, para generar 16 líneas de longitud, habrá 17 líneas de cuadrícula a lo largo del tu eje, con un paso de π/8 (2π/16) (la línea 17 se envuelve).

El siguiente pseudocódigo genera una malla triangular mediante la evaluación de una función paramétrica a intervalos regulares (esto funciona para ninguna función de superficie paramétrica, no solo esferas).

En el pseudocódigo a continuación, UResolución es el número de puntos de cuadrícula a lo largo del eje U (aquí, líneas de longitud), y Resolución V es el número de puntos de cuadrícula a lo largo del eje V (aquí, líneas de latitud)

var startU=0
var startV=0
var endU=PI*2
var endV=PI
var stepU=(endU-startU)/UResolution // step size between U-points on the grid
var stepV=(endV-startV)/VResolution // step size between V-points on the grid
for(var i=0;i

El código del ejemplo se explica rápidamente. Deberías mirar la función. void drawSphere(double r, int lats, int longs):

void drawSphere(double r, int lats, int longs) 
    int i, j;
    for(i = 0; i <= lats; i++) 
        double lat0 = M_PI * (-0.5 + (double) (i - 1) / lats);
        double z0  = sin(lat0);
        double zr0 =  cos(lat0);

        double lat1 = M_PI * (-0.5 + (double) i / lats);
        double z1 = sin(lat1);
        double zr1 = cos(lat1);

        glBegin(GL_QUAD_STRIP);
        for(j = 0; j <= longs; j++) 
            double lng = 2 * M_PI * (double) (j - 1) / longs;
            double x = cos(lng);
            double y = sin(lng);

            glNormal3f(x * zr0, y * zr0, z0);
            glVertex3f(r * x * zr0, r * y * zr0, r * z0);
            glNormal3f(x * zr1, y * zr1, z1);
            glVertex3f(r * x * zr1, r * y * zr1, r * z1);
        
        glEnd();
    

Los parametros lat define cuántas líneas horizontales quieres tener en tu esfera y lon cuantas lineas verticales r es el radio de tu esfera.

Ahora hay una doble iteración sobre lat/lon y se calculan las coordenadas de los vértices, usando trigonometría simple.

Los vértices calculados ahora se envían a su GPU usando glVertex...() como un GL_QUAD_STRIPlo que significa que estás enviando cada dos vértices que forman un quad con los dos enviados anteriormente.

Todo lo que tienes que entender ahora es cómo funcionan las funciones de trigonometría, pero supongo que puedes resolverlo fácilmente.

Sección de Reseñas y Valoraciones

Recuerda algo, que tienes la capacidad de decir si diste con el resultado.

¡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 *