Solution

Transcription

Solution
INF5071 — Infographie
Automne 2016
Solution du devoir 1
Auteur : Alexandre Blondin Massé
1. Supposons qu’une application graphique utilise des images de dimensions 64 × 32 pixels2
pour représenter des tuiles en projection isométrique (dans le dessin ci-bas, un exemple
d’image contenant une tuile est identifié par un rectangle bleu).
(a) (15 points) Expliquez comment calculer la position du coin supérieur gauche d’une
tuile 10 × 10 qu’on place dans une grille indexée comme l’illustre la grille ci-bas :
(0, 0)
9
9
(352, 192)
8
8
7
7
6
6
5
5
4
4
3
3
2
2
1
1
0
0
(640, 320)
Autrement dit, donnez le pseudocode d’une fonction
fonction CoinSupGauche(i, j : indices) : point
qui retourne la position que devrait occuper le coin supérieur gauche du rectangle
contenant la tuile aux indices i et j. Par exemple, on s’attend à ce que l’appel
CoinSupGauche(4, 2) retourne la valeur (352, 192) (voir le rectangle bleu dans
l’image ci-haut).
(b) (10 points) Dans la question ci-bas, nous avons supposé que toutes les tuiles se trouvaient à la même hauteur. Supposons que nous souhaitions également supporter
la possibilité d’afficher des tuiles plus hautes que d’autres. En utilisant des notions d’algèbres linéaire et vectorielle, expliquez de quelle façon vous traiteriez cette
situation et montrez en particulier que certaines tuiles à des hauteurs différentes
pourraient apparaı̂tre exactement au même endroit.
(c) (5 points boni ) Le concepteur principal d’un jeu appelé Super Hexagon est auteur
d’un autre jeu qui exploite le fait que différentes tuiles à des hauteurs différentes
apparaissent au même endroit. Quel est le nom de ce jeu et qui en est l’auteur ?
1/10
INF5071 — Infographie
Automne 2016
Solution: (a) Reprenons l’image de l’énoncé et indiquons à l’aide de points bleus
tous les coins que nous souhaitons atteindre (le rectangle bleu original a été laissé
pour faciliter la visualisation) :
(0, 0)
9
9
8
8
7
7
6
6
5
5
4
4
3
3
2
~v1
0
~u
2
1
0
(640, 320)
Nous constatons donc que l’ensemble des points bleus peut être engendré à l’aide
de deux vecteurs ~u et ~v (identifiés en rouge dans l’image). Plus précisément, les
coordonnées des points bleus sont donnés par
O + i~u + j~v ,
où 0 ≤ i, j ≤ 9 et où O est le point d’où originent les vecteurs ~u et ~v .
Il ne reste qu’à calculer les composantes de ces deux vecteurs et les coordonnées du
point O. Tout d’abord, on constate que O = (320 − 32, 320 − 32) = (288, 288). De
plus,
~u = (32, −16) et ~v = (−32, −16)
et donc
O + i~u + j~v = (288, 288) + i(32, −16) + j(−32, −16)
= (288 + 32i − 32j, 288 − 16i − 16j)
En pseudocode, cela donne
1: fonction CoinSupGauche(i, j : indices) : point
2:
retourner (288 + 32i − 32j, 288 − 16i − 16j)
3: fin fonction
(b) Comme il a été mentionné dans la partie (a), les tuiles peuvent être engendrés
par la base vectorielle formée des vecteurs ~u = (32, −16) et ~v = (−32, −16). Si on
souhaitait introduire une notion de hauteurs, nous pourrions la représenter par un
troisième vecteur w
~ qui devrait être orienté verticalement vers le haut, par exemple
2/10
INF5071 — Infographie
Automne 2016
w
~ = (0, −32) ou w
~ = (0, −16) (il faut choisir ce qui correspond à un déplacement
d’une unité vers le haut). En suivant la même logique qu’en (a), nous pourrions
donc générer n’importe quelle tuile, peu importe la hauteur. Par contre, une limite
de cette approche est que certaines tuiles distinctes apparaı̂traient exactement au
même endroit. Par exemple, si on prend w
~ = (0, −32), alors les tuiles d’indices
(i, j, k) = (0, 0, 1) et (i, j, k) = (1, 1, 0) seraient confondues. L’explication de ce
phénomène est simple : il n’est pas possible de former un ensemble de trois vecteurs
linéairement indépendants (ici, ~u, ~v et w)
~ dans un espace de dimension 2. C’est donc
une limitation de la projection isométrique, qui est partiellement réglée lorsqu’on
utilise une projection perspective !
(c) L’auteur du jeu Super Hexagon s’appelle Terry Cavanagh. Il a conçu un jeu
sorti en 2013, appelé Naya’s Quest, dont le “game play” exploite justement cette
observation.
2. (20 points) Supposez que les services suivants sont disponibles pour manipuler des maillages :
• M ← MaillageVide() construit un maillage vide et le stocke dans la variable M .
• M.AjouterSommet(p) ajoute un sommet dans le maillage M et dont les coordonnées sont données par le point p.
• M.AjouterArete(p1 , p2 ) ajoute une arête entre les sommets p1 et p2 dans le
maillage M . Si un ou les deux sommets n’existent pas dans la structure, une erreur
est signalée.
• M.AjouterFace(P ) ajoute une face dont les sommets sont donnés par la liste
P . Ces sommets doivent être énumérés dans l’ordre antihoraire lorsqu’on regarde
vers l’extérieur de la face. De plus, s’il n’y a pas d’arêtes entre deux sommets
consécutifs, une erreur est signalée.
Donnez le pseudocode d’une fonction dont l’en-tête est
fonction Grille(m, n : entiers positifs, d, e : réels) : maillage
et qui retourne un maillage modélisant une grille de m carrés par n carrés, dont l’épaisseur
est donnée par e et la distance entre les carrés de la grille est donnée par d. Autrement
dit, si vous implémentiez votre fonction dans un script Blender et que vous utilisiez les
paramètres m = 3, n = 4, e = 0.1 et d = 1.0, alors vous vous attendriez à obtenir un
maillage similaire à celui illustré dans l’image ci-bas.
Attention ! La topologie de votre maillage doit être bien définie. Autrement dit, aucune
erreur ne doit être signalée (vous devez donc d’abord ajouter les sommets, ensuite les
arêtes, puis finalement les faces) et vous devez vous assurer que c’est le côté visible des
faces (c’est-à-dire vers l’extérieur) qui est décrit en sens antihoraire.
3/10
INF5071 — Infographie
Automne 2016
Note : Vous pouvez utiliser la notation [p1 , p2 , p3 , p4 ] pour dénoter une liste qui contient
les quatre points p1 , p2 , p3 et p4 (autrement dit, vous pouvez utiliser des crochets pour
dénoter des listes). Aussi, bien que ce ne soit pas demandé dans la question, n’hésitez
pas à vérifier votre stratégie en l’implémentant comme un script Blender !
Voici une vue de face d’une portion de la grille avec les dimensions correspondantes :
e
d
4/10
INF5071 — Infographie
Automne 2016
Solution: Cette question n’est pas facile si on souhaite écrire un code compact. Ici,
je présente une solution la plus compacte possible. Pour cela, j’utilise une fonction
auxiliaire qui permet de construire un prisme rectangulaire selon les paramètres
suivants :
• (h, k, `) est le centre du prisme.
• (a, b, c) est un triplet représentant les “rayons” du prisme par rapport aux axes
x, y et z respectivement. Autrement dit, les 8 points du prisme sont données
par (h ± a/2, k ± b/2, ` ± c/2).
• sommets est un booléen qui indique si on doit ajouter ou non les sommets (pour
éviter de les ajouter s’ils y sont déjà).
• arêtes est un triplet de booléens qui indique les directions des arêtes à ajouter.
L’indice 0 correspond aux arêtes parallèles à l’axe x, l’indice 1 à celles parallèles
à l’axe y et l’indice 2 à celles parallèles à l’axe z.
• faces est un 6-tuplet de booléens indiquant quelles faces doivent être ajoutées
(pour éviter d’ajouter les faces intérieures). Les indices 0 et 1 correspondent
aux directions + et − de l’axe x, les indices 2 et 3 correspondent aux directions
+ et − de l’axe y et les indices 4 et 5 correspondent aux directions + et − de
l’axe z.
Voici donc la fonction en question :
fonction AjouterPrisme(M, h, k, `, a, b, c, sommets, arêtes, faces)
// On ajoute les sommets
si sommets alors
M.AjouterSommet((h − a, k − b, ` − c))
M.AjouterSommet((h − a, k − b, ` + c))
M.AjouterSommet((h − a, k + b, ` − c))
M.AjouterSommet((h − a, k + b, ` + c))
M.AjouterSommet((h − a, k − b, ` − c))
M.AjouterSommet((h − a, k − b, ` + c))
M.AjouterSommet((h − a, k + b, ` − c))
M.AjouterSommet((h − a, k + b, ` + c))
fin si
// Ensuite les arêtes
si arêtes[0] alors
M.AjouterAretes((h − a, k − b, ` − c), (h + a, k − b, ` − c))
M.AjouterAretes((h − a, k − b, ` + c), (h + a, k − b, ` + c))
M.AjouterAretes((h − a, k + b, ` − c), (h + a, k + b, ` − c))
M.AjouterAretes((h − a, k + b, ` + c), (h + a, k + b, ` + c))
fin si
si arêtes[1] alors
M.AjouterAretes((h − a, k − b, ` − c), (h − a, k + b, ` − c))
M.AjouterAretes((h − a, k − b, ` + c), (h − a, k + b, ` + c))
M.AjouterAretes((h + a, k − b, ` − c), (h + a, k + b, ` − c))
M.AjouterAretes((h + a, k − b, ` + c), (h + a, k + b, ` + c))
fin si
si arêtes[2] alors
M.AjouterAretes((h − a, k − b, ` − c), (h − a, k − b, ` + c))
5/10
INF5071 — Infographie
Automne 2016
M.AjouterAretes((h − a, k + b, ` − c), (h − a, k + b, ` + c))
M.AjouterAretes((h + a, k − b, ` − c), (h + a, k − b, ` + c))
M.AjouterAretes((h + a, k + b, ` − c), (h + a, k + b, ` + c))
fin si
// Finalement, les faces, décrites en sens antihoraire
si faces[0] alors
M.AjouterFace([(h − a, k − b, ` − c), (h − a, k + b, ` − c), (h − a, k + b, ` + c), (h − a, k + b, ` + c)])
fin si
si faces[1] alors
M.AjouterFace([(h + a, k − b, ` − c), (h + a, k − b, ` + c), (h + a, k + b, ` + c), (h + a, k + b, ` − c)])
fin si
si faces[2] alors
M.AjouterFace([(h − a, k − b, ` − c), (h + a, k − b, ` − c), (h + a, k − b, ` + c), (h − a, k − b, ` + c)])
fin si
si faces[3] alors
M.AjouterFace([(h − a, k + b, ` − c), (h − a, k + b, ` + c), (h + a, k + b, ` + c), (h + a, k + b, ` − c)])
fin si
si faces[4] alors
M.AjouterFace([(h − a, k − b, ` − c), (h − a, k + b, ` − c), (h + a, k + b, ` − c), (h + a, k − b, ` − c)])
fin si
si faces[5] alors
M.AjouterFace([(h − a, k − b, ` + c), (h + a, k − b, ` + c), (h + a, k + b, ` + c), (h − a, k + b, ` + c)])
fin si
fin fonction
Nous pouvons maintenant construire le maillage complet. Notons que si nous insérons
d’abord les petits cubes (aux intersections), alors il n’y a plus besoin d’ajouter de
sommets, et il ne manque que les arêtes entre les cubes. On obtient donc :
fonction Grille(m, n : entiers positifs, d, e : réels)
M ← MaillageVide()
// On ajoute d’abord les petits cubes
pour i ← 0, 1, . . . , m faire
pour j ← 0, 1, . . . , n faire
arêtes ← (vrai, vrai, vrai)
faces ← (faux, faux, faux, faux, faux, faux)
faces[0] ← j = 0
faces[1] ← j = m
faces[4] ← i = n
faces[5] ← i = 0
AjouterPrisme(M, j(d + e), 0, i(d + e), e/2, e/2, e/2, vrai, arêtes, faces)
fin pour
fin pour
// Puis les prismes entre les petits cubes
pour i ← 0, 1, . . . , m faire
pour j ← 0, 1, . . . , n faire
si i 6= m alors
arêtes ← (vrai, faux, faux)
faces ← (faux, faux, vrai, vrai, vrai, vrai)
AjouterPrisme(M, j(d + e), 0, (i + 1/2)(d + e), e/2, e/2, (d + e)/2, faux, arêtes, faces)
fin si
si j 6= n alors
arêtes ← (faux, faux, vrai)
faces ← (vrai, vrai, vrai, vrai, faux, faux)
AjouterPrisme(M, (j + 1/2)(d + e), 0, i(d + e), (d + e)/2, e/2, e/2, faux, arêtes, faces)
fin si
fin pour
fin pour
retourner M
fin fonction
3. (20 points) Considérez la texture suivante T décrite par une image de dimensions 512 ×
6/10
INF5071 — Infographie
Automne 2016
768 pixels2
(0, 0)
1
2
3
4
5
6
(768, 512)
Supposez que la couleur du pixel de la i-ième ligne et j-ième colonne est donné par
T [i][j] et supposez que vous avez un cube C dont le centre est donné par C.centre
et la demi-longueur d’un côté est C.rayon. Donnez le pseudocode d’une fonction dont
l’en-tête est
fonction CouleurPixel(p : point, C : cube, T : texture) : couleur
qui indique pour chaque point p qui se trouve sur le cube C, la couleur du pixel qu’il
devrait avoir. Il y a plusieurs solutions possibles à ce problème, mais vous devez respecter
les contraintes suivantes :
• Chacun des 6 chiffres doit apparaı̂tre sur une face;
• Deux faces opposées doivent avoir une somme de 7.
Remarque : vous n’avez pas à valider si p est bien un point qui se trouve sur le cube,
vous pouvez supposer que c’est toujours le cas.
Solution: Soit (h, k, `) le centre du cube C et r son rayon. Notons que les huit
sommets du cube sont donnés par les points
(h, k, `) + r(±1, ±1, ±1).
Une autre façon de voir le cube C est de remarquer qu’il s’agit de la région comprise
à l’intérieur des six plans d’équations cartésiennes
x = h − r,
x = h + r,
y = k − r,
y = k + r,
z =`−r
et z = ` + r.
Pour savoir si un point se trouve sur une face donnée, il suffit donc de vérifier s’il
satisfait une de ces équations. Évidemment, certains points (les huit sommets et les
7/10
INF5071 — Infographie
Automne 2016
points le long des arêtes du cube) se trouvent sur plusieurs faces. Dans ce cas, on
le traite comme s’il se trouvait sur n’importe laquelle des faces (ça n’a pas vraiment
d’importance). Bref, nous pouvons maintenant écrire le pseudocode d’une fonction
qui indique le numéro de la face sur laquelle se trouve n’importe quel point donné
(pour simplifier le pseudocode plus tard, nous numérotons les faces de 0 à 5 plutôt
que de 1 à 6) :
1: fonction NuméroFace(C : cube, p : point) : entier
2:
(h, k, `) ← C.centre
3:
r ← C.rayon
4:
si p.x = h − r alors retourner 0
5:
sinon si p.x = h + r alors retourner 5
6:
sinon si p.y = k − r alors retourner 1
7:
sinon si p.y = k + r alors retourner 4
8:
sinon si p.z = ` − r alors retourner 2
9:
sinon si p.z = ` + r alors retourner 3
10:
sinon Erreur : Le point p n’est pas sur C.
11:
fin si
12: fin fonction
Maintenant, remarquons que la texture T est divisée en exactement 6 carrés de
dimensions 256 × 256. Lorsque nous prenons un point quelconque p sur une face
de C, nous devons lui faire correspondre un point p0 dans T qui se trouve entre 0
et 255 (puis ensuite, on décale le résultat pour atteindre le bon carré parmi les 6
disponibles). Nous devons donc, pour cela, calculer la distance relative du point p
par rapport à un coin de la face sur laquelle il se trouve. La fonction suivante permet
d’établir cette correspondance :
1: fonction PositionRelative(C : cube, p : point) : couple de réels
2:
(h, k, `) ← C.centre
3:
r ← C.rayon
4:
si p.x = h − r ou p.x = h + r alors
5:
retourner ((p.y − k)/2r, (p.z − `)/2r)
6:
sinon si p.y = k − r ou p.y = k + r alors
7:
retourner ((p.x − h)/2r, (p.z − `)/2r)
8:
sinon si p.z = ` − r ou p.z = ` + r alors
9:
retourner ((p.x − h)/2r, (p.y − k)/2r)
10:
sinon
11:
Erreur : Le point p n’est pas sur C.
12:
fin si
13: fin fonction
Il ne reste qu’à combiner les deux fonctions en une seule :
1: fonction CouleurPixel(p : point, C : cube, T : texture) : couleur
2:
f ← NuméroFace(C, p)
8/10
INF5071 — Infographie
3:
4:
5:
6:
7:
Automne 2016
t ← PositionRelative(C, p)
i ← t.y + 256 · bf /3c
j ← t.x + 256 · (f mod 3)
retourner T [i][j]
fin fonction
4. (15 points) Deux objets décrivent une trajectoire rectiligne dans l’espace 3D selon les
fonctions vectorielles suivantes :
r~1 (t) = (t + 5, 2t − 2, 3t − 1)
r~2 (t) = (3t − 3, 2t − 2, 15 − t),
pour t ≥ 0, où t représente le temps en heures. Est-ce que les trajectoires des objets
s’intersectent ? Est-ce que les objets entreront en collision ? Si oui, à quel moment ?
Justifiez.
Solution: Vérifions d’abord si les objets entrent en collision. Si c’est le cas, alors
on aurait une valeur de t telle que r~1 (t) = r~2 (t), c’est-à-dire
(t + 5, 2t − 2, 3t − 1) = (3t − 3, 2t − 2, 15 − t).
Comme les premières composantes sont égales, on aurait donc t + 5 = 3t − 3, c’està-dire 8 = 2t, ce qui entraı̂ne t = 4. Ainsi, s’il y a une collision, c’est nécessairement
quand t = 4. Voyons quels sont les positions des deux objets en t = 4. On obtient
r~1 (4) = (9, 6, 11)
r~2 (4) = (9, 6, 11),
ce qui confirme qu’il y a bien collision après 4 secondes et que les trajectoires se
croisent.
5. (20 points) Considérez un cube dont les 8 sommets sont (±1, ±1, 1 ± 1) et qui repose sur
le plan z = 0. Une source de lumière se trouve en position (4, 4, 2) et éclaire tout point
de l’espace avec la même intensité, peu importe la distance (s’il existe un d’obstacle entre
le point et la source de lumière, alors la lumière ne parvient pas au point). Décrivez
la forme de l’ombre induite par le cube sur le plan et calculez son aire. Remarque :
N’hésitez pas à joindre un schéma de la situation pour mieux expliquer votre réponse.
Solution: Voici une illustration de la scène rendue par Blender :
9/10
INF5071 — Infographie
Automne 2016
Même en éloignant la caméra, on s’aperçoit que l’ombre est infinie et donc que son
aire est infinie. Décrivons maintenant sa forme. Le plus facile est de prendre une
vue de haut de la même scène. Voici ce qu’on obtient :
Noter que la face supérieure du cube apparaı̂t en noir puisqu’elle n’est pas éclairée
par la lumière. La lumière est donc projetée sur le point (4, 4, 0). Il ne reste qu’à
décrire le contour de la région ombrée. Tout d’abord, il y a le segment qui relie les
points (−1, 1, 0) et (−1, −1, 0) ainsi que le segment qui relie (−1, −1, 0) et (1, −1, 0).
Finalement, il y a les droites de vecteurs directeurs
v~1 = (−1, 1, 0) − (4, 4, 0) = (−5, −3, 0) et v~2 = (1, −1, 0) − (4, 4, 0) = (−3, −5, 0)
passant par le point (4, 4, 0). Plus précisément, ce sont les droites d’équations
(x, y, z) = (4, 4, 0) + t(−5, −3, 0) et (x, y, z) = (4, 4, 0) + t(−3, −5, 0).
10/10

Documents pareils