From BlenderWiki

Jump to: navigation, search
Blender3D FreeTip.gif
IMPORTANT! Do not update this page!
We have moved the Blender User Manual to a new location. Please do not update this page, as it will be locked soon.

Traduction effectuée d’après cette révision de la version anglaise.

Le module VideoTexture

Le module VideoTexture vous permet de manipuler des textures durant le jeu. Plusieurs sources de texture sont possibles : fichiers vidéo, fichiers image, capture vidéo, tampon mémoire, rendu caméra, ou un mélange de tout cela. Les fichiers vidéo et image peuvent être chargés depuis internet, en utilisant une URL en guise de nom de fichier. Vous pouvez de plus appliquer des filtres sur les images avant de les envoyer au GPU, ce qui permet des effets vidéo : écran bleu, bandes couleur, niveaux de gris, normal map. VideoTexture utilise FFmpeg pour charger images et vidéos. Tous les formats et codecs supportés par FFmpeg le sont par VideoTexture, entre autre :

  • AVI
  • Ogg
  • Xvid
  • Theora
  • Caméra dv1394
  • Capture video4linux (ce qui inclut beaucoup de webcams)
  • Capture videoForWindows (ce qui inclut beaucoup de webcams)
  • JPG


Comment ça marche

Le principe est simple : vous commencez par identifier une texture existante (par objet et nom), puis vous créez une nouvelle texture au contenu dynamique, et intervertissez les deux textures dans le GPU. Le GE n’est pas au courant de la substitution, et continue à afficher l’objet comme d’habitude, mais vous avez maintenant le contrôle du contenu de la texture. À la fin, la nouvelle texture est supprimée, et l’ancienne est restaurée.

Cette page est un guide du module VideoTexture, avec quelques exemples basiques.

Préparation du jeu

Avant de pouvoir utiliser le module VideoTexture, vous devez avoir des objets avec des textures correctement appliquées.

Imaginez que vous voulez avoir une télévision affichant des programmes live dans le jeu. Vous créerez un objet télévision et y UV-appliquerez une texture différente à l’emplacement de l’écran, par exemple “tv.png”. Ce à quoi ressemble cette texture n’a aucune importance – vous souhaiterez probablement utiliser un gris sombre, pour simuler l’écran éteint. Quand la télévision doit être allumée, vous créez une texture dynamique à partir d’une carte de capture vidéo et l’utilisez à la place de tv.png : l’écran TV va prendre vie.

Vous avez deux moyens de définir les textures que VideoTexture peut “accaparer” :

  1. Texture UV de base.
  2. Matériau Blender avec canal de texture image.

Puisque VideoTexture travaille au niveau de la texture, il est compatible avec toutes les fonctionnalités de texturing du GE : GLSL, multi-textures, shaders personnalisés, etc.

Premier exemple

Supposons que nous avons un objet de jeu avec une ou plusieurs faces assignées à un matériau/une image sur lequel/laquelle nous voulons afficher une vidéo.

La première étape est de créer un objet Texture. Nous le ferons dans un script qui n’est exécuté qu’une fois. Cela peut être au début du jeu – la vidéo n’étant jouée que lorsque vous rafraîchissez la texture ; nous y reviendrons. Le script est normalement attaché à l’objet que nous voulons voir afficher la vidéo, afin de pouvoir facilement récupérer la référence à celui-ci :

 import VideoTexture
 
 contr = GameLogic.getCurrentController()
 obj = contr.owner
 
 if not hasattr(GameLogic, 'video'):

Le test sur l’attribut “video” n’est qu’une astuce pour s’assurer que nous ne créons la texture qu’une seule fois.

Trouver le matériau

     matID = VideoTexture.materialID(obj, 'IMvideo.png')

