Sites


Blender pour le jeu video

Afficher plusieurs point de vues

En fonction du type de jeu et du type d'interactivité, il est possible et parfois même souhaitable d'avoir plusieurs points de vues affichés dans la même fenêtre. Par exemple, lorsque le jeu propose à deux joueurs de s'affronter dans un mode appelé écran partagé ou que nous désirons afficher plusieurs points de vue sur une même scène pour créer des effets graphiques intéressants.

Dans les faits, nous installerons deux caméras dans notre scène avec l'intention d'afficher ces deux points de vue dans la fenêtre principale, qui pour l'occasion sera divisée verticalement en deux parties égales.

Écran partagé

Le terme technique qui définit la zone d'affichage du jeu dans l'écran est le viewport. Il n'existe malheureusement pas de logic brick pour activer ces fonctionnalités, nous utiliserons donc un script Python.

partage d'ecran ou split-screen, setup

Le script peut être activé à partir de n'importe quel objet et doit être exécuté juste une fois : une fois en place les viewport persistent jusqu'à ce qu'ils soit supprimés explicitement. Le script doit désigner les caméras qui se partageront l'écran et définir les zones d'affichage pour chacune.

Voici le script, que nous détaillerons ensuite ligne par ligne.

from bge import logic, render
# Recuperer la scene
 scene = logic.getCurrentScene()
# Recuperer les cameras a partir de leur nom
 cam1 = scene.objects["Camera1"]
 cam2 = scene.objects["Camera2"]
# Recuperer la taille de la fenetre de jeu
 largeur = int(render.getWindowWidth())
 hauteur = int(render.getWindowHeight())
# Activer le viewport sur la Camera1
 cam1.useViewport = True
 cam1.setViewport(0, 0, int(largeur/2), hauteur)
# Activer le viewport sur la Camera2
 cam2.useViewport = True
 cam2.setViewport(int(largeur/2), 0, largeur, hauteur)

Après l'import des modules Python nécessaires, nous récupérons la scène dans laquelle se trouve l'objet.

 scene = logic.getCurrentScene()

Cet objet scene nous permet ensuite de récupérer les deux caméras grâce à leurs noms. Dans notre cas, nous avons au préalable choisi d'appeler les caméras Camera1 et Camera2.

cam1 = scene.objects["Camera1"] 
cam2 = scene.objects["Camera2"]

Il faut ensuite récupérer la taille de la fenêtre dans laquelle s'affiche le jeu. Que que le joueur soit en plein écran ou pas et que nous ayons défini une taille de fenêtre fixe ou pas, il est préférable de récupérer cette valeur directement par du code Python. C'est une méthode plus souple et plus sûre pour avoir toujours un écran partagé proportionné.

largeur = int(render.getWindowWidth())
hauteur = int(render.getWindowHeight())

Dans l'exercice, nous cherchons à diviser l'écran verticalement en deux parties égales. Camera1 utilise le système de viewport et affiche son point de vue dans un rectangle qui occupe la moitié gauche de l'écran. Camera2 suit le même principe, mais dans la moitié droite.

vue du positionnement des deux caméras

La méthode setViewport() ne tolère que des nombres entiers dans ses paramètres, c'est-à-dire les mesures en pixel des limites du rectangle dans lequel s'affiche la caméra. Attention, ces paramètres doivent suivre un ordre très précis : gauche, bas, droite, haut. Ce script indique que la première caméra prend toute la moitié gauche de l'écran.

cam1.useViewport = True 
cam1.setViewport(0, 0, int(largeur/2), hauteur) 

La deuxième caméra remplit l'espace restant.

cam2.useViewport = True cam2.setViewport(int(largeur/2), 0, largeur, hauteur)  

En utilisant les valeurs de hauteur et de largeur de notre fenêtre de jeu, nous nous assurons ainsi de remplir tout l'espace de cette même fenêtre.

copie d ecran du partage d ecran fonctionnel

Voici quelques détails techniques à propos des viewports qu'il est utile de connaître:

  • Si nous laissons la caméra courante inchangée et que nous activons une caméra secondaire en mode viewport, la caméra principale continue de remplir tout l'écran et la caméra secondaire vient en surimpression dans la zone du viewport.
  • Il n'est pas obligatoire que les viewports soient jointifs comme dans notre exemple. Ils peuvent se chevaucher mais dans ce cas l'ordre de chevauchement n'est pas prévisible. Heureusement l'objet caméra possède une méthode setOnTop qui permet de placer cette caméra au sommet de l'empilement de viewports. En appliquant cette méthode sur toutes les caméras en commençant par celle qui doit être la plus en arrière, nous pouvons forcer un ordre de chevauchement.
  • Les viewports n'effacent pas l'image déjà présente dans le frame buffer; ils s'affichent toujours en surimpression. Dans le cas de viewports jointifs comme dans notre exemple, cela ne porte pas à conséquence. Mais en cas de chevauchement, avec la caméra principale ou avec un autre viewport, l'image sous-jacente sera visible partout où il n'y a pas d'objet dans le viewport.

Pour supprimer un viewport, il suffit de mettre la propriété useViewport de la caméra correspondante à False.

Fichier référence : ecran_partage-panda.blend

Le miroir

Paramétrage du mirroir sous le Blender Game Engine

Le miroir est un cas particulier qui peut être utile par exemple dans le cas d'un jeu de voiture pour simuler un rétroviseur. L'idée est d'afficher le point de vue d'une caméra de la scène comme une texture d'un objet.

Pour cela, nous utiliserons un script Python écrit comme suit :

from bge import texture
from bge import logic

def createMirror(cont):
    obj = cont.owner
    scene = logic.getCurrentScene()
    observer = scene.objects["Camera"]

    # Obtention de l'index de la texture initiale
    ID = texture.materialID(obj, 'IMoriginal.png')

    # Creation de la nouvelle texture
    object_texture = texture.Texture(obj, ID)

    # il faut garder une reference permanente
    obj.attrDict["tex"] = object_texture

    # creons le miroir
    mirror_source = texture.ImageMirror(scene,observer,obj,ID)

    # changeons la couleur de fond du miroir (RGBA)
    mirror_source.background = [50,0,0,255]

    # echange de texture
    object_texture.source = mirror_source

    # remplacement dans le GPU
    object_texture.refresh(True)
    
def runMirror(cont):
    obj = cont.owner
    if "tex" in obj.attrDict:
        # rafraichissons l'image du miroir
        obj.attrDict["tex"].refresh(True)
        
def removeMirror(cont):
    obj = cont.owner
    try:
        del obj.attrDict["tex"]
    except:
        pass

À deux différences près, ce script ressemble beaucoup à celui présenté dans le chapitre Matériaux dynamiques et textures animées de la section Développer l'univers du jeu.

L'objet image est de type ImageMirror :

mirror_source = texture.ImageMirror(scene,observer,obj,ID)

Le constructeur requiert les paramètres suivants :

  • la scène courante ;
  • l'objet qui observe le miroir (l'image du miroir est prise de son point de vue), généralement ce sera la caméra courante pour que le reflet ait l'air naturel ;
  • l'objet sur lequel l'effet miroir sera projeté ;
  • l'ID du matériel dont la texture sera remplacée.

Il est nécessaire de rafraîchir l'image du miroir fréquemment pour tenir compte du déplacement de l'observateur. Ceci est réalisé par la fonction runMirror qui doit être exécuté à chaque frame ou chaque fois que l'observateur bouge.

Mirroir fonctionnel sous le Blender Game Engine

Pour réaliser cet effet miroir, le BGE effectue un rendu spécial à partir d'un point symétriquement opposé à l'observateur par rapport au miroir. Ce rendu est appliqué à l'objet via la texture. Pour que le reflet ne soit pas déformé, il faut que la texture recouvre au mieux la surface de l'objet miroir. Nous obtiendrons ce résultat grâce à la fonction UV mapping > Project from View (Bounds).

Fichier référence : mirroir-panda.blend

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.