Dessiner une sphère dans OpenGL sans utiliser gluSphere ()?

Y a-t-il des tutoriels qui expliquent comment je peux dessiner une sphère dans OpenGL sans avoir à utiliser gluSphere()?

Beaucoup de tutoriels 3D pour OpenGL ne sont que sur des cubes. J'ai cherché mais la plupart des solutions pour dessiner une sphère doivent utiliser gluSphere(). Il y a aussi un site qui a le code pour dessiner une sphère à ce site mais il n'explique pas les mathématiques derrière le dessin de la sphère. J'ai aussi d'autres versions de la façon de dessiner la sphère en polygone au lieu de quads en cela lien. Mais encore une fois, je ne comprends pas comment les sphères sont dessinées avec le code. Je veux être capable de visualiser afin que je puisse modifier la sphère si j'en ai besoin.

74
demandé sur user1118321 2011-10-07 16:20:55

8 réponses

Une façon de le faire est de commencer par un solide platonique avec des côtés triangulaires-un octaèdre , par exemple. Ensuite, prenez chaque triangle et divisez-le récursivement en triangles plus petits, comme ceci:

triangles dessinés récursivement

Une fois que vous avez une quantité suffisante de points, vous normalisez leurs vecteurs afin qu'ils soient tous à une distance constante du centre du solide. Cela provoque les côtés à bomber dans une forme qui ressemble à une sphère, avec une douceur croissante que vous augmentez le nombre de points.

Normalisation ici signifie déplacer un point de sorte que son angle par rapport à un autre point est le même, mais la distance entre eux est différente. Voici deux dimensions, par exemple.

entrez la description de l'image ici

A et B sont séparés de 6 unités. Mais supposons que nous voulons trouver un point sur la ligne AB qui est à 12 unités de A.

entrez la description de l'image ici

On peut dire que C est la forme normalisée de B par rapport à A, avec la distance 12. Nous pouvons obtenir C avec du code comme ce:

#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 nous faisons ce processus de normalisation sur un grand nombre de points, tous par rapport au même point A et avec la même distance R, alors les points normalisés reposeront tous sur l'arc d'un cercle avec le centre A et le rayon R.

segment de ligne bombé

Ici, les points noirs commencent sur une ligne et "se gonflent" dans un arc.

Ce processus peut être étendu en trois dimensions, auquel cas vous obtenez une sphère plutôt qu'un cercle. Il suffit d'ajouter un composant DZ à la normaliser fonction.

polygones normalisés

niveau 1 octaèdre bombéniveau 3 octaèdre bombé

Si vous regardez la sphère à Epcot, vous pouvez sorte de voir cette technique au travail. c'est un dodécaèdre avec des visages bombés pour le rendre plus Rond.

239
répondu Kevin 2013-03-28 18:22:48

Je vais expliquer plus loin une façon populaire de générer une sphère en utilisant la latitude et la longitude (une autre façon, icosphères , a déjà été expliqué dans la réponse la plus populaire au moment de cette écriture.)

Une sphère peut être exprimée par l'équation paramétrique suivante:

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

Où:

  • r est le rayon;
  • u {[3] } est la longitude, allant de 0 à 2π; et
  • v est la latitude, allant de 0 à π.

Générer la sphère implique alors d'évaluer la fonction paramétrique à intervalles fixes.

Par exemple, pour générer 16 lignes de longitude, il y aura 17 lignes de grille le long de l'axe u, avec un pas de π/8 (2π / 16) (la 17ème ligne s'enroule autour).

Le pseudocode suivant génère un maillage triangulaire en évaluant une fonction paramétrique à intervalles réguliers (cela fonctionne Toute fonction de surface paramétrique, pas seulement des sphères).

Dans le pseudocode ci-dessous, UResolution est le nombre de points de grille le long de L'axe U (ici, les lignes de longitude), et VResolution est le nombre de points de grille le long de L'axe V (ici, lignes de latitude)

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<UResolution;i++){ // U-points
 for(var j=0;j<VResolution;j++){ // V-points
 var u=i*stepU+startU
 var v=j*stepV+startV
 var un=(i+1==UResolution) ? EndU : (i+1)*stepU+startU
 var vn=(j+1==VResolution) ? EndV : (j+1)*stepV+startV
 // Find the four points of the grid
 // square by evaluating the parametric
 // surface function
 var p0=F(u, v)
 var p1=F(u, vn)
 var p2=F(un, v)
 var p3=F(un, vn)
 // NOTE: For spheres, the normal is just the normalized
 // version of each vertex point; this generally won't be the case for
 // other parametric surfaces.
 // Output the first triangle of this grid square
 triangle(p0, p2, p1)
 // Output the other triangle of this grid square
 triangle(p3, p1, p2)
 }
}
20
répondu Peter O. 2016-12-06 16:08:52