VideoTexture.materialID() est une fonction fort pratique pour récupérer le matériau d’un objet qui utilise video.png comme texture. Cette méthode fonctionnera avec les matériaux de Blender et les textures UV. Dans le cas d’une texture UV, elle récupère le matériau interne correspondant aux faces qui sont assignées à cette texture. Dans le cas d’un matériau Blender, elle récupère le matériau qui utilise dans son premier canal texture une texture image correspondant au nom spécifié.

Le préfixe “IM” indique que nous recherchons un nom de texture, mais vous pouvez également chercher un matériau en utilisant le préfixe “MA”. Par exemple, si vous voulez trouver un matériau nommé VideoMat sur cet objet, le code devient :

     matID = VideoTexture.materialID(obj, 'MAVideoMat')


Créer la texture

VideoTexture.Texture est la classe qui crée l’objet Texture, qui charge la texture dynamique dans le GPU. Le constructeur prend un argument obligatoire, et trois optionnels :

gameObj
L’objet jeu.
materialID
L’indice du matériau retourné par VideoTexture.materialID(), par défaut 0 pour le premier matériau.
textureID
Indice de la texture, dans le cas de plusieurs canaux texture, par défaut 0 pour le premier canal.
Dans le cas d’une texture UV, ce paramètre devrait toujours être à zéro.
textureObj
Référence vers un autre objet Texture dont vous voulez réutiliser la texture.
Si vous utilisez cet argument, vous ne devriez par créer de source pour cette texture, et il n’y a pas non plus besoin de la rafraîchir : l’autre objet Texture fournira la texture pour les deux matériaux/textures.
     GameLogic.video = VideoTexture.Texture(obj, matID)


Rendre la texture persistante

Notez que nous avons assigné l’objet à un attribut “video” créé pour l’occasion dans GameLogic. La raison en 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 disparaîtrait en même temps. L’objet module GameLogic est un emplacement pratique pour stocker des objets persistants.

Créer une source

Nous avons maintenant un objet Texture, mais il ne peut rien faire car il n’a aucune source. Vous devez créer un objet source à partir de l’une des sources disponibles dans VideoTexture :

VideoFFmpeg
Films, vidéos.
Fichiers vidéo, capture vidéo, streaming vidéo.
ImageFFmpeg
Images fixes.
Fichiers image, images du web.
ImageBuff
Image depuis la mémoire d’une application.
Pour des images générées par ordinateur, des programmes de dessin.
ImageViewport
Partie ou totalité du viewport (c-à-d le rendu de la caméra active, tel qu’affiché à l’écran).
ImageRender
Rendu d’une caméra non active.
ImageMix
Un mélange de deux des sources précédentes, ou plus.

Dans cet exemple, nous utilisons un simple fichier vidéo comme source. Le constructeur VideoFFmpeg prend en argument un nom de fichier. 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 = VideoTexture.VideoFFmpeg(movie)

Nous créons l’objet de source vidéo et l’assignons à l’attribut source de l’objet Texture, afin de le rendre lui aussi persistant, puisque l’objet Texture l’est déjà.

Notez que vous pouvez changer la source de Texture à tout moment. Supposons que vous voulez alterner entre deux films durant le jeu. Vous pouvez faire comme suit :

     GameLogic.mySources[0] = VideoTexture.VideoFFmpeg('movie1.avi')
     GameLogic.mySources[1] = VideoTexture.VideoFFmpeg('movie2.avi')

Puis assigner (et ré-assigner) la source au cours du jeu :

     GameLogic.video.source = GameLogic.mySources[movieSel]


Régler la source

La source VideoFFmpeg dispose de divers attributs pour contrôler l’affichage du film :

