Master Informatique 2017-2018
M3DS



TP 05 : Modélisation

1  Introduction

Ce tp permet de pratiquer 2 aspects de la modélisation 3D : les arêtes ailées et les BSP.

Les 2 parties sont totalement indépendantes (2 squelettes distincts). Attention : la partie "arêtes ailées" est beaucoup plus courte que la partie BSP.

2  Winged-Edges


Exercice 1. Introduction

Les objets winged-edges manipulés proviennent de fichiers obj. Il y a 3 objets disponibles (cliquez sur "Next Object" pour passer de l’un à l’autre : cube, vache, bonhomme). Le bouton "Draw OBJ" correspond à un affichage direct des données de l’OBJ (similaire au tracé effectué lors du TP02).

Vous pouvez contrôler le point de vue avec les touches bas/haut/droite/gauche/click gauche+glisser pour tourner/molette pour zoomer.

Leur construction en winged edges est déjà assurée par le squelette et ont la représentation suivante (cf cours pour la structure d’un winged-edges) :

Pour les parcours demandés, vous utiliserez donc les méthodes des classes WVertex, WFace et WVertex (qui correspondent aux tables des arêtes ailées données en cours).


Exercice 2. Affichage

Question 1. Complétez WFace::draw(bool withNormal) qui se charge de tracer une face d’un winged edges : il s’agit de parcourir la face sommet par sommet (uniquement les sommets nécessaires) en alimentant le tableau position par des push_back(un_Vector3) (ne vous préoccupez pas du calcul des normales pour l’instant).

Testez sur les objets disponibles : il faut cliquer sur le bouton "WFace::draw (wire)" pour provoquer l’affichage du winged edges face par face avec cette méthode WFace::draw que vous venez de compléter (on passe d’un objet à l’autre avec le bouton "Next Object"; vous pouvez naviguer dans la scène (touches gauche/droite/haut/bas/click gauche+move pour tourner/molette pour zoomer)).

Remarque :

Question 2. On travaille maintenant au niveau du sommet dans WVertex.cpp. Dans WVertex::computeNormal() vous devez calculer la normale average affectée au sommet this en moyennant toutes les normales des faces qui sont incidentes à this (i.e. toutes les faces qui ont le sommet this en commun).

Pour cela, on parcourt les faces autour du sommet en exploitant la structure du winged-edges (on suppose la surface sans bords pour pouvoir faire le tour complet); on moyenne alors toutes les normales des faces pour l’attribuer au sommet (ne pas oublier de normer à la fin de la procédure).

Testez en cliquant sur le bouton "Show/Hide Vertex Normal" qui provoque l’appel à votre WVertex::computeNormal() pour chaque sommet de l’objet et trace des segments rouges pour visualiser chacune de ces normales.

Notez que sur le personnage, cela ne fonctionne pas (peut être sanctionné par un segmentation fault). Nous étudions ce souci 2 questions plus loin.

Question 3. Nous exploitons ces normales pour l’éclairage : il suffit de revenir sur WFace::draw(bool withNormal) puis d’affecter le tableau normal avec des push_back comme pour les positions (l’appel à v->normal() permet de récupérer la normale calculée à la question précédente).

Testez (en cliquant sur "WFace::draw (light)"). Le cas du cube vous parait il correct ? (expliquez en 2 lignes dans le Readme.txt).

Question 4. Avec le bonhomme, cela ne fonctionne pas : quel est le problème selon vous ? (dans quel cas votre parcours est incorrect ?). Répondez en 2 lignes dans le Readme.txt.

Question 5. Bonus (faites la deuxième partie sur les BSP en priorité avant de répondre à cette question).

Modifiez alors le parcours pour corriger le problème.

3  BSP

Reprenez l’archive bsp.zip sur le portail.

Compilez et exécutez : vous voyez un polygone et un ensemble de points. Vous pouvez naviguer dans la scène (click gauche+glisser/bas/haut/gauche/droite/molette).


Exercice 3. Signe et intersection

Le premier objectif est de déterminer de quel coté se trouve un point par rapport à une face de l’objet.

On commence par travailler dans le fichier FaceBSP.cpp. Cette classe représente une face de la scène par un tableau de sommets (cf attribut vector<VertexBSP *> _tabVertex dans FaceBSP.h). La classe VertexBSP contient les coordonnées de chaque sommet (x,y,z) (accessible par la méthode Vector3 VertexBSP::point()).

Question 1. Complétez la méthode ESign FaceBSP::sign(const Vector3 &p) qui donne le signe du point p par rapport à la face this (il suffit de faire la localisation d’un point par rapport à un plan par produit scalaire). Les commentaires dans le source vous donnent les méthodes/fonctions qui peuvent être utiles au calcul du résultat.