Le code de l'échantillon est rapidement expliqué. Vous devriez regarder dans la fonction void drawSphere(double r, int lats, int longs). Les paramètres lat définit le nombre de lignes horizontales que vous voulez avoir dans votre sphère et lon combien de lignes verticales. r est le rayon de votre sphère.

Maintenant, il y a une double itération sur lat/lon et les coordonnées du sommet sont calculées, en utilisant une trigonométrie simple.

Les sommets calculés sont maintenant envoyés à votre GPU en utilisant glVertex...() comme GL_QUAD_STRIP, ce qui signifie que vous envoyez chacun deux sommets qui forment un quad avec les deux précédemment envoyés.

Tout ce que vous devez comprendre maintenant, c'est comment fonctionnent les fonctions de trigonométrie, mais je suppose que vous pouvez le comprendre facilement.

2
répondu Constantinius 2011-10-07 12:42:42

Si vous vouliez être sournois comme un renard, vous pourriez demi-pouce le code de GLU. Consultez le code source MesaGL (http://cgit.freedesktop.org/mesa/mesa/).

1
répondu blockchaindev 2011-10-07 12:44:06

Voir le livre rouge OpenGL: http://www.glprogramming.com/red/chapter02.html#name8 Il résout le problème par subdivision de polygone.

1
répondu Walter 2013-03-23 20:12:21

Bien que la réponse acceptée résout la question, il y a une petite idée fausse à la fin. Les Dodécaèdres sont (ou pourraient être) des polyèdres réguliers où toutes les faces ont la même surface. Cela semble être le cas de L'Epcot (qui, d'ailleurs, n'est pas du tout un dodécaèdre ). Puisque la solution proposée par @ Kevin ne fournit pas cette caractéristique, j'ai pensé que je pourrais ajouter une approche qui le fait.

Un bon moyen de générer un polyèdre N-Face où tous les sommets se trouvent dans la même sphère et toutes ses faces ont une surface/surface similaire commence par un icosaèdre et la sous-division itérative et la normalisation de ses faces triangulaires (comme suggéré dans la réponse acceptée). Les dodécaèdres, par exemple, sont en fait icosaèdres tronqués .

Les icosaèdres réguliers ont 20 faces (12 sommets) et peuvent facilement être construits à partir de 3 rectangles d'or; c'est juste une question d'avoir ceci comme point de départ au lieu d'un l'octaèdre. Vous pouvez trouver un exemple ici.

Je sais que c'est un peu hors sujet, mais je crois que cela peut aider si quelqu'un arrive ici à la recherche de ce cas spécifique.

1
répondu Carles Araguz 2018-03-22 10:21:59

Mon exemple comment utiliser 'triangle strip' pour dessiner une sphère "polaire", il consiste à dessiner des points par paires:

const float PI = 3.141592f;
GLfloat x, y, z, alpha, beta; // Storage for coordinates and angles        
GLfloat radius = 60.0f;
int gradation = 20;

for (alpha = 0.0; alpha < GL_PI; alpha += PI/gradation)
{        
    glBegin(GL_TRIANGLE_STRIP);
    for (beta = 0.0; beta < 2.01*GL_PI; beta += PI/gradation)            
    {            
        x = radius*cos(beta)*sin(alpha);
        y = radius*sin(beta)*sin(alpha);
        z = radius*cos(alpha);
        glVertex3f(x, y, z);
        x = radius*cos(beta)*sin(alpha + PI/gradation);
        y = radius*sin(beta)*sin(alpha + PI/gradation);
        z = radius*cos(alpha + PI/gradation);            
        glVertex3f(x, y, z);            
    }        
    glEnd();
}

Le premier point entré (glVertex3f) est comme suit l'équation paramétrique et le second est décalé d'un seul pas d'angle alpha (à partir du parallèle suivant).

0
répondu bloody 2016-09-17 13:10:18

Une façon est de faire un quad qui fait face à la caméra et d'écrire un sommet et un fragment shader qui rend quelque chose qui ressemble à une sphère. Vous pouvez utiliser des équations pour un cercle / sphère que vous pouvez trouver sur internet.

Une bonne chose est que la silhouette d'une sphère ressemble à n'importe quel angle. Cependant, si la sphère n'est pas au centre d'une vue en perspective, elle apparaîtrait peut-être plus comme une ellipse. Vous pouvez travailler sur les équations pour cela et les mettre dans le fragment d'ombrage. Ensuite, l'ombrage de la lumière doit changer à mesure que le joueur se déplace, si vous avez en effet un joueur se déplaçant dans L'espace 3D autour de la sphère.

Quelqu'un peut-il commenter s'il a essayé cela ou si cela serait trop coûteux pour être pratique?

0
répondu Steven2163712 2016-09-22 02:28:13