range
[début,fin] (floats).
Règle les temps de début et de fin de l’affichage de la vidéo, exprimés en secondes depuis le début. Par défaut, la vidéo entière.
repeat
(integer).
Nombre de répétitions de la vidéo, -1 pour une lecture en boucle infinie.
framerate
(float).
Framerate (nombre d’images par seconde) relatif, <1.0 pour ralentir, >1.0 pour accélérer.
scale
(bool).
Mettez-le à True (Vrai) pour utiliser l’algorithme de redimensionnement “nearest neighbour” (“voisin le plus proche”).
Les largeurs et hauteurs de texture doivent être des puissances de deux. Si ce n’est pas le cas, il faut la redimensionner. Par défaut, VideoTexture utilise la fonction gluScaleImage(), précise mais lente. De toute façon, mieux vaut redimensionner la vidéo à l’avance, afin que ce ne soit pas à faire pendant le jeu !
flip
(bool).
Réglez-le à True si l’image doit être inversée verticalement.
FFmpeg fournit toujours une image “tête en bas”, cet attribut est donc activé par défaut.
filter
Permet d’ajouter un filtre supplémentaire à la vidéo, avant de l’envoyer au GPU.
Assignez-y l’un des objets filtres de VideoTexture. Par défaut, l’image est envoyée non-modifiée au GPU. Si un canal alpha est présent dans la vidéo, il sera également automatiquement récupéré et envoyé au GPU.

Nous allons simplement mettre l’attribut scale à True, car gluScaleImage() est vraiment trop lente pour de la vidéo en temps réel. Dans le cas où la vidéo a déjà des dimensions puissances de deux, cela n’a aucun effet.

     GameLogic.video.source.scale = True


Jouer la vidéo

Nous sommes maintenant prêt à jouer la vidéo :

     GameLogic.video.source.play()

La lecture de la vidéo n’est pas un processus en tâche de fond : il ne se produit que lorsque vous rafraîchissez la texture. Nous avons donc besoin d’un autre script qui s’exécute toutes les images 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 aucun effet. L’argument de refresh() est un drapeau qui indique si la texture devrait être recalculée lors du prochain rafraîchissement. Pour afficher une vidéo, vous avez vraiment intérêt à le mettre à True.

Processus avancés

L’argument à True de la méthode Texture.refresh() invalide simplement le tampon image après l’avoir envoyé au GPU, afin qu’à l’image suivante, une nouvelle image soit chargée depuis la source. Il a pour effet de bord de rendre l’image inaccessible depuis Python. Vous pouvez également le faire manuellement en appelant directement la méthode refresh() de la source.

Voici quelques idées de processus avancés :

  • Utiliser le tampon image dans Python (cela n’affecte pas la Texture) :
     GameLogic.video.refresh(False)
     image = GameLogic.video.source.image
     # image est un tampon de chaîne binaire (pixels RGBA, organisés ligne par ligne).
     # ... Utilisez image...
     # Invalider image pour l'image suivante.
     GameLogic.video.source.refresh()
  • Charger l’image depuis la source, pour un travail dans Python, et sans l’envoyer au GPU :
     # Notez que nous n’appelons meme pas refresh sur la Texture
     # Nous pourrions aussi créer juste un objet source, sans objet Texture.
     image = GameLogic.video.source.image
     # ... Utilisez image...
     GameLogic.video.source.refresh()


Télécharger la démo

Vous trouverez la démo ici.

Démos avancées

Voici une démo qui illustre l’utilisation de deux vidéos, alternativement sur la même texture. Notez qu’elle requiert un fichier vidéo supplémentaire, la bande annonce de Elephant Dream. Vous pouvez le remplacer par un autre fichier avec lequel vous voulez lancer la démo.

Voici une démo qui illustre l’utilisation de la source ImageMix. ImageMix est une source qui à besoin d’autres sources, qui peuvent être de n’importe quelle type proposé par Texture, comme VideoFFmpeg, ImageFFmpeg ou ImageRender. Vous les assignez avec setSource(), et les pondérez avec setWeight(). Faites attention à ces poids, il s’agit de valeurs short (comprises entre 0 et 255), et la somme de tous les poids devrait être égale à 255. ImageMix va alors mélanger toutes ses sources, en fonction de leur pondération respective. Les sources doivent toutes avoir les même dimensions (après réduction aux dimensions puissances de 2 les plus proches). Si ce n’est pas le cas, vous aurez une erreur Python sur la console.