Testez (click sur "Face Side") : les points sont colorés suivant leur signe : les points doivent apparaitre rouges du coté vert du polygone, et verts du coté rouge (s’ils apparaissent bleus, c’est que l’affectation de signe n’a pas été faite).

Question 2. Complétez Vector3 FaceBSP::intersection(const Vector3 &p1,const Vector3 &p2) qui retourne le point résultant de l’intersection entre le segment [p1p2] et le plan porteur de la facette this. Précondition : p1 et p2 sont de part et d’autre de la facette (donc l’intersection existe nécessairement).

Testez en cliquant sur "Segment Intersection" et vérifiez visuellement : vous devez voir apparaître les points d’intersection de chaque segment en bleu au niveau du plan (cela peut "déborder" du polygone : il s’agit d’une intersection du plan du polygone)


Exercice 4. Découpe d’une face

Question 1. On continue à travailler dans FaceBSP.cpp pour y compléter la méthode FaceBSP::separe : elle coupe la face this par la face f pour construire les faces négatives et positives de this (l’une d’elle peut être vide s’il n’y a pas de découpe). En vous référant aux commentaires du source, complétez cette méthode (appliquez par exemple la technique vue en cours).

Testez en appuyant sur "Face cutting" : vous devez remarquer la découpe sur l’une des deux faces affichées (la plus petite face a coupé la plus grande).


Exercice 5. Création et affichage du BSP
On travaille à présent dans ObjectBSP.cpp. Cette classe contient et gère une structure d’arbre binaire de classe TreeBSP. Il reste à implémenter la construction et l’affichage de cet arbre BSP.

Question 1. Il faut complêter la méthode statique (i.e. méthode de classe) ObjectBSP::consBSP qui construit récursivement un arbre BSP à partir du tableau de faces tabFace. Les commentaires indiquent les méthodes utiles.

Exécutez : vous pouvez vérifier visuellement la découpe correcte en cliquant sur "Build BSP" (affichage de l’ensemble des faces du BSP, et sans élimination des parties cachées; si vous cliquer sur "BSP Visualisation" vous visualisez les faces avec élimination par depth buffer). Vous devez obtenir 6 faces sur cet exemple.

Question 2. Complétez la méthode ObjectBSP::drawBSP(TreeBSP *tree,const Vector3 &eye) qui effectue la méthode du peintre (i.e. afficher les faces de la plus éloignée à la plus proche) récursivement sur tree selon le point d’observation eye (position de la caméra) : il suffit de parcourir l’arbre de manière infixe en testant le signe de eye (cf cours).

Testez en cliquant 2 fois sur "BSP Visualisation" (après avoir fait "Build BSP"). Cela provoque l’affichage en appelant votre méthode du peintre : vous pouvez vérifier la méthode appelée avec le message affiché en bas de fenêtre ("without hidden removal/depth/painter"). Vous devez voir le résultat de la construction BSP avec une élimination des parties cachées correcte (comparez avec l’élimination par depth buffer).

Question 3. On teste à présent avec un objet plus complexe (modifiez le _bsp3.read("simple_nontri.obj"); du constructeur GLApplication::GLApplication() avec "wolf.obj" par exemple). Testez la construction.

Testez la visualisation (cliquer sur "BSP Build" puis "BSP Visualisation").

Il est probable que vous obteniez quelques faces mal construites (problème abordé dans la question suivante).

Avec erreurs éventuellesSans erreurs

Question 4. Il faut modifier la méthode FaceBSP::intersection de façon à rendre robuste le calcul d’intersection : cette méthode pré-suppose en effet qu’il y a une intersection lorsque les 2 points p1 et p2 d’une arête sont de part et d’autre du plan (i.e. de signe distincts); c’est-à-dire lorsqu’on sait que [p1p2] intersecte la face avec une intersection entre p1 et p2.

Or le calcul numérique peut être instable si p1p2 est "presque" parallèle au plan. Corrigez alors le calcul pour forcer une intersection entre p1 et p2 (ce principe revient souvent pour rendre robuste/déterministe les algorithmes de programmation 3D : on impose éventuellement le calcul pour contrer les éventuelles erreurs numériques et respecter ainsi les invariants).

Question 5. Cliquez sur le bouton "Transparency", puis visualisez avec une élimination par depth buffer, puis visualisez avec une élimination par peintre (passez de l’un à l’autre en cliquant plusieurs fois sur "BSP Visualisation"). La transparence est obtenue dans les 2 cas exactement de la même façon : on mélange la couleur du fragment source de chaque pixel tracé avec la couleur du fragment destination (i.e. on "voit" la couleur destination "à travers" la source). Expliquez en 3 lignes maxi dans le Readme.txt d’où provient le défaut pour l’élimination par depth buffer.

Transparence avec depthTransparence avec peintre

Ce document a été traduit de LATEX par HEVEA