|
Maîtriser le Triangle
Le Débutant absolu anime un Triangle
Si vous ne voulez pas vous poser
d'inutiles questions, ajustez votre ordinateur de façon à pouvoir lire
les extensions des fichiers.
Nous avons besoin
d'installer le programme VrmlPad sur notre ordinateur. C'est un petit programme
et il s'installe très rapidement. Entre le téléchargement et l'installation
complète l'opération ne devrait prendre que quelques minutes. Téléchargez le fichier
d'installation ici :
Il nous faut maintenant un dossier pour y installer nos fichiers exemples Ouvrez
"Explorateur Windows". Pour y arriver :
Ouvrez VrmlPad puis cliquez tools (outils) dans le menu puis choisissez
options Nous pouvons commencer à écrire le code de notre triangle dans le VrmlPad. La première ligne #VRML V2.0 utf8 doit toujours être exactement au début d'un fichier VRML. C'est cette ligne qui indique au programme visionneur qu'il doit l'interpréter comme un fichier vrml. Par la suite quand vous voyez un texte commencer par "#" et ceci jusqu'au début d'une nouvelle ligne, vous savez qu'il s'agit d'un commentaire. Ces commentaires sont à usage humain seul et n'ont aucun effet sur le déroulement du programme.
Noeuds et Champs
Pensez qu'un Noeud est un bloc de construction urilisé en Vrml.
Nous allons fabriquer un polygone à trois côtés qui aura un mètre de haut et un mètre
de gauche à droite. Pour fabriquer quoi que ce soit en Vrml, nous devons instancier
un Noeud Shape (forme).
Shape{
Remarquez qu'en VrmlPad une erreur nous
est signalée tant que nous n'avons pas refermé une accolade. Ceci, parce que
le code de l'instanciation est incomplet jusqu'à ce que l'accolade soit refermée. Mais dès que nous
avons terminé d'écrire le code nécessaire au Noeud Shape le code est légal, et le visionneur Blaxxun
contact peut l'ouvrir sans erreur. Avant toutefois de pouvoir ouvrir le code dans le vivionneur
nous devons l'enregistrer dans VrmlPad avec les clés CTRL+S (ou un clic sur la vignette de sauvegarde,
une petite disquette). geometry IndexedFaceSet { Après insertion de ce code, VrmlPad ne devrait signaler aucune erreur. Le code ressemble à ceci : Shape {
Notez comment j'ai décalé d'une tabulation à droite le champ geometry du Noeud Shape.
En disposant les choses de cette façon, on voit mieux quel Noeud et quel champ appartient à quel Noeud.
Il existe un dispositif de VrmlPad très utile pour que nos lignes de code soient automatiquement
indentées de cette façon :
Tapez CTRL+A pour souligner tout le texte.
pour construire un polygone il nous faut deux listes de nombres, les coords (coordonnées) et les index (indices). Occupons nous d'abord des coords (une coord peut aussi être appelée coordonnée, ou coin, ou angle, point ou sommet) qui indiquent l'emplacement des sommets du polygone.
Nous installons nos coords dans une instance du membre de
l'IndexedFaceSet appelé coord.
coord Coordinate { de telle sorte que notre code (toujours exempt d'erreurs) ressemble maintenant à :
Shape {
Les données en Vrml sont toujours placées dans des champs, jamais directement dans un Noeud.
Un Noeud Coordinate contient donc un champ appelé "point" (point).
Le "point" est un champ de type MFVec3f et c'est là que nous
installons notre liste de coords (coordonnées). Nous allons donc ajouter ce champ
et ses crochets, avant d'y écrire notre liste. point [
Entre les crochets du champ nous insérons maintenant les données x, y et z qui vont définir la position de chacun des points (sommets) de notre polygone.
x définit en mètres, de droite à gauche, la position du sommet.
La liste des points dans un IndexedFaceSet commence TOUJOURS par 0, puis 1, puis 2 et ainsi de suite.
Ceci ne veut pas dire que le point 0 sera toujours à cette place dans un polygone, ni qu'il est toujours en bas à gauche du polygone, il peut aussi bien être n'importe où. On l'appelle "point 0" parce qu'il est le premier de la liste des points. il se trouve que dans cet exemple le point 0 est à gauche de la base, parce que ses données sont : -1 0 0 Le point 0 se situe à gauche de la base de notre triangle parce que le premier nombre, ou composante x de ce sommet, est -1 (un mètre à gauche) et que le deuxième nombre, la composante y, est 0 en hauteur (notre base est à zéro mètre de haut). Ici toutes nos composantes z (distances à l'écran ou au delà de l'écran) seront égales à 0, notre polygone est à plat contre le plan z. pour que le point un spécifie la position du sommet droit de la base, nous reproduisons les mêmes composantes, sauf la composante x qui devient positive : 1 0 0 pour que le point 2, notre troisième coordonnée, soit en haut et au milieu, la composante x est fixée à 0, milieu de la base, la composante y est fixée à 1 mètre de haut, comme suit : 0 1 0
coord Coordinate {
Si les coords (les coordonnées des sommets)sont seules à être fixées,
il n'y a toujours rien à voir.
Si nous avions choisi l'ordre 2 1 0, nous aurions toujours un triangle légal. Sauf que pour le voir, il aurait fallu le faire tourner d'un demi tour (ce qui revient à remettre les sommets dans l'ordre 0 1 2). Pourquoi? Vous pouvez imaginer que le triangle n'est "peint" que d'un seul côté...
Nous pouvons toujours écrire le nom du champ coordIndex et ses crochets
avant d'y préciser les données voulues (entre ces mêmes crochets). coordIndex [
A ce moment là, aucune erreur n'est décelable par VrmlPad, en bas de la fenêtre.
Par ailleurs, peu importe que coordIndex soit placé avant ou après coord,
dès le moment que ces deux champs, tout deux membres du Noeud IndexedFaceSet, y sont.
La syntaxe reste correcte. Après ajout de notre coordIndex notre IndexFaceSet doit ressembler à ceci : geometry IndexedFaceSet { ou à celà : geometry IndexedFaceSet {
Une chose importante à noter dès maintenant c'est que notre champ coordIndex vient une tabulation
plus loin que la colonne où se trouve notre Noeud IndexedFaceSet et son accolade de fermeture.
Souvenez-vous que pour s'en assurer on tape CTRL+A puis CTRL+SHIFT+F dans VrmlPad et
tout s'aligne en fonction de l'emplacement des accolades. coordIndex [ Taper CTRL+S dans vrmlPad pour sauvegarder puis rafraîchir et nous devrions voir maintenant notre triangle :)
Examiner le triangle des deux côtés
Pour examiner notre triangle selon différents angles il faut faire passer
Blaxxun contact en mode examine.
Cliquez dans la scène 3d puis tapez CTRL+SHIFT+E
Cliquez-tirez le pointeur de la souris dans la scène 3d pour faire tourner le triangle.
Remarquez que vous ne pouvez pas voir l'autre côté du triangle, comme je l'ai déjà expliqué.
C'est fait exprès. Le travail de l'ordinateur est accéléré s'il n'a qu'un seul côté
à "peindre". Tous les triangles seront toujours dessinés en sens inverse des aiguilles
d'une montre et nous ne verrons jamais les triangles bâtis dans un autre ordre. solid FALSE
Sauvegardez et rafraîchissez pour constater que le triangle peut être vu des deux côtés.
On ajoute une ombre au triangle
Notre triangle est dépourvu d'ombres. Sa brillance est constante, quel que soit l'angle sous
lequel on le regarde.
S'il fallait fabriquer un objet avec des triangles comme ça, il aurait une allure
plutôt plate. Pour lui donner une ombre, il faut ajouter dans le Noeud Shape
(forme) un champ appearance (apparence) contenant un Noeud
Appearance (Apparence), puis dans le Noeud Appearance un champ
material (matière) contenant lui-même un Noeud Material (Matière). appearance Appearance { ajoutées au Noeud Shape apportent une ombre à notre triangle.
Notez aussi que plus on le tourne, plus il est sombre. Il est possible de donner à ce triangle n'importe quelle couleur en ajoutant au Noeud Material un champ diffuseColor (couleur diffusée) portant la couleur voulue. Le champ diffuseColor est du type SFColor (Simple champ, Couleur). Un champ de type SFColor comporte trois composantes r, g, et b.
r pour red (rouge) Les composantes peuvent prendre toute valeur décimale de 0 à 1. 0 pour rien du tout, 1 pour la totale. de cette façon, ajuster notre champ diffuseColor à 1 0 0 donne un triangle rouge. Pour cela on ajoute dans les accolades du Noeud Material : diffuseColor 1 0 0
on sauvegarde et on rafraîchit pour voir le triangle rouge :)
Notre fichier devrait ressembler à mon fichier de travail "triangle.wrl" : On obtient un rouge sombre en diminuant la composante rouge, par exemple : .7 0 0
devient rouge plus sombre Si on continue à diminuer la composante rouge on arrive à 0 0 0 qui est noir, puisque toutes les valeurs sont nulles. Pour avoir un rouge plus clair, on augmente les 2 autres composantes à égalité, par exemple : 1 .4 .4 qui donne un rose et Si on poursuit l'augmentation des 2 autres composantes on arrive à 1 1 1 qui représente un blanc, puisque les 3 valeurs sont bloquées au maximum. Ci-dessous quelques combinaisons de couleurs, mais vous pourrez essayer vous-même de trouver à votre goût vos propres combinaisons :
0 1 0 #vert Nous pouvons être heureux de notre compétence, ce triangle est déjà assez sophistiqué pour qu'on puisse le porter fièrement comme un avatar de plein droit.
On ajoute un autre triangle à notre IndexedFaceSet pour en faire un losange
Pour ajouter un triangle nul besoin de définir 3 coords car une seule suffit. Ceci parce qu'on utilise les indices pour savoir quels sommets joindre ensemble. Les indices peuvent désigner, pour tracer un polygone, un sommet pris n'importe où dans la liste coord. C'est tout l'avantage de disposer de deux listes, une de coords (coordonnées) et une de index (indices) au lieu d'une seule qui préciserait les coordonnées successives. Avec deux listes, on peut s'arranger pour que des polygones partagent les mêmes sommets dans un Noeud IndexedFaceSet. Typiquement un point dans un IndexedFaceSet est utilisé dans deux triangles. Il en résulte que l'ordinateur aura moins de sommets (coordonnées) à prendre en compte. Pour installer le sommet supplémentaire à l'opposé du sommet supérieur nous fixons une coordonnée y identique au signe près -1. de sorte que nos coordonnées sont maintenant :
-1 0 0 #point 0 = gauche Reste à joindre trois sommets indicés pour fabriquer un triangle tout neuf. Pour que Blaxxun contact sache où finit un triangle et où commence un autre, il est IMPERATIF d'ajouter -1 après le dernier indice du dernier polygone avant d'ajouter l'ensemble des indices du polygone suivant. (Les indices commencent avec 0, puis suivent les entiers positifs 1, 2, 3, ..., de sorte que la marque "-1" ne peut pas être interprétée comme un indice, c'est donc la "marque de fin"). Notre champ indexCoord ressemble alors à ceci : coordIndex [ Bien sûr, au lieu de tracer deux triangles pour faire un polygone en losange nous pourrions tracer un polygone à quatre sommets en changeant les valeurs des indices en 0 3 1 2 et notre coordIndex, si nous le faisions, deviendrait : coordIndex [ Mais je veux continuer à diviser moi-même mon polygone en triangles, parce que sans cela nous serions bloqués quand nous voudrions changer (par exemple) les composantes z si elles ne doivent pas rester toutes identiques. De plus on ne gagne rien en temps d'éxécution d'un polygone à quatre côtés, puisque l'ordinateur va de toute façon découper tout polygone de plus de trois arêtes en triangles avant de le représenter. Pour montrer un carré au lieu d'un losange on écrit :
On peut très bien laisser les coordIndex comme ils sont en listant les coords ainsi :
-1 -1 0 #angle inférieur gauche Essayez de modifier les composantes x, y et z des coordonnées pour obtenir des formes différentes. Jouer avec les triangles est l'exercice le plus utile et de loin pour qui veut se sentir à l'aise, comme chez soi, avec eux. Si nous fixons nos coords comme ça :
-1 0 0 #point 0 = gauche alors les sommets du haut et du bas de notre losange, du fait des valeurs de z maintenant différentes de celles des sommets moyens droit et gauche, lui donnent un aspect plié. Notez que cette pliure (crease) apparaît aiguë entre les deux triangles lorsque nous les faisons tourner en mode "examine".
Bien souvent, quand on construit un objet, on préfère lui donner un aspect lisse.
On pourrait le faire en dessinant plein de petits triangles ce qui serait catastrophique
en temps d'exécution 3d. creaseAngle 3.14 l'angle de notre pli est maintenant fixé à 1 PI radians (180 degrés)
Couleur Par Sommets color Color {
Pas d'inquiétude... dans ce Noeud Color il faut à nouveau introduire un champ color
car les données doivent toujours être dans un champ, jamais directement dans un Noeud.
Cela fait trois colors de suite, eh bien c'est comme ça! Ici on a donc champ, Noeud, champ.
color [ On sauvegarde et on rafraîchit, de sorte qu'on aperçoit maintenant nos adorables triangles bien colorés :)
Inutile de conserver le champ diffuseColor ni ses valeurs car il a été
de toute façon annulé par le Noeud Color et nous pouvons aussi bien effacer
la ligne qui lui correspond. Notre fichier devrait déjà ressembler à mon
fichier de travail :
Naturellement, on pourrait obtenir des objets plus complexes en ajoutant triangle
sur triangle, toutefois, plutôt que d'écrire le code à la main pour les générer,
définissant sommet après sommet, un à la fois, ajoutant des indexCoords
l'un après l'autre avec un simple éditeur de texte, ce qui pourrait sembler
à la longue une tâche bien fastidieuse, mieux vaut faire appel à une interface
graphique.
Seamless3D
représente justement une telle solution qui peut produire autant de triangles en
color per vertex que l'on veut, et avec facilité.
Translation d'un Triangle 2 mètres à droite
donc, pour déplacer notre triangle de 2 mètres à droite nos
coordonnées x y et z seront 2 0 0 translation 2 0 0
Le champ translation appartient à un Noeud Transform
on ajoutera donc d'abord la ligne
Transform {
translation 2 0 0
children Shape {
appearance Appearance {
material Material {
diffuseColor 1 0 0
}
}
geometry IndexedFaceSet {
solid FALSE
coord Coordinate {
point [
-1 0 0 #point 0
1 0 0 #point 1
0 1 0 #point 2
]
}
coordIndex [
0 1 2 #joindre les 3 points en sens anti-horaire
]
}
}
}
Rotation de 1/8 de tour selon l'axe y
En Vrml un champ rotation contient 4 valeurs. Les x, y et z sont les axes pris en compte et l'angle mesure la rotation autour de l'axe spécifié.
Bien que les valeurs de x, y et z puissent prendre toute valeur utile
(de 0 à 1) la plupart du temps on se contente d'un seul axe pour
faire tourner un objet, ce qui donne : On fixe l'angle à la valeur voulue, compte tenu de ce qu'il est mesuré en radians. Un tour complet mesure 2 Pi radians, soit 6.283185307 donc, pour une rotation de 1/8 de tour, nous allons fixer notre angle à la valeur de 6.283185307 / 8 = 0.785398163
rotateOnTheYAxisOne8th.wrl est le même que translate2MetersToTheRight.wrl
sauf que la ligne
Transform {
rotation 0 0 1 0.785398163
children Shape {
appearance Appearance {
material Material {
diffuseColor 1 0 0
}
}
geometry IndexedFaceSet {
solid FALSE
coord Coordinate {
point [
-1 0 0 #point 0
1 0 0 #point 1
0 1 0 #point 2
]
}
coordIndex [
0 1 2 #joindre les 3 points en sens anti-horaire
]
}
}
}
Pour approfondir cette question des rotations, voir mon didacticiel
Comprendre les Rotations VrmlAnimation Translation DEF myTimer TimeSensor{
cycleInterval 4 # un cycle = 4 secondes
loop TRUE # le cycle est répété en boucle
}
DEF myPosInt PositionInterpolator {
key [0 .25 .5 .75 1] # le cycle comporte 4 phases de durée égale
keyValue [
-3 0 0 # la phase 0 commence 3 mètres à gauche
0 0 0 # la phase 1 commence là où la phase 0 finit
# c'est à dire au centre
3 0 0 # la phase 2 commence là où la phase 1 finit
# soit 3 mètres à droite
0 0 0 # la phase 3 commence là où la phase 2 finit
# de nouveau au centre
-3 0 0 # la phase 3 finit au point de départ
# le cycle peut recommencer
]
}
DEF myNode Transform {
children Shape {
appearance Appearance {
material Material { # colore le triangle en rouge
diffuseColor 1 0 0 # valeurs r v b = rouge au max
# vert et bleu nuls
}
}
geometry IndexedFaceSet {
solid FALSE
coord Coordinate {
point [ # les 3 positions pour les trois sommets
-1 0 0 # point 0 x,y,z base à gauche
1 0 0 # point 1 x,y,z base à droite
0 1 0 # point 2 x,y,z en haut
]
}
coordIndex [ # joindre les 3 points en sens anti-horaire
0 1 2
]
}
}
}
# Envoyer les quatre fractions du cycle d'horloge interne à l'interpolateur
# qui préparera les positions intermédiaires
ROUTE myTimer.fraction_changed TO myPosInt.set_fraction
# envoyer ces positions au Noeud Transform qui dessine l'objet
# dans ses positions successives
ROUTE myPosInt.value_changed TO myNode.translation
Animation Rotation L'ordre des transformations d'un objet est rigide. Il faut savoir que le visionneur interprète toujours la rotation avant la translation. ( voir le code rotAnimation.wrl voir l'exemple rotAnimation.wrl ) Voici le code français correspondant : DEF myTimer TimeSensor{
cycleInterval 4 # un cycle = 4 secondes
loop TRUE # le cycle est en boucle
}
DEF myRotInt OrientationInterpolator {
key [0 .25 .5 .75 1] # le cycle est découpé en 4 phases de durée égale
keyValue [
0 1 0 0 # phase 0 commence à 0 revolution autour de y
0 1 0 1.570796327 # phase 1 commence où phase 0 finit, quart de tour
0 1 0 3.141592654 # phase 2 commence où phase 1 finit, demi tour
0 1 0 4.71238898 # phase 3 commence où phase 2 finit, 3 quarts de tour
0 1 0 6.283185307 # phase 3 finit après un tour complet, on recommence
]
}
DEF myNode Transform {
children
Shape {
appearance Appearance {
material Material { #Colorer le triangle en rouge
diffuseColor 1 0 0 # r v b = plein rouge, vert et bleu nuls
}
}
geometry IndexedFaceSet {
solid FALSE
coord Coordinate {
point [ # les 3 positions des 3 sommets
-1 0 0 # point 0 x,y,z = base gauche
1 0 0 # point 1 x,y,z = base droite
0 1 0 # point 2 x,y,z = haut
]
}
coordIndex [ # joindre lese 3 points en sens anti-horaire
0 1 2
]
}
}
}
# Envoyer les quatre fractions du cycle d'horloge interne à l'interpolateur
ROUTE myTimer.fraction_changed TO myRotInt.set_fraction
# envoyer ces positions au Noeud Transform qui dessine l'objet
# dans ses positions successives
ROUTE myRotInt.value_changed TO myNode.rotation
Si l'on veut expressément le contraire, pour obtenir un mouvement
orbital par exemple, il est nécessaire d'ajouter un autre Noeud Transform.( voir le code orbit.wrl voir l'exemple orbit.wrl ) dont le code des commentaires en français est le suivant : DEF myTimer TimeSensor{
cycleInterval 4 # une cycle = 4 secondes
loop TRUE # le cycle est en boucle
}
DEF myRotInt OrientationInterpolator {
key [0 .25 .5 .75 1] # break the cycle down to 4 phases of time all of equal length
keyValue [
0 1 0 0 # phase 0 commence à 0 revolution autour de y
0 1 0 1.570796327 # phase 1 commence où phase 0 finit, quart de tour
0 1 0 3.141592654 # phase 2 commence où phase 1 finit, demi tour
0 1 0 4.71238898 # phase 3 commence où phase 2 finit, 3 quarts de tour
0 1 0 6.283185307 # phase 3 finit après un tour complet, on recommence
]
}
DEF myNode Transform {
children
Shape {
appearance Appearance {
material Material { # Colore le triangle en rouge
diffuseColor 1 0 0 # r v b = plein rouge, vert et bleu nuls
}
}
geometry IndexedFaceSet {
solid FALSE
coord Coordinate {
point [
point [ # les 3 positions des 3 sommets
-1 0 0 # point 0 x,y,z = base gauche
1 0 0 # point 1 x,y,z = base droite
0 1 0 # point 2 x,y,z = haut
]
}
coordIndex [
0 1 2 # joindre lese 3 points en sens anti-horaire
]
}
}
}
# Envoyer les quatre fractions du cycle d'horloge interne à l'interpolateur
ROUTE myTimer.fraction_changed TO myRotInt.set_fraction
# envoyer ces positions au Noeud Transform qui dessine l'objet
# dans ses positions successives
ROUTE myRotInt.value_changed TO myNode.rotation
Il est vraiment très important pour vous de jouer avec ces trois derniers exemples,
afin de vous imprégner du sens, du mécanisme et de l'importance des
instructions DEF, des TimeSensor, des Interpolator et des
ROUTE.
Ceci complète notre survol des procédures d'animation d'un triangle. Note du traducteur : A partir d'ici, Thyme cesse de prodiguer des explications aussi détaillées, point à point. C'est que dès maintenant vous avez compris "comment ça marche". Par la suite, de nombreux exemples doivent suffire pour progresser, à supposer, c'est bien entendu, que vous les examiniez dans le détail. On ne survole pas, on suit le code, "le crayon à la main". Bon travail. Fin de note.
Qu'est-ce qui est unique avec le triangle?
Toujours du côté simple
Deux Triangles
Deux triangles avec le pli adouci de creaseAngle (faux pli) Deux Triangles avec leur Normale Note du traducteur (hilare) : Mais ... TOUT ce qu'on fait en 3d est une illusion d'optique! Un jour, un jour où nous serions au coin du feu, grignotant des noix et jetant les coquilles dans le feu, oh les jolies flammes, je vous dirai (en confidence) que le monde, le real life, le vrai monde qui nous entoure, est aussi une illusion d'optique, c'est un jeu video généré par les couches optiques de notre cerveau, mais il faudrait se lancer dans une tartine neurobiologique et nous n'avons pas le temps. Cependant, c'est bien en fournissant à ces mêmes couches optiques, grâce au Vrml, les informations qu'elles attendent que nous pouvons créer des "mondes" qui nous semblent justement si réalistes. Je bavarde je bavarde ... il faut rendre la parole à Thyme. Fin de note.... cette courbure est une illusion d'optique provoquée par les normales que nous avons ajoutées. Ces normales nous permettent de manipuler les ombres dans les triangles constitutifs des objets pour les lisser avec un nombre très réduit de triangles. ( voir le code twoTrianglesWithNormals.wrl voir l'exemple twoTrianglesWithNormals.wrl ) Si vous tenez à une expérience visuelle interactive de ce que sont ces normales, examinez donc ma Demo des Normales : Les 4 gros bâtons rouges qui sortent des sommets des triangles représentent les normales. Je n'ai ajouté les petits bâtons verts et bleus que pour donner une meilleure idée visuelle de leur orientation. Les trois curseurs ne contrôlent que le bâton rouge du sommet gauche. Cliquez-tirez le curseur rouge pour orienter la normale à votre gré. A la première tentative une fenêtre devrait surgir et indiquer les données de la normale. Si vous y apercevez d'étranges nombres comportant un "e" vous pouvez considérer qu'ils sont égaux à zéro (il s'agit d'une notation mathématique exponentielle usuelle). Les trois nombres x, y et z représentent la position relative de la normale à son pied. Ces nombres sont toujours dans l'intervalle de 0 à 1 (les normales sont des vecteurs unité). Le premier curseur tourne la normale autour de son axe x, le second autour de l'axe y et le troisième autour de l'axe z. Pour re-initialiser un curseur, cliquez son axe bleu. Constatez que c'est alors que la normale est dirigée vers l'écran que le triangle est le plus brillant. Ceci, parce que la lumière définie par le Vrml est dirigée vers l'écran (rayons parallèles à l'axe z). Plus on en écarte la normale, plus le triangle est assombri. Ceci admis, tentez autre chose. Puisqu'on est en mode examine, ne touchez plus aux curseurs, mais faites donc tourner toute la scène pour ramener la normale en direction de l'écran: surprise, la partie du triangle qui entoure le pied de la normale retrouve sa brillance. C'est bien parce que c'est l'orientation des normales et non celle des triangles qui dicte la façon dont l'ordinateur doit répartir la brillance et les ombres. Les normales ne contrôlent pas la lumière, elles contrôlent la façon dont la lumière doit se comporter à leur pied. La transition progressive des ombres d'une normale à la suivante est liée à une interpolation (exécutée par l'ordinateur). C'est de là que vient l'aspect de douce courbure de nos triangles alors qu'ils restent tout à fait plats.
Deux triangles texturés comportant des normales
Generation de deux Triangles en vrmlscript
Generating d'un sol avec le vrmlscript Quand vous aurez essayé quelques exemples en ajoutant de plus en plus de fonctions tug, une à la fois, de façon à ne pas prendre trop de risques sur l'endroit où se trouve celui sur lequel vous travaillez. Si vous ne savez plus où une des fonctions tug se trouve en train de tracter, faites-la temporairement tirer à une grande hauteur pour la repérer visuellement avec facilité. Revenez ensuite à la normale.
Animation de Triangles
Morphing (déformation) de 2 Triangles Copyright© 2000-2008 Graham Perrett
thyme@seamless3d.com
traduction Matthieu |