M2 Image

TP1 - prise en main



Partie 1 :  installez gKit

cf la rubrique installation de la doc.

modifiez un des tutos, par exemple le tuto6 (version plutot "c") ou le tuto7 (version plutot "c++") pour afficher plusieurs objets, par exemple des cubes disposés sur une grille :



affichez le temps cpu et gpu (cf classe AppTime).

quelles remarques peut on faire sur le temps cpu et le temps gpu en fonction du nombre d'objets affichés ?
est ce que le temps d'affichage varie selon la position de la camera ? et le temps cpu ?

Partie 2 : et avec openGL ?

modifiez votre programme pour dessiner les objets directement avec openGL. Le mieux est de faire les modifications progressivement, en suivant les tuto9_shader et tuto9_buffer :
    1. utilisez le shader minimaliste du tuto9 pour dessiner vos objets, au lieu de laisser draw() le faire à votre place, (ou le tp 4 de l'année passée pour plus de détails)
    2. changez la couleur des objets...
    3. créez les buffers et configurez le vertex array object et dessiner directement

Partie 3 : animation et déformations


chargez 2 keyframes d'une animation : robot (quaternius)

on suppose que la première keyframe correspond au temps t= 0 et la 2ième au temps t= 1.
comment interpoler (linérairement) la position de chaque sommet en fonction du temps t, connaissant sa position à t= 0 et à t= 1 ?

écrivez le vertex shader qui réalise cette interpolation.
quelles informations sont nécessaires ?
comment les fournir au shader ?

modifiez votre shader et votre programme.

indication : float global_time() de window.h renvoie le temps écoulé depuis le lancement de l'application, en millisecondes.

bonus : chargez toutes les keyframes de l'animation et affichez les, en boucle.


Partie 4 : plusieurs matières

assets de quaternius

chaque triangle d'un Mesh est associé à une matière, cf la classe Material.
affichez vos objets en fonction de leurs matières. cf Mesh::mesh_materials() pour les recuperer. les indices des matieres des triangles sont dans Mesh::materials().

il existe bien sur plusieurs solutions. une solution courante consiste à trier les triangles par matiere, puis à afficher chaque groupe de triangles séparement, ce qui permet de modifier tous les paramètres (couleurs, textures, etc.) sans problèmes. c'est aussi la solution la plus couteuse pour le cpu.

est-il reellement nécessaire de faire plusieurs affichages ?
peut-on re-organiser les "informations" différemment pour afficher tous les triangles et leurs matieres, en une seule fois ?
testez votre solution et comparez.

et si les matieres utilisaient des textures en plus de couleurs / coefficients ?

indications :
    le fragment shader connait l'indice de la primitive qu'il dessine...
    on peut utiliser des tableaux d'uniforms : cf tuto_uniform_buffer attention à l'organisation mémoire des tableaux uniforms !!
    on peut ajouter des attributs aux sommets des triangles : pour configurer un attribut entier (l'indice de la matière par exemple), il faut utiliser glVertexAtttribIPointer(), au lieu de glVertexAttribPointer()
    on peut grouper plusieurs textures dans une seule plus grande : cf atlas de textures,
    il existe des tableaux de textures : cf GL_TEXTURE_2D_ARRAY


bonus :
peut on utiliser la meme strategie avec les matieres de plusieurs objets ? quelles seraient les contraintes à respecter ?
    on peut dessiner plusieurs objets avec un seul glDraw(), cf glDrawArraysInstanced() et glMultiDrawArraysIndirect()...
    qui gere les ressources openGL ? chaque objet ? la technique d'affichage ? faut-il creer une gestion centralisee ?


Partie 5 : et avec des ombres ?

pour déterminer qu'un point d'un triangle est à l'ombre, il faut commencer par dessiner les objets qui peuvent projetter une ombre depuis le point de vue du soleil / de la source de lumière.
Comment construire le point de vue et la projection ?

indication :
vous aurez peut etre besoin d'une projection orthographique

Transform Ortho( const float left, const float right, const float bottom, const float top, const float znear, const float zfar )
{
    float tx= - (right + left) / (right - left);
    float ty= - (top + bottom) / (top - bottom);
    float tz= - (zfar + znear) / (zfar - znear);
   
    return Transform(
        2.f / (right - left),                    0,                     0, tx,
                           0, 2.f / (top - bottom),                     0, ty,
        0,                                       0, -2.f / (zfar - znear), tz,
        0,                                       0,                     0, 1);
}

        cf glOrtho(), ou les détails de la construction sur scratchapixel.com, mais attention à l'organisation des matrices !!

écrire le zbuffer dans une texture.
vous aurez besoin de configurer et de dessiner dans un framebuffer object, ou fbo, cf tuto rendu multi-passses.

afficher les ombres.
il ne reste plus qu'à dessiner "normalement" depuis la camera et dans la fenêtre (associée au fbo 0).
modifiez vos fragment shaders pour récupérer dans le zbuffer la distance de l'objet visible et éclairé et comparez avec la profondeur du fragment.

indication : vous aurez besoin de Viewport() de mat.h pour la transformation du repère projectif vers le repère image du zbuffer.