Navigation▲
Tutoriel précédent : les rotations |
Tutoriel suivant : particules/instanciation |
I. Introduction▲
Les billboards sont des éléments 2D incrustés dans un monde 3D. Ce n'est pas un menu 2D au-dessus de tout le reste ni un plan 3D autour duquel vous pouvez tourner, mais quelque chose entre les deux, comme les barres de vies dans beaucoup de jeux.
Ce qui diffère avec les billboards est qu'ils sont positionnés à un endroit spécifique, mais que leur orientation est automatiquement calculée afin qu'ils soient toujours face à la caméra.
II. Solution n° 1 : la méthode 2D▲
Cette méthode est très simple.
Calculez simplement où votre point est à l'écran et affichez un texte 2D (voir le onzième tutoriel) à cette position.
// Tout ce qu'il y a ici est expliqué dans le troisième tutoriel ! Il n'y rien de nouveau.
glm::
vec4 BillboardPos_worldspace(x,y,z, 1.0
f);
glm::
vec4 BillboardPos_screenspace =
ProjectionMatrix *
ViewMatrix *
BillboardPos_worldspace;
BillboardPos_screenspace /=
BillboardPos_screenspace.w;
if
(BillboardPos_screenspace.z <
0.0
f){
// L'objet est derrière la caméra, ne l'affichez pas.
}
Voilà !
En plus d'être super facile à implémenter, le billboard aura la même taille, peu importe sa distance avec la caméra. Mais le texte 2D est toujours affiché au-dessus de tout le reste et cela peut désorganiser le rendu et s'afficher au-dessus d'autres objets.
III. Solution n° 2 : la méthode 3D▲
Celle-ci est habituellement mieux et pas trop compliquée.
Le but est de garder le modèle aligné avec la caméra, mais si la caméra se déplace :
Vous pouvez voir ce problème comme étant un souci de génération de matrice de modèle, même si ce n'est pas aussi simple que cela.
L'idée est que chaque coin du billboard est au centre, déplacé par les vecteurs haut et droit de la caméra ;
Bien sûr, on ne connaît que le centre du billboard dans l'espace monde, dans lequel nous avons aussi besoin des vecteurs haut/droit de la caméra.
Dans l'espace caméra, le vecteur haut de celle-ci est (0, 1, 0). Pour l'obtenir dans l'espace monde, multipliez-le par la matrice qui transforme de l'espace caméra vers l'espace monde, qui est, bien sûr, l'inverse de la matrice de vue.
Une façon plus simple de l'exprimer en mathématique est :
CameraRight_worldspace =
{
ViewMatrix[0
][0
], ViewMatrix[1
][0
], ViewMatrix[2
][0
]}
CameraUp_worldspace =
{
ViewMatrix[0
][1
], ViewMatrix[1
][1
], ViewMatrix[2
][1
]}
Une fois que l'on a cela, il est très simple de calculer la position finale du sommet :
vec3
vertexPosition_worldspace =
particleCenter_wordspace
+
CameraRight_worldspace *
squareVertices.x *
BillboardSize.x
+
CameraUp_worldspace *
squareVertices.y *
BillboardSize.y;
- particleCenter_worldspace est, comme son nom l'indique, la position du centre du billboard : elle est déterminée en utilisant une variable uniforme vec3 ;
- squareVertices est le modèle original. SquareVertices.x est -0.5 pour les sommets de gauche, qui sont donc déplacé vers la gauche de la caméra (à cause du *CameraRight_worldsspace) ;
- BillboardSize est la taille du billboard, en unités monde, envoyée avec une variable uniforme.
Et presto, voici le résultat. C'était facile, non ?
Pour information, voici comment squareVertices est définie :
// Le VBO contient les quatre sommets des particules.
static
const
GLfloat g_vertex_buffer_data[] =
{
-
0.5
f, -
0.5
f, 0.0
f,
0.5
f, -
0.5
f, 0.0
f,
-
0.5
f, 0.5
f, 0.0
f,
0.5
f, 0.5
f, 0.0
f,
}
;
IV. Solution n° 3 : la méthode 3D avec taille fixe▲
Comme vous pouvez le voir ci-dessus, la taille du billboard change suivant la distance de la caméra. Dans certains cas, cela est le résultat attendu, mais dans d'autres, tel que les barres de vies, vous souhaitez probablement une taille fixe à la place.
Comme le déplacement entre le centre et un coin doit être fixe dans l'espace écran, c'est exactement ce que l'on va faire : calculer la position du centre dans l'espace écran et la décaler.
vertexPosition_worldspace =
particleCenter_wordspace;
// Obtenir la position dans l'espace écran du centre de la particule
gl_Position =
VP *
vec4(vertexPosition_worldspace, 1.0
f);
// Ici on doit faire la division de perspective soi-même.
gl_Position /=
gl_Position.w;
// Déplace les sommets directement dans l'espace écran. Pas besoin de CameraUp/Right_worlspace ici.
gl_Position.xy +=
squareVertices.xy *
vec2(0.2
, 0.05
);
Souvenez-vous qu'à cet endroit du pipeline de rendu, vous êtes en coordonnées normalisées du périphérique, donc entre -1 et 1 sur les deux axes : ce n'est pas en pixels.
Si vous souhaitez une taille en pixels, c'est facile : utilisez simplement (ScreenSizeInPixels / BillboardSizeInPixels) au lieu de BillboardSizeInScreenPercentage.
V. Solution n° 4 : rotation verticale seule▲
Quelques systèmes représentent les arbres et les lampes lointains tels des billboards. Mais vous ne souhaitez vraiment, vraiment pas, que votre arbre soit tordu : il DOIT être vertical. Donc vous avez besoin d'un système hybride qui tourne seulement autour d'un seul axe.
Bien, ce cas-là est laissé comme exercice pour le lecteur !
VI. Remerciements▲
Cet article est une traduction autorisée dont le texte original peut être trouvé sur opengl-tutorial.org.
Navigation▲
Tutoriel précédent : les rotations |
Tutoriel suivant : particules/instanciation |