3D Lingo

 

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.

faceAvant = [ [0, 0, 0], [100, 0, 0], [100,100,0] , [0,100,0]

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 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 nœuds !
-- 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 nœuds 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).

 

 

LE CERCLE

on definitUnCerclePlein facettes, rayon, hauteur

increment = pi*2/facettes
angle = 0
lesPoints = []

-- 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 nœuds !
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]

posX = position[1]
posY = position[2]
posZ = position[3]
increment = pi*2/facettes.
angle = 0
lesPoints = []

-- RÉVOLUTION
-- on fait tourner par incrément

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

 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)

-- puis les vis ˆ vis obtenus après révolution partielle
-- on évite de faire des nœuds 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

 

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/12
-- on fait douze quartiers car le premier fait un douzième de sphère

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

 

 

LE TORE

Même principe ici, mais une base circulaire (et non plus demi circulaire) que l'on fait tourner autour d'un axe excentré.

 

 

on definitUnTore facettes, rayon, rayonExterieur , position

posX = position[1]
posY = position[2]
posZ = position[3]
increment = pi*2/facettes -- Rappel : pi*2 = un cercle complet
angle = 0
lesPoints = []

-- RÉVOLUTION

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

  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

-- 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 nœud en forme de "bonbon"

posX = position[1]
posY = position[2]
posZ = position[3]
increment = pi/facettes
angle = 0
lesPoints = []

-- REVOLUTION

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 !


objet = []
angleDuQuartier = pi*2/15

nouvoMonde = rotationSelonAxeXDe ( angleDuQuartier)

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

end

A suivre...