« Programmation objet et géométrie/Objets Python sous Blender/Création de surfaces paramétrées avec bpy » : différence entre les versions
m Renommage de catégorie : Modification de la catégorie Catégorie:Blender3D (livre) → Catégorie:Blender 3D (livre) |
m <source> -> <syntaxhighlight> (phab:T237267) |
||
Ligne 28 : | Ligne 28 : | ||
Comme précédemment, on importe les classes Blender et bpy, mais aussi les fonctions trigonométriques et <math>\pi</math>, qui sont des méthodes (et propriété pour <math>\pi</math>) de l'objet ''math'': |
Comme précédemment, on importe les classes Blender et bpy, mais aussi les fonctions trigonométriques et <math>\pi</math>, qui sont des méthodes (et propriété pour <math>\pi</math>) de l'objet ''math'': |
||
< |
<syntaxhighlight lang="python"> |
||
from Blender import * |
from Blender import * |
||
import bpy |
import bpy |
||
from math import pi, cos, sin |
from math import pi, cos, sin |
||
sommets=[] |
sommets=[] |
||
</syntaxhighlight> |
|||
</source> |
|||
===Liste des sommets=== |
===Liste des sommets=== |
||
Ligne 39 : | Ligne 39 : | ||
Lors de sa création, la liste des sommets est vide. Il reste donc à la remplir, ce qui se fait par quelque chose qu'on n'a pas utilisé dans l'article précédent: Une boucle. Celle-ci est double (puisqu'il y a deux paramètres) et ses deux indices sont choisis entre 0 et 100 (pour ''i'') et entre 0 et 50 (pour ''j''). Pour passer de <math>0 \leqslant i \leqslant 100</math> à <math>0 \leqslant u \leqslant \pi</math>, on multiplie ''i'' par <math>\frac{\pi}{100}</math> pour avoir ''u''. De même, <math>v=j \times \frac{\pi}{50}</math>: |
Lors de sa création, la liste des sommets est vide. Il reste donc à la remplir, ce qui se fait par quelque chose qu'on n'a pas utilisé dans l'article précédent: Une boucle. Celle-ci est double (puisqu'il y a deux paramètres) et ses deux indices sont choisis entre 0 et 100 (pour ''i'') et entre 0 et 50 (pour ''j''). Pour passer de <math>0 \leqslant i \leqslant 100</math> à <math>0 \leqslant u \leqslant \pi</math>, on multiplie ''i'' par <math>\frac{\pi}{100}</math> pour avoir ''u''. De même, <math>v=j \times \frac{\pi}{50}</math>: |
||
< |
<syntaxhighlight lang="python"> |
||
for i in range(0,100): |
for i in range(0,100): |
||
u=i*pi/100 |
u=i*pi/100 |
||
Ligne 48 : | Ligne 48 : | ||
z=cos(u)*sin(2*v) |
z=cos(u)*sin(2*v) |
||
sommets.append([x,y,z]) |
sommets.append([x,y,z]) |
||
</syntaxhighlight> |
|||
</source> |
|||
''x'', ''y'' et ''z'' sont calculés à partir de ''u'' et ''v'' avec les formules ci-dessus, puis le sommet (x,y,z) est ajouté à la base de donnée des sommets. À l'issue de cette boucle, la surface de Steiner sera riche de <math>101 \times 51 = 5151</math> points. |
''x'', ''y'' et ''z'' sont calculés à partir de ''u'' et ''v'' avec les formules ci-dessus, puis le sommet (x,y,z) est ajouté à la base de donnée des sommets. À l'issue de cette boucle, la surface de Steiner sera riche de <math>101 \times 51 = 5151</math> points. |
||
Ligne 61 : | Ligne 61 : | ||
< |
<syntaxhighlight lang="javascript"> |
||
| | | | |
| | | | |
||
4--54-104-154- |
4--54-104-154- |
||
Ligne 73 : | Ligne 73 : | ||
0--50-100-150- |
0--50-100-150- |
||
</syntaxhighlight> |
|||
</source> |
|||
===tableau des faces=== |
===tableau des faces=== |
||
Ligne 79 : | Ligne 79 : | ||
Ainsi, chaque sommet a un numéro de la forme <math>50i+j</math>, et est relié successivement aux sommets de numéros <math>50i+j+50</math>, <math>50i+j+51</math> et <math>50i+j+1</math>. Il suffit alors de créer un tableau initialisé à 0 pour les faces, et d'y ajouter des listes telles que celle ci-dessus, au fur et à mesure, dans une double boucle: |
Ainsi, chaque sommet a un numéro de la forme <math>50i+j</math>, et est relié successivement aux sommets de numéros <math>50i+j+50</math>, <math>50i+j+51</math> et <math>50i+j+1</math>. Il suffit alors de créer un tableau initialisé à 0 pour les faces, et d'y ajouter des listes telles que celle ci-dessus, au fur et à mesure, dans une double boucle: |
||
< |
<syntaxhighlight lang="python"> |
||
faces=[] |
faces=[] |
||
for i in range(0,99): |
for i in range(0,99): |
||
for j in range(0,49): |
for j in range(0,49): |
||
faces.append([50*i+j,50*i+j+50,50*i+j+51,50*i+j+1]) |
faces.append([50*i+j,50*i+j+50,50*i+j+51,50*i+j+1]) |
||
</syntaxhighlight> |
|||
</source> |
|||
En réalité, il manque des faces telles que 49-99-50-0 et 5000-0-1-5001 mais leur absence ne se verra pas, et corriger cet oubli, est laissé en exercice... |
En réalité, il manque des faces telles que 49-99-50-0 et 5000-0-1-5001 mais leur absence ne se verra pas, et corriger cet oubli, est laissé en exercice... |
||
Ligne 101 : | Ligne 101 : | ||
Ce qui s'écrit ainsi: |
Ce qui s'écrit ainsi: |
||
< |
<syntaxhighlight lang="python"> |
||
st=bpy.data.meshes.new('pp') |
st=bpy.data.meshes.new('pp') |
||
st.verts.extend(sommets) |
st.verts.extend(sommets) |
||
Ligne 107 : | Ligne 107 : | ||
scn = bpy.data.scenes.active |
scn = bpy.data.scenes.active |
||
ob = scn.objects.new(st, 'steiner') |
ob = scn.objects.new(st, 'steiner') |
||
</syntaxhighlight> |
|||
</source> |
|||
Ensuite il suffit de cocher le bouton ''Set smooth'' pour arrondir les angles (et en profiter pour décocher le bouton ''double sided'' puisque pour une fois, on a défini une surface unilatère), à texturer la surface avec un matériau transparent, puis à effectuer un rendu: |
Ensuite il suffit de cocher le bouton ''Set smooth'' pour arrondir les angles (et en profiter pour décocher le bouton ''double sided'' puisque pour une fois, on a défini une surface unilatère), à texturer la surface avec un matériau transparent, puis à effectuer un rendu: |
Version actuelle du 16 avril 2020 à 10:06
Pour représenter des surfaces paramétrées, on utilise la seule chose que Blender sache gérer: Des polyèdres. Seulement ils ont tellement de faces et elles sont si petites, que le polyèdre aura l'air, si on n'y fait trop attention, d'une surface de classe . Cette représentation des surfaces par des approximations polyédrales est à la base de chapitres entiers des mathématiques:
- la méthode des éléments finis en analyse numérique;
- la cohomologie en topologie.
Dans les deux cas, la surface est approchée par une triangulation. Comme les deux paramètres de la surface
s'appellent souvent et , le nom d' uv-mapping est souvent utilisé dans les logiciels de 3D (comme Blender) pour désigner les coordonnées de textures.
Ci-dessous on va représenter une surface unilatère, la surface romane de Steiner.
Expression paramétrique[modifier | modifier le wikicode]
La surface de Steiner est donnée par la représentation paramétrique suivante:
avec et .
sommets[modifier | modifier le wikicode]
Entête du fichier[modifier | modifier le wikicode]
Comme précédemment, on importe les classes Blender et bpy, mais aussi les fonctions trigonométriques et , qui sont des méthodes (et propriété pour ) de l'objet math:
from Blender import *
import bpy
from math import pi, cos, sin
sommets=[]
Liste des sommets[modifier | modifier le wikicode]
Lors de sa création, la liste des sommets est vide. Il reste donc à la remplir, ce qui se fait par quelque chose qu'on n'a pas utilisé dans l'article précédent: Une boucle. Celle-ci est double (puisqu'il y a deux paramètres) et ses deux indices sont choisis entre 0 et 100 (pour i) et entre 0 et 50 (pour j). Pour passer de à , on multiplie i par pour avoir u. De même, :
for i in range(0,100):
u=i*pi/100
for j in range(0,50):
v=j*pi/50
x=sin(2*u)*sin(v)**2
y=sin(u)*sin(2*v)
z=cos(u)*sin(2*v)
sommets.append([x,y,z])
x, y et z sont calculés à partir de u et v avec les formules ci-dessus, puis le sommet (x,y,z) est ajouté à la base de donnée des sommets. À l'issue de cette boucle, la surface de Steiner sera riche de points.
Il reste à trouver, dans cette immense collection, quels sommets sont reliés à quels autres.
faces[modifier | modifier le wikicode]
plan des (u,v)[modifier | modifier le wikicode]
Les faces seront des quadrilatères, bordés horizontalement par des lignes de niveau de v et verticalement par des lignes de niveau de u. Les numéros des sommets correspondent à l'ordre de leur création, soit colonne par colonne:
| | | |
4--54-104-154-
| | | |
3--53-103-153-
| | | |
2--52-102-152-
| | | |
1--51-101-151-
| | | |
0--50-100-150-
tableau des faces[modifier | modifier le wikicode]
Ainsi, chaque sommet a un numéro de la forme , et est relié successivement aux sommets de numéros , et . Il suffit alors de créer un tableau initialisé à 0 pour les faces, et d'y ajouter des listes telles que celle ci-dessus, au fur et à mesure, dans une double boucle:
faces=[]
for i in range(0,99):
for j in range(0,49):
faces.append([50*i+j,50*i+j+50,50*i+j+51,50*i+j+1])
En réalité, il manque des faces telles que 49-99-50-0 et 5000-0-1-5001 mais leur absence ne se verra pas, et corriger cet oubli, est laissé en exercice...
Création de la surface de Steiner[modifier | modifier le wikicode]
Ensuite comme précédemment il reste à
- Instancier un objet héritant de la classe meshes, et l'appeler pp (comme plan projectif)
- Y placer les sommets calculés ci-dessus;
- Y ajouter les faces calculées ci-dessus;
- Rendre la scène Blender active pour pouvoir la modifier;
- En profiter pour y placer l'objet surface de Steiner
Ce qui s'écrit ainsi:
st=bpy.data.meshes.new('pp')
st.verts.extend(sommets)
st.faces.extend(faces)
scn = bpy.data.scenes.active
ob = scn.objects.new(st, 'steiner')
Ensuite il suffit de cocher le bouton Set smooth pour arrondir les angles (et en profiter pour décocher le bouton double sided puisque pour une fois, on a défini une surface unilatère), à texturer la surface avec un matériau transparent, puis à effectuer un rendu:
Exercice[modifier | modifier le wikicode]
Construire une bouteille de Klein en utilisant la représentation paramétrique de Jeener [1]: