Les hooks (crochets en français) font partie des techniques avancées d'affichage. Ils permettent d'exécuter du code à chaque frame alors que le contexte OpenGL est prêt pour l'affichage. Cela signifie qu'il est possible d'ajouter des éléments ou des effets graphiques dans la fenêtre de jeu par voie de programmation sans passer par le moteur graphique du jeu. Les possibilités sont vastes mais le prix à payer est qu'il faut passer par OpenGL. Voyons plus en détails comment cela se passe.
Un hook est une fonction Python que nous devons écrire et dans laquelle nous mettrons du code OpenGL, soit directement grâce au module bgl
de Blender qui exporte la plupart des fonctions, soit indirectement via notre API Python préférée pour générer du graphisme OpenGL.
Nous devons enregistrer cette fonction auprès de la scène courante :
scene.pre_draw.append(my_function)
scene.post_draw.append(my_function)
Les attributs pre_draw
et post_draw
sont des listes pour permettre à différentes parties du code d'enregistrer leur fonctions. Pour supprimer une fonction hook existante, il suffit d'utiliser la méthode remove
: scene.post_draw.remove(my_function)
Une fois enregistrée auprès de la scène, la fonction sera appelée par le moteur graphique à chaque frame avec les modalités suivantes :
La fonction est appelée sans argument. Cependant, comme elle est appelée dans le cadre de la scène où elle a été enregistrée, elle a accès à la scène de manière habituelle (via la fonction logic.getCurrentScene()
) et si nécessaire à tous les objets qu'elle contient.
pre_draw
: matrice chargée, frame buffer vide.
Le contexte OpenGL est prêt pour des commandes d'affichage, le frame buffer est vide et les matrices OpenGL actives sont telles que les vertices que nous enverrons à OpenGL devront être en coordonnées world. Nous avons bien sûr la possibilité de charger de nouvelles matrices mais nous devrons impérativement rétablir l'état OpenGL avant le return
. Tout ce que nous mettrons dans le frame buffer sera combiné avec le rendu des objets.
post_draw:
matrice indéterminée, frame buffer rempli.
Les fonctions post_draw
héritent d'un frame buffer contenant le rendu de tous les objets de la scène plus le résultat des éventuels filtres 2D. Elle ne peuvent compter sur des valeurs particulières de matrices OpenGL, elle devront donc positionner les matrices selon leurs besoins sans nécessité de rétablir l'état OpenGL avant le return
.
Les fonctions hook sont compatibles avec les viewports dans les limites suivantes :
pre_draw
sont exécutées pour chaque viewport. Elles héritent du contexte OpenGL du viewport courant. Cela permet d'agir dans chaque viewport. Cependant, une fonction qui ne devrait écrire que dans un viewport devrait d'abord tester le viewport avec la fonction OpenGL appropriée (il n'existe aucun moyen de connaître le viewport courant avec l'API du BGE).post_draw
ne sont exécutées qu'une seule fois par frame à la fin du rendu de tous les viewports. Elles héritent de la totalité de la fenêtre OpenGL.Nous allons afficher une sorte de barre rouge et semi transparente à l'écran. Cette routine doit s'effectuer après le rendu de l'image. Pour être sûr que la routine s'effectuera bien après le rendu de l'image la fonction write()
s'enregistre dans la liste post_draw
contenu dans l'objet scene
récupéré juste avant. post_draw
est une liste de fonctions (plus exactement post_draw
est une liste de callable) qui seront exécutées les unes après les autres, et cela après chaque rendu.
from bge import logic, render
import bgl
def init():
scene = logic.getCurrentScene()
scene.post_draw = [write]
def write():
""" Write on screen """
scene = logic.getCurrentScene()
width = render.getWindowWidth()
height = render.getWindowHeight()
# OpenGL setup
bgl.glMatrixMode(bgl.GL_PROJECTION)
bgl.glLoadIdentity()
bgl.gluOrtho2D(0, width, 0, height)
bgl.glMatrixMode(bgl.GL_MODELVIEW)
bgl.glLoadIdentity()
# Draw a 2D rectangle to make the fonts stand out
bgl.glEnable(bgl.GL_BLEND)# Enable alpha blending
bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA)
view_buf = bgl.Buffer(bgl.GL_INT, 4)
bgl.glGetIntegerv(bgl.GL_VIEWPORT, view_buf)
view = view_buf
bgl.glMatrixMode(bgl.GL_PROJECTION)
bgl.glLoadIdentity()
bgl.gluOrtho2D(0, view[2], 0, view[3])
bgl.glMatrixMode(bgl.GL_MODELVIEW)
bgl.glLoadIdentity()
bgl.glBegin(bgl.GL_QUADS)
bgl.glColor4f(.4, 0, 0, 0.4)
bgl.glVertex2f(5, (height/2))
bgl.glVertex2f(width -5, (height/2))
bgl.glVertex2f(width - 5, (height/2) + 21)
bgl.glVertex2f(5, int(height/2) + 21)
bgl.glEnd()
def main(cont):
own = cont.owner
if not "init" in own:
own["init"] = True
init()
Ressource : OpenGL_postdraw.blend
Il est aussi possible d'afficher du texte de la même façon, via le moduleblf
.
Il y a une erreur de communication avec le serveur Booktype. Nous ne savons pas actuellement où est le problème.
Vous devriez rafraîchir la page.