Le module VideoTexture : bge.texture¶
Le module bge.texture
vous permet de manipuler les textures pendant le jeu. Plusieurs sources de textures sont possibles : fichiers vidéo, fichiers image, capture vidéo, tampon de mémoire, rendu de caméra ou un mélange de tout cela. Les fichiers vidéo et image peuvent être chargés depuis Internet en utilisant un URL à la place d’un nom de fichier. De plus, vous pouvez appliquer des filtres sur les images avant de les envoyer au GPU, produisant ainsi un effet vidéo : écran bleu, gradient, gris, normal map. bge.texture
utilise FFmpeg pour charger les images et les vidéo. Tous les formats et codecs pris en charge par FFmpeg le sont par bge.texture
, y compris (mais pas limités à ceux-ci) :
- AVI
- Ogg
- Xvid
- Theora
- caméra dv1394
- Carte de capture video4linux (ceci inclut de nombreux webcams)
- Carte de capture videoForWindows (ceci inclut de nombreux webcams)
- JPG
Comment ça marche¶
Le principe est simple : d’abord vous identifiez une texture existante par objet et nom, ensuite vous créez une nouvelle texture avec un contenu dynamique et échangez les deux textures dans le GPU. Le GE n’est pas averti de la substitution et continue à afficher l’objet comme toujours, sauf que vous avez maintenant le contrôle de la texture. À la fin, la nouvelle texture est supprimée et l’ancienne texture restaurée.
La présente page est un guide pour le module bge.texture
avec des exemples simples.
Préparation du jeu¶
Avant que vous puissiez utiliser le module bge.texture
, vous devez disposer d’objets avec des textures appliquées de façon appropriée.
Imaginez que vous voulez avoir une télévision affichant des émissions en direct dans le jeu. Vous allez créer un objet télévision et appliquer (UV) une texture différente à la place de l’écran, par exemple tv.png
. Ce à quoi ressemble cette texture n’est pas important ; probablement vous aimeriez la rendre en gris foncé pour simuler l’état éteint. Quand la télévision doit être allumée, vous créez une texture dynamique depuis une carte de capture vidéo et l’utilisez à la place de tv.png
: l’écran TV va prendre vie.
Vous avez deux façons pour définir les textures que bge.texture
peut saisir :
- Texture UV simple.
- Matériau Blender avec canal de texture d’image.
Du fait que bge.texture
fonctionne au niveau texture, c’est compatible avec toutes les fonctions sophistiquées de texturage de BGE : GLSL, multi-texture, custom shaders, etc.
Premier exemple¶
Supposons que nous avons un objet de jeu avec une ou plusieurs faces assignées à un matériau/image sur lequel nous voulons afficher une vidéo.
La première étape est de créer un objet Texture
. Nous allons le faire dans un script qui s’exécute une fois. Il peut être au début du jeu, la vidéo est seulement jouée quand vous actualisez la texture ; nous allons revenir dessus plus tard. Le script est normalement attaché à l’objet sur lequel vous voulons afficher la vidéo de sorte que nous pouvons facilement récupérer la référence de l’objet :
import bge.texture
contr = GameLogic.getCurrentController()
obj = contr.owner
if not hasattr(GameLogic, 'video'):
La coche sur l’attribut video
est simplement une astuce pour nous assurer que vous avons créé la texture seulement une fois.
Recherche de matériau¶
matID = bge.texture.materialID(obj, 'IMvideo.png')
bge.texture.materialID()
est une fonction pratique pour récupérer le matériau de l’objet qui utilise video.png
comme texture. Cette méthode fonctionnera avec un matériau Blender et une texture UV. Dans le cas d’une texture UV, il prend le matériau interne correspondant aux faces qui sont assignées à cette texture. Dans le cas d’un matériau Blender, il prend le matériau qui a un canal de texture d’image correspondant au nom du premier canal.
Le préfixe IM
indique que nous sommes en train de chercher un nom de texture mais nous pouvons aussi chercher un matériau en donnant le préfixe MA
. Par exemple, si nous voulons trouver le matériau appelé VideoMat
sur cet objet, le code devient :
matID = bge.texture.materialID(obj, 'MAVideoMat')
Création d’une texture¶
bge.texture.Texture
est la classe qui crée l’objet Texture
qui charge la texture dynamique sur le GPU. Le constructeur prend un argument obligatoire et trois facultatifs :
gameObj
- L’objet game.
materialID
- Index du matériau retourné par
bge.texture.materialID()
, 0 = premier matériau par défaut. textureID
- Index de texture dans le cas de canal multi-texture, 0 = premier canal par défaut. Dans le cas de texture UV, ce paramètre devrait toujours être à 0.
textureObj
- Référence à un autre objet
Texture
dont nous voulons réutiliser la texture. Si nous utilisons cet argument, nous ne devrions pas créer de source sur cette texture et il n’est pas nécessaire de le réactualiser non plus ; l’autre objetTexture
fournira la texture à la fois pour les matériaux/textures.
GameLogic.video = bge.texture.Texture(obj, matID)
Rendre une texture persistante¶
Notez que nous avons assigné l’objet à un GameLogic
, attribut video
que nous avons créé pour l’occasion. La raison est que l’objet Texture
doit être persistant à travers les scripts de jeu. une variable locale serait supprimée à la fin du script et la texture GPU supprimée en même temps. l’objet du module GameLogic
est un emplacement pratique pour stocker les objets persistants.
Création d’une source¶
maintenant nous avons un objet Texture
mais il ne peut rien faire car il n’a aucune source. Nous devons créer une source à partir d’une des sources possibles disponibles dans bge.texture
:
VideoFFmpeg
- images animées. Fichier vidéo, capture vidéo, streaming vidéo.
ImageFFmpeg
- Images fixes. Fichier image, image sur le web.
ImageBuff
- Image depuis la mémoire de l’application. Pour les images générées par ordinateur, les applications de dessin.
ImageViewport
- Tout ou partie de la vue (= rendu de la caméra active affichée à l’écran).
ImageRender
- Rendu d’une caméra non active.
ImageMix
- Un mélange de deux ou plus des sources ci-dessus.
Dans cet exemple nous utilisons un simple fichier vidéo comme source. Le constructeur VideoFFmpeg
prend un nom de fichier comme argument. Pour éviter toute confusion avec l’emplacement du fichier, nous utiliserons GameLogic.expandPath ()
pour construire un nom de fichier absolu, en supposant que le fichier vidéo est dans le même dossier que le fichier blend:
movie = GameLogic.expandPath('//trailer_400p.ogg')
GameLogic.video.source = bge.texture.VideoFFmpeg(movie)
Nous créons l’objet source vidéo et l’assignons à l’attribut source
de l’objet Texture
pour définir la source et la rendre persistante : comme l’objet Texture
est persistant, l’objet source sera aussi persistant.
Notez que nous pouvons modifier la source Texture
à tout moment. Supposez que nous voulons échanger les deux films durant le jeu.
Nous pouvons faire ce qui suit
GameLogic.mySources[0] = bge.texture.VideoFFmpeg('movie1.avi')
GameLogic.mySources[1] = bge.texture.VideoFFmpeg('movie2.avi')
Et ensuite assigner (et réassigner) la source durant le jeu
GameLogic.video.source = GameLogic.mySources[movieSel]
Configuration de la source¶
La source VideoFFmpeg
a plusieurs attributs pour contrôler la lecture vidéo :
range
- [start,stop] (flottants). Définissez les temps de début et de fin de la lecture vidéo, exprimés en secondes depuis le début de la vidéo. Par défaut, la vidéo complète.
repeat
- (entier). Nombre de lectures vidéo. -1 pour infini.
framerate
- (flottant). Fréquence de trames relative, <1.0 pour lent, >1.0 pour rapide.
scale
- (booléen). Fixé à True pour activer l’algorithme rapide de mise à l’échelle nearest-neighbor (le plus proche voisin). La largeur et la hauteur de texture doivent être des puissances de 2. Si la taille d’image vidéo n’est pas une puissance de 2, la remise à l’échelle est nécessaire. Par défaut
bge.texture
utilise la fonctiongluScaleImage()
précise mais lente. Le mieux est de remettre à l’échelle la vidéo hors ligne afin qu’aucune mise à l’échelle ne soit nécessaire à l’exécution ! flip
- (booléen). Fixé à True si l’image doit être retournée verticalement. FFmpeg livre toujours l’image retournée, aussi cet attribut est fixé à True par défaut.
filter
- Définir un filtre supplémentaire sur la vidéo avant son envoi vers le GPU. Assignez à un de objets filtres
bge.texture
. Par défaut l’image est envoyée sans modification au GPU. Si un canal alpha est présent dans la vidéo, il est automatiquement chargé et envoyé de même au GPU.
Nous allons simplement mettre l’attribut scale
à True parce que gluScaleImage ()
est vraiment trop lent pour une vidéo en temps réel. Dans le cas où les dimensions vidéo sont déjà une puissance de 2, il n’a aucun effet.
GameLogic.video.source.scale = True
Lecture de la vidéo¶
Nous sommes maintenant prêts à lire la vidéo
GameLogic.video.source.play()
La lecture vidéo n’est pas un processus d’arrière-plan : il se passe seulement quand nous actualisons la texture. Aussi nous devons avoir un autre script qui fonctionne sur chaque trame et appelle la méthode refresh()
de l’objet Texture
if hasattr(GameLogic, 'video'):
GameLogic.video.refresh(True)
Si la source vidéo est arrêtée, refresh()
n’a pas d’effet, L’argument de refresh()
est un drapeau qui indique si la texture devrait être recalculée au prochain rafraîchissement. Pour la lecture vidéo, vous voudrez certainement le mettre à True.
Vérification du statut de la vidéo¶
Les classes de source vidéo (telle que VideoFFMpeg) ont un attribut status
. Si la lecture vidéo est en cours, sa valeur est 2, si elle est arrêtée, c’est 3. Aussi dans notre exemple
if GameLogic.video.source.status == 3:
#video has stopped
Flux de travail avancé¶
L’argument True dans la méthode Texture.refresh()
invalide simplement le tampon d’image après son envoi vers le GPU de sorte que sur la trame suivante, une nouvelle image sera chargée depuis la source. Il a l’effet indésirable de rendre l’image indisponible pour Python. Vous pouvez aussi le faire manuellement en appelant directement la méthode refresh()
de la source.
Voici certaines possibilités de flux de travail avancés :
Utiliser le tampon d’image dans Python (n’affecte pas la Texture)
GameLogic.video.refresh(False) image = GameLogic.video.source.image # image is a binary string buffer of row major RGBA pixels # ... use image # invalidates it for next frame GameLogic.video.source.refresh()
Charger l’image depuis la source pour le traitement avec Python sans chargement vers le GPU :
Notez que nous n’appelons même pas d’actualisation de la Texture.
Vous pourrions aussi créer un objet source sans objet Texture
image = GameLogic.video.source.image # ... use image GameLogic.video.source.refresh()
Si vous avez plus d’un matériau sur le maillage et que vous voulez modifier une texture d’un matériau particulier, récupérez son ID
matID = bge.texture.materialID(gameobj, "MAmat.001")
Le matériau GLSL peut avoir plus d’un canal de texture, identifiez la texture par le slot de texture où elle est définie, en voici deux
tex=bge.texture.Texture(gameobj, matID, 2)
Démos avancées¶
Voici une démo qui montre l’utilisation de deux vidéos alternativement sur la même texture. Notez qu’elle nécessite un fichier vidéo supplémentaire qui est la bande-annonce de Elephant Dream. Vous pouvez le remplacer par un autre fichier dont vous voulez lancer la démo.
Voici une démo qui montre l’utilisation de la source ImageMix
. ImageMix``est une source qui nécessite des sources, qui peuvent être n'importe quelle autre source ``Texture
, comme VideoFFmpeg
, ImageFFmpeg
ou ImageRender
. Vous les définissez avec setSource ()
et leur poids relatif avec setWeight()
. Faites attention au fait que le poids est un nombre entre 0 et 255, et que la somme de tous les poids devrait être 255. ImageMix
fait un mélange de tous les sources selon leurs poids. Les sources doivent avoir la même taille d’image (après réduction de la dimension à la puissance de deux la plus proche). Si cette condition n’est pas remplie, vous obtiendrez une erreur Python sur la console.