Dado que a exponenciação com números imaginários tem o efeito de girar os números, decidi animar usando vetores de tamanho 2 em torno do zero. Então, eu começaria com 2 (o mandelbrot clássico). Girando o vetor por 90 graus no sentido anti-horário, eu chegaria a 0+2i. Mais 90 graus me levariam a -2, depois 0-2i e, finalmente, com 360 graus, eu estaria de volta a 2.
Então, a parte real varia com o cosseno e a parte imaginária varia com o seno. Basta dividir os 2*pi radianos do círculo pelo número de quadros que quisermos.
Testei primeiro com 4 passos e obtive as seguintes imagens:
use GD;
use strict;
use constant PI => 4 * atan2(1, 1);
use constant E => exp(1);
use constant MAXITER => 256;
use constant SIDE => 512;
use constant FRAMES => 1000;
sub mandel($$$$) {
my $c=1;
my ($x, $y, $rp, $ip)=@_;
my $r=$x;
my $i=$y;
while($r**2+$i**2<4 && $c<MAXITER) {
my $a=atan2($i,$r);
my $b=$r**2+$i**2;
my $p=($b**($rp/2))*(E**(-1*$ip*$a));
my $nr=$p*cos($rp*$a+0.5*$ip*($b!=0?log($b):0));
my $ni=$p*sin($rp*$a+0.5*$ip*($b!=0?log($b):0));
$r=$nr+$x;
$i=$ni+$y;
$c++;
}
return $c;
}
my $img=new GD::Image(SIDE,SIDE);
my @colours=();
for my $c (0..255) {
$colours[$c]=$img->colorAllocate(($c*7)%255, ($c*13)%255, ($c*19)%255),
};
for my $frame (0..FRAMES-1) {
my $theta=0;
if($frame>0) {
$theta=(2*PI)*($frame/FRAMES);
}
my $ip=2*sin($theta);
my $rp=2*cos($theta);
for my $a (0..SIDE) {
for my $b (0..SIDE) {
my $d=mandel(-2+(4*$a/SIDE), -2+(4*$b/SIDE), $rp, $ip);
$img->setPixel($a, $b, $colours[$d]);
}
}
open(IMAGE, sprintf(">frame%04d.png", $frame));
binmode IMAGE;
print IMAGE $img->png;
close IMAGE;
}
O código é simples e a biblioteca GD torna fácil a geração de PNGs (ou GIFs ou JPEGs...). Depois, usei ffmpeg para juntar tudo numa animação.
ffmpeg -i frame%04d.png -vf curves=preset=lighter video.mp4
E o resultado final é este vídeo:
O vídeo está no youtube também.
Nenhum comentário:
Postar um comentário