II - Modélisation Lingo (créer Une bibliothèque
d'objets 3 D)
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 :
on definitUnCarre cote
lesPoints = [[-cote/2, -cote/2, -cote/2],
[cote/2, -cote/2, -cote/2], Â [cote/2, cote/2, -cote/2],
[-cote/2, cote/2, -cote/2] ]
return lesPoints
end
Un cube c'est déjà une première face :
on definitUnCube cote
lesPoints = definitUnCarre (cote)
-- on crée les autres cots
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 dfinissant 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 coordonnes (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 dfinissant 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 coordonnes
(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 dfinissant 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 dfinissant 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 cre et on l'insre auprs 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 coordonnes (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 faon 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 dfinissant 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'insre aprs 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 coordonnes
(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 faon 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 dfinissant 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 cre et on l'insre aprs 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 coordonnes
(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 faon 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