On programme la simulation du pilotage d'un vaisseau dans une scène 3D. Tout se passe comme si nous pilotions un vaisseau se déplaçant dans un espace à 3 dimensions qu'est la scène programmée et interprétée par povray.
L'interface de commande est un script ruby. La programmation en ruby est plus conviviale et moins laborieuse qu'en shell bash.
Les images sont mémorisées et numérotées puis agglomérées ultérieurement pour produire une animation.
Au départ, on place la camera à la postion <0,0,0>, on regarde dans une direction qui est l'axe des z, avec un zénith qui est l'axe des y, et une direction à droite qui est l'axe des x et dont le module est adapté au dimension de l'image de sortie, afin d'avoir des échelles horizontales et verticales identiques.
On fixe également un angle de vue qui est posé égal à 90°.
Puis on opère une rotation <rx,ry,rz> de la caméra, suivi d'un changemant d'échelle de 1/h, suivi d'une translation <tx,ty,tz>.
camera{
location 0
angle 90
right x*image_width/image_height
up y
direction z
rotate <rx,ry,rz>
scale 1/h
translate <tx,ty,tz>
}
L'instruction right x*image_width/image_height assure que l'image n'est pas déformée quelque soit ses dimensions dans le fichier ".ini".
La rotation <rx,ry,rz> est définie comme étant une rotation de rx degrès autour de l'axe des x, suivie d'une rotation de ry degrès autour de l'axe des y, suivie d'une rotation de rz degrès autour de l'axe des z. Puis le point de dépard étant <0,0,0>, on se translate à la position <tx,ty,tz>.
La camera étant ainsi programmée, le vaisseau se comportera comme suit :
| #version 3.7 #default { pigment { rgb 1 } } #declare S = function(x,y,z) { asin(z)} sky_sphere { pigment { function {S(x,y,z)} frequency 20 color_map { [0 rgb 0 ] [1 rgb 1 ] } } } light_source{<-9000,9000,-9000>, 1 } camera { location 0 direction z up y right x*image_width/image_height angle 90 rotate <rx,ry,rz> } sphere{<0,0,10>,3 } plane{y,-6 } |
Version 3.7 Par défaut la pigmentation des objets est blanche S = ((x,y,z) ↦ arcsin(z)). Définition du ciel Définition du pigment Selon le degrès de déclinaison autours de l'axe z Avec une fréquence de 20 Coloration en dent de scie 0 noir 1 blanc Source lumineuse placée en <-9000,9000,-9000>, de force 1 Camera Positionnée en <0,0,0> Direction du regard selopn l'axe des z Direction de la verticale selon l'axe des y Direction du tribord selon l'axe des x Angle de vue 90° Rotation <rx,ry,rz> Sphère à la position <0,0,13> de rayon 3 Plan perpendiculaire au vecteur y et de valeur rapportée sur l'axe y égale à -6 |
|
|||||||||||||||||||
Puis il existe un autre paramètre de localisation, qui est l'échelle h de l'observateur. Ce paramètre de position est indispensable pour naviguer aux abords d'une surface fractale qui se complexifie selon le niveau n d'itération du fractal. Il permet de réduire la taille du vaisseau et de passer par des trous de plus en plus petit. Le passage à l'échelle h s'effectue en exécutant scale 1/h sur la caméra. Mais se changement d'échelle doit s'opérer avant d'effectuer la translation sans quoi celle-ci s'en trouverait également changée.
L'échelle `h` croit en même temps que le niveau d'itération du fractal. Grosso-modo on peut constater que l'augmentation du niveau d'itération de `1` correspond à une augmentation d'un nombre de chiffres significatif à-peu-près constant. Ce qui signifie qu'il existe grosso-modo un facteur `xi` liant `h` et `n` :
`h=e^(xi n)`
Les variables tx, ty, tz, rx, ry, rz, h, n ou celles qui les déterminent, devront être mémorisées.
La direction de la camera est donnée par le vecteur z subissant la rotation <rx,ry,rz>. La direction désignant le haut est donnée par le vecteur y subissant la rotation <rx,ry,rz>. La direction désignant la droite est donnée par le vecteur x*image_width/image_height subissant la rotation <rx,ry,rz>.
Une difficulté apparaît dans le choix des noms de variable. Il est toujours préférable de choisir des noms de variable qui se rapprochent le plus de ceux utilisés dans l'expression de la théorie. Ceci afin de faciliter la transcription de la théorie au programme. Le langage povray n'autorise pas l'utilisation d'autres caractères que ceux habituellement utilisés, et les lettres `x,y,z,t,u,v` sont déjà utilisées par povray. Par contre, ruby autorise l'utilisation de toutes sortes de caractère. Pour contourner cette difficulté, il peut être utile d'avoir deux jeux de variables, l'un pour povray et l'autre pour ruby et la théorie, et un dictionnaire de traduction povray-ruby :
tx` ↔ x`
ty` ↔ y`
tz` ↔ z` rx` ↔ alpha`
ry` ↔ beta`
rz` ↔ gamma` h ` ↔ h`
Pour obtenir une animation élégante, il faut que la trajectoire soit harmonieuse et donc régulière. On pose une vitesse de translation `vec v` qui doit évoluer continûment. Et on pose une vitesse de basculement `vec w` qui doit évoluer continûment.
Et on pose une vitesse de changement d'échelle `u` qui doit évoluer continûment. Le vaisseau peut ainsi se réduire en taille, d'une façon régulière selon une vitesse de changement d'échelle, ce qui lui permettra en particulier de se faufiler dans les infractuosités toujours plus petite des surfaces fractales lorsqu'on s'y rapproche et que l'on augmente le niveau `n` d'itération du fractal.
L'échelle `h` se modifie en la multipliant par un facteur `k` qui évolue en fonction du temps. Cette évolution au cours du temps se traduit par l'équation différentielle suivante :
`h"←"(:t:)`
`k"←"(:t:)``h(:t"+"dt:)=h k^dt`
Donc
`ln(h(:t"+"dt:)) = ln(h)+ln(k)dt`
Cette dernière équation correspond à l'équation cinématique de la vitesse. Elle utilise la position logarithmique de l'échelle `ln(h)` que l'on note `b`, et sa vitesse `ln(k)` que l'on note `u`.
`b"="ln(h)`
`u"="ln(k)`
En conséquence :
La variable `b` est appelée l'échelle logarithmique. La variable `u` est appelée la vitesse d'échelle logarithmique.`b"←"(:t:)`
`u"←"(:t:)``b(:t"+"dt:) = b+udt`
`e^(b(:t"+"dt:)) = e^b e^(udt)`
`h(:t"+"dt:) = h e^(udt)`
Il y a 3 coordonnées de vitesse de translation, 3 coordonnées de vitesse de basculement, et une coordonnée de vitesse de changement d'échelle.
1- La vitesse de translation :
`vec v = [((dx)/dt),((dy)/dt),((dz)/dt)]`
1- La vitesse de basculement :
`vec w = [((d alpha)/dt),((d beta)/dt),((d gamma)/dt)]`
2- La vitesse de changement d'échelle `u` décrite précédement :
`u = (b(:t"+"dt:)-b)/(dt)`
`u = (db)/(dt)`
`u = (d ln(h))/(dt)`
`u = 1/h (dh)/(dt)`
La plus simple évolution continue d'une vitesse est l'évolution linéaire c'est à dire selon une accélération constante `vec a`. Parcontre l'accélération n'a pas besoin d'être continue. Il n'y a pas d'inertie sur l'accéleration. Son évolution se fait par à-coup, c'est à dire que l'accélération est constante pendant un certain temps, puis subit instantanément un changement de valeur pour rester constant à nouveau pendant un certain temps avec cette nouvelle valeur. Chaque modification de l'accéleration correspond à un ordre de navigation. La succession des ordres de navigation est mémorisée dans le journal de bord et permet de refaire le même chemin.
On se dote d'un mécanisme pour stabiliser l'orientation du vaisseau <rx,ry,rz>, en spécifiant l'état finale rechercher <fx,fy,fz>, et le temps imparti pour cela, `Delta`.
Pour chaque composante en x en y et en z de l'orientation `r`, la vitesse de basculement se note `w`. On suppose que l'accélération `k` est constante au signe près, telle que, elle puisse être appliquée sur une première partie du temps `delta`, puis être appliqué négativement sur la seconde partie du temps `Delta-delta`, afin que la vitesse finale soit nulle et que le paramètre finale soit le bon, c'est à dire telle que :
`r"←"(:t:)`
`w"←"(:t:)`
`k"←"(:t:)`` w(:t"+"Delta:) = 0`
`r(:t"+"Delta:) = f`
D'autre part nous avons :
`r(:t"+"dt:) = r + wdt + k dt^2/2`
` w(:t"+"dt:) = w + kdt`
`r(:t"+"Delta:) = r + w Delta + k delta^2/2 - k(Delta-delta)^2/2`
`r(:t"+"Delta:) = r + w Delta - kDelta^2/2 + k Deltadelta`
`w(:t"+"Delta:) = w + k delta - k(Delta-delta)`
`w(:t"+"Delta:) = w + 2 k delta - kDelta`
On résoud le système d'équation suivant :
`w + 2 k delta - kDelta = 0`
`r + w Delta - kDelta^2/2 + k Deltadelta = f`
---- 28 décembre 2020 ----
`(2delta-Delta)k=-w`
`(2delta-Delta)r + (2delta-Delta)w Delta - (2delta-Delta)kDelta^2/2 + (2delta-Delta)k Deltadelta = f`
`2delta r-Delta r + 2delta w Delta-Delta^2 w +w Delta^2/2 -w Deltadelta = f`
`delta(2 r + 2 w Delta - w Delta) = f+Delta^2 w/2`
`delta= (f+Delta^2 w/2)/(2 r + w Delta) ` `2 k delta = kDelta-w`
`2r + 2w Delta - kDelta^2 + 2k deltaDelta = 2f`
`2r + 2w Delta - kDelta^2 + (kDelta-w)Delta = 2f`
`2r + w Delta = 2f`
`w = 2(f-r)/Delta`
On considère un pas de temps constant `dt` entre chaque image. L'itération est donné par :
`vec x(:t"+"dt:) = vec x+vec vdt+vec adt^2/2`
`vec v(:t"+"dt:) = vec v+vec adt^2`
`h(:t"+"dt:) = h e^(udt)`
Et pour chaque composante de la rotation, Si `Delta` n'est pas nul, alors l'itération est donnée
`r(:t"+"dt:) = r + wdt + k dt^2/2`
`w(:t"+"dt:) = 2(f-r)/Delta`
Si au contraire `dt">"delta` alors l'itération est donné par :
`r(:t"+"dt:) = r + w dt - k dt^2/2`
`w(:t"+"dt:) = w + 2 k delta - kdt`
`Delta` est mémorisé. C'est un nombre entier de fois `dt`. Et s'il n'est pas nulle, il est recalculé après chaque itération comme suit :
`"Nouveau" Delta =Delta-dt`
Le script tourne en boucle et s'arrête lorsqu'on presse la touche 'esc', et ouvre le fichier de commande qui est un script ruby récapitulant toutes les variables en cours. L'utilisateur donne un ordre de pilotage en modifiant ce fichier. Puis il relance le script qui repare de son point d'arrêt. Pour cela, les variables suivantes doivent être mémorisées dans un fichier.
t = 0
x = 0
y = 0
z = 0vx = 0
vy = 0
vz = 0ax = 0
ay = 0
az = 0h = 1
n = 8rx = 0
ry = 0
rz = 0wx = 0
wy = 0
wz = 0`Delta` = 0
fx = 0
fy = 0
fz = 0
Installez les paquets suivant : build-essential, ruby-full
sudo apt install buid-essential ruby-full
installer le gem ruby2d
sudo gem ruby2d
Il se peut qu'un message vous indique qu'il faille d'abord installer quelques paquets. Procédez alors d'abord à l'installation de ces paquets.
Le programme ruby utilise la commande system("povray", args) pour commander povray, et utilise le gem ruby2d pour gérer l'affichage. Les images produitent sont numérotées en 4 chiffres en commençant par a0000.png
| #! /usr/bin/ruby -w
def iter() require 'ruby2d' p "Logiciel de pilotage dans une scène 3D POV-Ray" if $tt > 100 then close end show |
Shebang (exacutez "type ruby" pour savoir quel shebang mettre) Procédure modifiant les paramètres pour calculer l'image suivante Augmentation du temps Augmentation |
|||||
---- 18 décembre 2020 ----