II - Modélisation Lingo (créer Une bibliothèque
d'objets 3 D quadée)
Voici une série de fonctions permettant de calculer les
coordonnées x,y,z des coins des facettes d'un objet. Ces
fonctions retournent toutes une liste brute de coordonnées.
Le gestionnaire "vasY" décrit dans notre
précèdent article sait extraire ces coordonnées
et mobiliser les sprites requis. Après avoir disposé
un TRÈS grand nombre de sprites sur la scène (900
sprites ne seront pas de trop pour nos essais!) on modifiera une
seule ligne de ce gestionnaire ainsi :
on vasY
tout = definitUnMachinQuelconque (paramètres,
position)
UnSprite = 1
repeat with n = 1 to count(tout)
the pc1 of sprite UnSprite = [tout[n][1], tout[n][2], tout[n][3]]
the pc2 of sprite UnSprite = [tout[n+1][1], tout[n+1][2], tout[n+1][3]]
the pc3 of sprite UnSprite = [tout[n+2][1], tout[n+2][2], tout[n+2][3]]
...
LE CUBE
Un cube c'est une liste de points que l'on aura pas trop de mal
à placer dans un espace 3D. On décrira par exemple
la première face par 4 points.
Il importe de décrire ces points de façon continue
si l'on souhaite utiliser les quads car rappelons-le les quads c'est
une liste de coins pris un à un de telle sorte qu'ils font
le tour du bitmap. Nous plaçons notre cube au centre de l'axe
de repères. Soit pris un à un dans le sens horlogique :
lesPoints = definitUnCarre (cote)
-- on crée les autres cotÈs un à
un
unCote = [[-cote/2, -cote/2, -cote/2], [cote/2, -cote/2, -cote/2],
[cote/2, -cote/2, cote/2],[-cote/2, -cote/2, cote/2]]
repeat with n in unCote
add lesPoints , n
end repeat
unCote = [[cote/2, -cote/2, cote/2],[cote/2, cote/2, cote/2],[cote/2,
cote/2, -cote/2], [cote/2, -cote/2, -cote/2]]
repeat with n in unCote
add lesPoints , n
end repeat unCote = [[cote/2, cote/2, -cote/2], [-cote/2, cote/2,
-cote/2],[-cote/2, cote/2, cote/2], [cote/2, cote/2, cote/2]]
repeat with n in unCote
add lesPoints , n
end repeat
unCote = [[-cote/2, cote/2, -cote/2], [-cote/2, -cote/2, -cote/2],[-cote/2,
-cote/2, cote/2],[-cote/2, cote/2, cote/2]]
repeat with n in unCote
add lesPoints , n
end repeat unCote = [[-cote/2, -cote/2, cote/2], [cote/2, -cote/2,
cote/2], [cote/2, cote/2, cote/2], [-cote/2, cote/2, cote/2] ]
repeat with n in unCote
add lesPoints , n
end repeat
return lesPoints
end
On pourrait de même définir une pyramide (un cube
dont toutes les arrêtes supérieures se rejoignent au
centre). La méthode permettrait encore la définition
d'un tetraèdre régulier.
Nous verrons plus tard que cest mêmes objets peuvent être
créés à partir des métamorphoses du
cône (un pyramide = un cône à 4 facettes). Justement,
c'est le moment de nous interroger sur les moyens de modéliser
des formes arrondies.
Créer des formes arrondies
Le procédé mis en uvre ici pour calculer les
points à la base d'un cylindre sera réexploité
pour créer toute sorte de variantes... jusque la sphère.
On va utiliser ici les fonctions sinus et cosinus. Nous allons créer
chacun des points de la base par rÈvolution puis nous créerons
la profondeur par extrusion.
Rappel : pour connaître les coordonnées x,y d'un point
placé sur un cercle, on utilise l'angle que ce point fait
avec le centre. Dessinons un polygone ici de 8 cotés qui
fera la base de notre future cylindre. Pour connaître les
coordonnées du deuxième point b connaissant le rayon
R : x = R* COS(pi/4), y = R*SIN(pi/4)
Dès lors nous pouvons facilement mettre en place une routine
qui nous aide à générer les point c, d , e...
On choisira l'angle d'incrément en fonction du nombre de
facettes que l'on souhaite obtenir (résultat optimum avec
un nombre impair) :
LE CYLINDRE
Le rappel de cette simple règle nous permet donc de faire
ça :
on definitUnCylindre facettes, rayon, hauteur
increment = pi*2/facettes -- Rappel : pi*2
= un cercle complet
angle = 0
lesPoints = []
-- RÉVOLUTION
-- on fait tourner par incrément (selon facettes)
repeat while angle <= pi*2 - increment
a = point(cos(angle)*rayon,sin(angle)*rayon)
add lesPoints, a
angle = angle + increment
b = point(cos(angle)*rayon,sin(angle)*rayon)
add lesPoints, b
end repeat
-- on a maintenant une liste de points dÈfinissant
par couple les cotés au sol (ou à plat)
-- chaque point ‡ une position sur l'axe Z (hauteur totale / 2)
points3D = []
H = -hauteur/2
repeat with n in lesPoints
x = []
add x , n[1]
add x, n[2]
add x, H
add points3D, x
end repeat
-- EXTRUSION
-- chaque point a aussi un vis ‡ vis de l'autre cotÈ de l'axe
Z
-- on peut connaître ce point facilement mais on ne peut
l'ajouter simplement à la liste car on obtiendrait de nuds
!
-- l'ordre des points dans la liste doit être tel que nous
puissions les en extraire pour définir des quads
objet = []
H = hauteur/2
repeat with n = 1 to count(points3D)
add objet, points3D[n]
add objet, points3D[n+1] -- on reprend les
deux premiers points de la liste points3D
x = []
add x, points3D[n+1][1] -- on crée
le troisième point à partir des coordonnées
du deuxième
add x, points3D[n+1][2]
add x, H
add objet, x
x = []
add x, points3D[n][1] -- on crée
le quatrième point à partir des coordonnées
du premier
add x, points3D[n][2]
add x, H add objet, x
-- on évite ainsi de faire des nuds
avec les futurs quads !
n = n + 1 end repeat
return objet -- on connaît les coordonnÈes
(x,y,z) de chaque point de construction du cylindre
end
Pour réaliser un disque ou cercle plein, on reprend LA MÊME
routine de génération de points mais en lieu et place
d'une extrusion on va rassembler tous les points en vis a vis, au
centre du cercle (coordonnées 0,0).
-- R VOLUTION
-- on fait tourner par incrément (selon nombre de facettes
souhaité)
repeat while angle <= pi*2 - increment
a = point(cos(angle)*rayon,sin(angle)*rayon)
add lesPoints, a
angle = angle + increment
b = point(cos(angle)*rayon,sin(angle)*rayon)
add lesPoints, b
end repeat
-- on a maintenant une liste de points
dÈfinissant par couple les cotés au sol
-- on ajoute z pour obtenir des coordonnées
points3D = []
H = 0
repeat with n in lesPoints
x = [] add x , n[1]
add x, n[2]
add x, H
add points3D, x
end repeat
-- chaque point a aussi un vis ‡ vis AU
CENTRE DE L'AXE
objet = []
H = 0
repeat with n = 1 to count(points3D)
add objet, points3D[n]
add objet, points3D[n+1]
-- on reprend les deux premiers points de
la liste points3D
x = []
add x, 0
add x, 0
add x, H
add objet, x
-- on crée le troisième point
à partir des coordonnées du deuxième
x = []
add x, 0
add x, 0
add x, H
add objet, x
-- on crée le quatrième point
à partir des coordonnées du premier
-- on évite ainsi de faire des nuds
!
n = n + 1
end repeat
-- on connaît les coordonnÈes (x,y,z)
de chaque point de construction du cercle
return objet
end
Avec quelques modifications (nous vous laissons deviner lesquelles)
le cercle plein deviendrait un colimaçon.
LE CÔNE
Le procédé ROTATION/EXTRUSION est fructueux, il va
nous permettre de créer un cÙne (en relevant le point
central). une pyramide un tétraèdre régulier
pourront être créés de la même manière
en limitant le nombre de facettes. Le code Lingo ici est quasiment
identique au prÈcËdent. On ajoute seulement un paramètre
"position" qui permet de placer l'objet dans l'espace
relativement au centre absolu.
on definitUnCone facettes, rayon, hauteur, position --
position = [x,y,z]
repeat while angle <= pi*2 - increment
a = point(cos(angle)*rayon,sin(angle)*rayon)
add lesPoints, a
angle = angle + increment
b = point(cos(angle)*rayon,sin(angle)*rayon)
add lesPoints, b
end repeat
-- on a maintenant une liste de points
dÈfinissant par couple les cotés au sol
-- on ajoute Z
points3D = []
H = 0
repeat with n in lesPoints
x = []
add x , n[1]
add x, n[2]
add x, H
add points3D, x
end repeat
- EXTRUSION
-- chaque point a aussi un vis ‡ vis AU CENTRE DE L'AXE,
--ON RELÈVE CE POINT de la hauteur passée en paramËtre
afin de créer le cône
objet = []
H = -hauteur
repeat with n = 1 to count(points3D)
add objet, points3D[n]
add objet, points3D[n+1]
-- on reprend les deux premiers points de
la liste points3D
x = []
add x, 0
add x, 0
add x, H
add objet, x
-- on crée le troisième point
à partir des coordonnées du deuxième
x = []
add x, 0
add x, 0
add x, H
add objet, x
-- on crée le quatrième point
à partir des coordonnées du premier
n = n + 1
end repeat
--- maintenant pour placer l'objet :
toutPlace = []
repeat with n in objet
temp = []
add temp, n[1] + posX
add temp, n[2] + posY
add temp, n[3] + posZ
add toutPlace, temp
end repeat
return toutPlace
end
LA SPHÈRE
C'est en suivant le même principe que l'on va générer
la liste des points de la sphère. On va d'abord se doter
de la liste des points d'un demi cercle simple. Ce demi cercle devra
ensuite être pivoté. Ce qui nous donnera une liste
de point en vis à vis (le tout formant un quartier). on dupliquera
ce premier quartier plusieurs fois pour faire un tour complet et
créer la sphère.
on definitUneSphere facettes, rayon, position
posX = position[1]
posY = position[2]
posZ = position[3]
increment = pi/facettes
-- un demi cercle divisé par le nombre
de facettes voulues
-- NOTA ici avec pi/4 on obtiendrait un quart de cercle puis par
extrusion, une demi sphère.
angle = 0
lesPoints = []
-- RÉVOLUTION
repeat while angle <= pi - increment
a = point(cos(angle)*rayon,sin(angle)*rayon)
add lesPoints, a
angle = angle + increment
b = point(cos(angle)*rayon,sin(angle)*rayon)
add lesPoints, b
end repeat
-- on a maintenant une liste de points
dÈfinissant par couple les cotés au sol
-- chaque point ‡ une position sur l'axe Z, on l'en dote :
points3D = []
repeat with n in lesPoints
x = []
add x , n[1]
add x, n[2]
add x, 0
add points3D, x
end repeat
-- EXTRUSION
-- chaque point a aussi un vis ‡ vis de l'autre cotÈ de l'axe
Z
-- on le crÈe et on l'insËre auprËs de lui
-- mais pour le calculer on va faire tourner le système
de repères !
-- DONC exploiter nos fonctions de révolution
3D
objet = [] angleDuQuartier = pi*2/12
-- on fait tout le tour en 12 portions
=> chaque portion = 1/12 ème
nouvoMonde = rotationSelonAxeXDe (angleDuQuartier)
-- le monde a tourné
repeat with n = 1 to count(points3D)
add objet, points3D[n]
add objet, points3D[n+1]
-- d'abord les points initiaux
-- on reprend les deux premiers points de la liste points3D
-- puis les vis ‡ vis obtenus après
révolution partielle
-- on évite de faire des nuds avec les quads en plaçant
les points dans le bon ordre
n = n + 1
end repeat
-- Dès lors on connaît les
coordonnÈes (x,y,z) de chaque point de construction du quartier
-- on va dupliquer ce quartier (tous ses
points) et le faire tourner plusieurs fois
-- de faÁon ‡ faire un tour complet
-- Nota en augmentant l'incrément d'angle de pivotement
on ferait moins
-- de copies et l'on obtiendrait une sphère hélicoïdale
repeat while angle <= pi*2 - increment
a = point(cos(angle)*rayon ,sin(angle)*rayon+ rayonExterieur)
add lesPoints, a angle = angle + increment
b = point(cos(angle)*rayon ,sin(angle)*rayon + rayonExterieur
)
add lesPoints, b
end repeat
-- on a maintenant une liste de points dÈfinissant
par couple les cotés au sol
-- chaque point a aussi une position sur l'axe Z, on l'en dote
:
points3D = []
repeat with n in lesPoints x = []
add x , n[1]
add x, n[2]
add x, 0
add points3D, x
end repeat
-- EXTRUSION
-- chaque point a aussi un vis ‡ vis de l'autre cotÈ de l'axe
X
-- on le crée et on l'insËre aprËs lui
-- mais pour le calculer on va faire tourner le système
de repères
objet = []
angleDuQuartier = pi*2/15
-- on fait tout le tour en 15 portions =>
première portion = 1/15 ème de tour
nouvoMonde = rotationSelonAxeXDe (angleDuQuartier)
-- on fait tourner le monde
repeat with n = 1 to count(points3D)
add objet, points3D[n]
add objet, points3D[n+1]
-- ce sont les points initiaux que
l'on reprend ici
-- viennent ensuite les points en vis à vis :
add objet, equivalenceAbsolu (points3D[n+1][1], points3D[n+1][2],
points3D[n+1][3], nouvoMonde)
add objet, equivalenceAbsolu (points3D[n][1], points3D[n][2],
points3D[n][3], nouvoMonde)
-- on évite de faire des noeud
avec les quads !
-- d'où la précédence de n+1
n = n + 1
end repeat
-- on connaît les coordonnÈes (x,y,z)
de chaque point de construction de la portion
-- on va dupliquer ce morceau (tous ces points) et le tourner
plusieurs fois
-- de faÁon ‡ faire un tour complet
tout = duplicate(objet)
repeat while angleDuQuartier < pi*2
repeat with n in objet
add tout, equivalenceAbsolu (n[1], n[2], n[3],
nouvoMonde)
end repeat
angleDuQuartier = angleDuQuartier + pi*2/15
end repeat
-- maintenant pour placer l'objet :
toutPlace = []
repeat with n in tout
temp = []
add temp, n[1] + posX
add temp, n[2] + posY
add temp, n[3] + posZ
add toutPlace, temp
end repeat
return toutPlace
end
LA BOBINE
on definitUneBobine facettes, rayon, position, diametreCentral
-- diamètreCentral ne peut avoir une
valeur inférieure à rayon sinon
-- on obtient un nud en forme de "bonbon"
repeat while angle <= pi - increment
a = point(cos(angle)*rayon ,sin(angle)*rayon - diametreCentral)
add lesPoints, a
angle = angle + increment
b = point(cos(angle)*rayon ,sin(angle)*rayon - diametreCentral)
add lesPoints, b
end repeat
-- on a maintenant une liste de points dÈfinissant
par couple les cotés au sol
-- chaque point ‡ une position sur l'axe Z, on l'en dote :
points3D = []
repeat with n in lesPoints x = []
add x , n[1]
add x, n[2]
add x, 0
add points3D, x
end repeat
-- EXTRUSION
-- chaque point a aussi un vis ‡ vis de l'autre cotÈ de l'axe
X
-- on le crÈe et on l'insËre aprËs lui
-- mais pour le calculer on va faire tourner le système
de repères !
repeat with n = 1 to count(points3D)
add objet, points3D[n]
add objet, points3D[n+1]
-- d'abord les points initiaux
puis les vis a vis pour ne pas croiser les quads
add objet, equivalenceAbsolu (points3D[n+1][1], points3D[n+1][2],
points3D[n+1][3], nouvoMonde)
add objet, equivalenceAbsolu (points3D[n][1], points3D[n][2],
points3D[n][3], nouvoMonde)
n = n + 1
end repeat
-- on connaît les coordonnÈes (x,y,z)
de chaque point de construction du morceau
-- on va dupliquer ce bout (tous ces points) et le faire tourner
plusieurs fois
-- de faÁon ‡ faire un tour complet
tout = duplicate(objet)
repeat while angleDuQuartier < pi*2
nouvoMonde = rotationSelonAxeXDe ( angleDuQuartier)
repeat with n in objet
add tout, equivalenceAbsolu (n[1], n[2],
n[3], nouvoMonde)
end repeat
angleDuQuartier = angleDuQuartier + pi*2/15
end repeat
toutPlace = []
repeat with n in tout
temp = []
add temp, n[1] + posX
add temp, n[2] + posY
add temp, n[3] + posZ
add toutPlace, temp
end repeat
return toutPlace