Une chose qui m'a été demandé par un certain nombre de gens est de savoir comment faire un "affichage tête haute" (HUD ou) lorsque vous utilisez OpenGL pour l'affichage en trois dimensions des objets dans une fenêtre en perspective. De nombreux jeux et autres programmes ont besoin de présenter certaines données à l'utilisateur comme si elle était écrite à droite sur l'écran en face du monde en trois dimensions. Mais, si vous avez utilisé glFrustum () pour configurer votre fenêtre qu'il ne ressemblera pas que, depuis n'importe quel dessin fait dans une fenêtre en perspective sera une expérience certaine quantité de distorsion lorsque filtrée à travers la matrice de projection.
La réponse à ce problème est relativement simple et directe. Vous ne laissez pas le dessin HUD passer par la matrice de projection même que les objets en trois dimensions. Sous le capot, la matrice de vue du projet est juste une matrice 4x4 de GLfloats, exactement comme la matrice de vue du modèle que nous utilisons pour transformer des objets dans notre monde virtuel. Et, tout comme la matrice de vue du modèle, nous pouvons apporter des changements à la matrice de projection entre les appels de dessin.
Pour illustrer ce point, je vais prendre l'ancienne icosaèdre projet de la OpenGL ES à partir du sol pour séries et faire un peu de dessin en deux dimensions sur le dessus de l'icosaèdre, exactement de la même façon que vous dessinez un HUD. Pour garder les choses simples, je vais juste faire quelques carrés et un peu de texte, comme ceci:

Les trois places et le texte sera dessiné en utilisant une matrice de projection orthographique, alors peu importe la manière dont l'objet derrière elle est transformée, déplacé ou projeté, les trois places et le texte sera rédigé exactement le même sans distorsion ou de mouvement. Vous pouvez utiliser cette technique pour attirer exactement les mêmes score du joueur, la ligne de mire d'un fusil, des contrôles un vaisseau spatial, ou tout autre dessin qui a besoin d'apparaître comme si elle était sur un morceau de verre en face de l'univers virtuel.
Avant de commencer, regardons l'setupView: fonction où nous mettons en place la fenêtre dans l'ancien projet icosaèdre:
C'est à peu près une tourbière standard perspective viewport configuration qui va permettre à nos objets en trois dimensions pour obtenir plus petits car ils s'éloignent du spectateur. Tout ce que nous tirage au sort sera déformée pour représenter la perspective, que nous ne voulons pas pour nos éléments du HUD. Alors ... Créons un couple de méthodes pratiques pour sortir du mode perspective et en mode orthographique et vice-versa
Tout d'abord, pour passer la projection en mode orthographique, nous allons utiliser cette méthode:
C'est assez simple, mais il faut bien briser la ligne par ligne. La première ligne est important. Nous ne voulons pas le test de profondeur si nous sommes de dessin en deux dimensions parce que nous voulons que tous nos dessin fait sur le même plan, sans profondeur.
Ensuite, nous appelons glMatrixMode () pour rendre la matrice de projection actif. Après cela, nous poussons la matrice de projection existant sur la pile de matrice de sorte que nous pouvons restaurer plus tard. Lorsque ce est appelé, la matrice de projection contient une matrice qui a été généré par notre appel à glFrustum (), et nous devons être en mesure d'y revenir plus tard. Nous avons ensuite la charge de l'identité d'identifier puis mettre en place une projection orthographique où chaque pixel de l'écran équivaut à une unité d'OpenGL, ce qui rendra nos deux dimensions dessin plus facile puisque chaque unité sera égal à un pixel.
Après cela, nous chargeons la matrice identité dans notre matrice de vue modèle si nous commençons à tirer de notre HUD avec une ardoise propre, non affecté par les transformations utilisées précédemment.
En plus d'une méthode pour entrer en mode orthographique, nous avons également besoin d'une méthode pour rétablir notre matrice de projection précédente, celle qui nous avons créé dans setupView:. Depuis que nous avons poussé la matrice de projection existant sur la pile de matrice précédemment, tous nous avons à faire ici est ré-eneable profondeur des tests et la pop de notre matrice de projection vieux de la pile de matrice:
Maintenant nous avons la possibilité de basculer entre le mode de perspective et orthographique, nous allons donc faire un peu de dessin. Voici la méthode de dessin du projet icosaèdre avec le code HUD nouveau dessin élaboré en gras. J'ai utilisé la classe Texture2D Apple pour gérer le dessin du texte. J'ai fait cela juste pour la simplicité - c'est loin d'être le moyen le plus efficace pour dessiner le texte dans OpenGL ES. En fait, c'est assez inefficace, mais c'est facile et gratuit. Peut-être je vais me concentrer sur les meilleures façons de dessiner du texte dans une future affectation, mais ce poste est d'environ HUD, pas de texte, afin que nous puissions vivre avec une inefficacité peu.
Nous commençons par appeler notre méthode switchToOrtho. Nous définissons ensuite les sommets d'un carré qui sera établi à l'aide GL_LINE_LOOP et de soumettre ces sommets en utilisant glVertexPointer (). Après cela, nous appelons glDrawArrays () trois fois, en changeant la couleur et faire un transforment traduire entre les appels de telle sorte que chaque carré est dessiné à droite de la précédente et dans une couleur différente.
Après cela, nous utilisons Texture2D de dessiner le mot "texte" sur l'écran. Comme cette classe tire l'essentiel le texte dans un contexte graphique crée ensuite une texture hors de lui, nous avons pour l'activer (et désactiver) un tas de textures options liées.
Après nous sommes tous fait le dessin, que nous appelons la méthode que nous avons créé d'autres, switchBackToFrustum, pour revenir au mode perspective afin que la prochaine fois que notre drawView: méthode est appelée, nous sommes de retour dans trois dimensions de mode.
Et c'est tout ce qu'il ya à dessiner un HUD sur une fenêtre en perspective. Vous pouvez télécharger le projet Xcode ici et de jouer avec elle-même.
La réponse à ce problème est relativement simple et directe. Vous ne laissez pas le dessin HUD passer par la matrice de projection même que les objets en trois dimensions. Sous le capot, la matrice de vue du projet est juste une matrice 4x4 de GLfloats, exactement comme la matrice de vue du modèle que nous utilisons pour transformer des objets dans notre monde virtuel. Et, tout comme la matrice de vue du modèle, nous pouvons apporter des changements à la matrice de projection entre les appels de dessin.
Pour illustrer ce point, je vais prendre l'ancienne icosaèdre projet de la OpenGL ES à partir du sol pour séries et faire un peu de dessin en deux dimensions sur le dessus de l'icosaèdre, exactement de la même façon que vous dessinez un HUD. Pour garder les choses simples, je vais juste faire quelques carrés et un peu de texte, comme ceci:

Les trois places et le texte sera dessiné en utilisant une matrice de projection orthographique, alors peu importe la manière dont l'objet derrière elle est transformée, déplacé ou projeté, les trois places et le texte sera rédigé exactement le même sans distorsion ou de mouvement. Vous pouvez utiliser cette technique pour attirer exactement les mêmes score du joueur, la ligne de mire d'un fusil, des contrôles un vaisseau spatial, ou tout autre dessin qui a besoin d'apparaître comme si elle était sur un morceau de verre en face de l'univers virtuel.
Avant de commencer, regardons l'setupView: fonction où nous mettons en place la fenêtre dans l'ancien projet icosaèdre:
-(void)setupView:(GLView*)view
{
GLfloat size;
const GLfloat zNear = 0.1,
zFar = 1000.0,
fieldOfView = 60.0;
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
CGRect rect = self.view.bounds;
glMatrixMode(GL_PROJECTION);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size /
(rect.size.width / rect.size.height), zNear, zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
colors = [[NSMutableArray alloc] initWithCapacity:20];
for (int i =0; i < 20; i++)
[colors addObject:[UIColor randomColor]];
}C'est à peu près une tourbière standard perspective viewport configuration qui va permettre à nos objets en trois dimensions pour obtenir plus petits car ils s'éloignent du spectateur. Tout ce que nous tirage au sort sera déformée pour représenter la perspective, que nous ne voulons pas pour nos éléments du HUD. Alors ... Créons un couple de méthodes pratiques pour sortir du mode perspective et en mode orthographique et vice-versa
Tout d'abord, pour passer la projection en mode orthographique, nous allons utiliser cette méthode:
-(void)switchToOrtho
{
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrthof(0, self.view.bounds.size.width, 0, self.view.bounds.size.height, -5, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}C'est assez simple, mais il faut bien briser la ligne par ligne. La première ligne est important. Nous ne voulons pas le test de profondeur si nous sommes de dessin en deux dimensions parce que nous voulons que tous nos dessin fait sur le même plan, sans profondeur.
Ensuite, nous appelons glMatrixMode () pour rendre la matrice de projection actif. Après cela, nous poussons la matrice de projection existant sur la pile de matrice de sorte que nous pouvons restaurer plus tard. Lorsque ce est appelé, la matrice de projection contient une matrice qui a été généré par notre appel à glFrustum (), et nous devons être en mesure d'y revenir plus tard. Nous avons ensuite la charge de l'identité d'identifier puis mettre en place une projection orthographique où chaque pixel de l'écran équivaut à une unité d'OpenGL, ce qui rendra nos deux dimensions dessin plus facile puisque chaque unité sera égal à un pixel.
Après cela, nous chargeons la matrice identité dans notre matrice de vue modèle si nous commençons à tirer de notre HUD avec une ardoise propre, non affecté par les transformations utilisées précédemment.
En plus d'une méthode pour entrer en mode orthographique, nous avons également besoin d'une méthode pour rétablir notre matrice de projection précédente, celle qui nous avons créé dans setupView:. Depuis que nous avons poussé la matrice de projection existant sur la pile de matrice précédemment, tous nous avons à faire ici est ré-eneable profondeur des tests et la pop de notre matrice de projection vieux de la pile de matrice:
-(void)switchBackToFrustum
{
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}Maintenant nous avons la possibilité de basculer entre le mode de perspective et orthographique, nous allons donc faire un peu de dessin. Voici la méthode de dessin du projet icosaèdre avec le code HUD nouveau dessin élaboré en gras. J'ai utilisé la classe Texture2D Apple pour gérer le dessin du texte. J'ai fait cela juste pour la simplicité - c'est loin d'être le moyen le plus efficace pour dessiner le texte dans OpenGL ES. En fait, c'est assez inefficace, mais c'est facile et gratuit. Peut-être je vais me concentrer sur les meilleures façons de dessiner du texte dans une future affectation, mais ce poste est d'environ HUD, pas de texte, afin que nous puissions vivre avec une inefficacité peu.
- (void)drawView:(GLView*)view;
{
static GLfloat rico;
static const GLfloat icosahedronVertices[]= {
0, -0.525731, 0.850651,
0.850651, 0, 0.525731,
0.850651, 0, -0.525731,
-0.850651, 0, -0.525731,
-0.850651, 0, 0.525731,
-0.525731, 0.850651, 0,
0.525731, 0.850651, 0,
0.525731, -0.850651, 0,
-0.525731, -0.850651, 0,
0, -0.525731, -0.850651,
0, 0.525731, -0.850651,
0, 0.525731, 0.850651,
};
static const GLubyte icosahedronFaces[] = {
1, 2, 6,
1, 7, 2,
3, 4, 5,
4, 3, 8,
6, 5, 11,
5, 6, 10,
9, 10, 2,
10, 9, 3,
7, 8, 9,
8, 7, 0,
11, 0, 1,
0, 11, 4,
6, 2, 10,
1, 6, 11,
3, 5, 10,
5, 4, 11,
2, 7, 9,
7, 1, 0,
3, 9, 8,
4, 8, 0,
};
static const GLubyte icosahedronNumberOfFaces = 60;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Icosahedron
glLoadIdentity();
glEnableClientState(GL_VERTEX_ARRAY);
glTranslatef(0.0f,0.0f,-2.0f);
glRotatef(rico,1.0f,1.0f,1.0f);
glVertexPointer(3, GL_FLOAT, 0, icosahedronVertices);
for(int i = 0; i < icosahedronNumberOfFaces; i += 3)
{
UIColor *oneColor = [colors objectAtIndex:i/3];
[oneColor setOpenGLColor];
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &icosahedronFaces[i]);
}
glDisableClientState(GL_VERTEX_ARRAY);
static NSTimeInterval lastDrawTime;
if (lastDrawTime)
{
NSTimeInterval timeSinceLastDraw = [NSDate timeIntervalSinceReferenceDate] - lastDrawTime;
rico+=50 * timeSinceLastDraw;
}
// ------------------------------------------------
// Draw HUD ---------------------------------------
// ------------------------------------------------
[self switchToOrtho];
static const GLfloat squareVertices[] = {
5.0f, 150.0f,
5.0f, 250.0f,
100.0f, 250.0f,
100.0f, 150.0f
};
glLineWidth(3.0);
glColor4f(0.0, 0.0, 1.0, 1.0); // blue
glTranslatef(5.0, 0.0, 0.0);
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glTranslatef(100.0, 0.0, 0.0);
glColor4f(1.0, 0.0, 0.0, 1.0); // Red
glDrawArrays(GL_LINE_LOOP, 0, 4);
glTranslatef(100.0, 0.0, 0.0);
glColor4f(1.0, 1.0, 0.0, 1.0); // Yellow
glDrawArrays(GL_LINE_LOOP, 0, 4);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0, 1.0, 1.0, 1.0);
glLoadIdentity();
Texture2D *textTex = [[Texture2D alloc] initWithString:@"Text"
dimensions:CGSizeMake(100., 40.0)
alignment:UITextAlignmentCenter
font:[UIFont boldSystemFontOfSize:36.0]];
[textTex drawAtPoint:CGPointMake(160.0, 440.0) depth:-1];
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
[self switchBackToFrustum];
lastDrawTime = [NSDate timeIntervalSinceReferenceDate];
}Nous commençons par appeler notre méthode switchToOrtho. Nous définissons ensuite les sommets d'un carré qui sera établi à l'aide GL_LINE_LOOP et de soumettre ces sommets en utilisant glVertexPointer (). Après cela, nous appelons glDrawArrays () trois fois, en changeant la couleur et faire un transforment traduire entre les appels de telle sorte que chaque carré est dessiné à droite de la précédente et dans une couleur différente.
Après cela, nous utilisons Texture2D de dessiner le mot "texte" sur l'écran. Comme cette classe tire l'essentiel le texte dans un contexte graphique crée ensuite une texture hors de lui, nous avons pour l'activer (et désactiver) un tas de textures options liées.
Après nous sommes tous fait le dessin, que nous appelons la méthode que nous avons créé d'autres, switchBackToFrustum, pour revenir au mode perspective afin que la prochaine fois que notre drawView: méthode est appelée, nous sommes de retour dans trois dimensions de mode.
Et c'est tout ce qu'il ya à dessiner un HUD sur une fenêtre en perspective. Vous pouvez télécharger le projet Xcode ici et de jouer avec elle-même.
Aucun commentaire:
Enregistrer un commentaire