Escolar Documentos
Profissional Documentos
Cultura Documentos
TG319 - Cleber Foletto Pedrozo PDF
TG319 - Cleber Foletto Pedrozo PDF
CENTRO DE TECNOLOGIA
CURSO DE CIÊNCIA DA COMPUTAÇÃO
ANIMAÇÃO DE UM FRACTAL
UTILIZANDO MÚSICA EM PURE DATA
TRABALHO DE GRADUAÇÃO
por
elaborado por
Cleber Foletto Pedrozo
COMISSÃO EXAMINADORA:
Trabalho de Graduação
Curso de Ciência da Computação
Universidade Federal de Santa Maria
Trabalho de Graduação
Undergraduate Program in Computer Science
Universidade Federal de Santa Maria
This paper presents a method for animating fractals from music in Pure Data software.
From the study of the fractal theory and the programming environment aimed at the media
called Pure Data to implement a component that synchronizes music with the Julia’s
fractal. Using the Pure Data it was possible to extract music caracteristics, which are
used as parameters for the animation. To maintain the characteristc of Pure Data that
runs their applications in real time, was faced with a concurrence problem, where the
CPU is overloaded with rendering the video. To solve this problem, is adopted among
some solutions, to use the GPU for math’s graphics. The result is a synchronization
object between the structure responsible for the music and the structure responsible for
the animation. Thus, this work also has information for future optimization approaches
and synchronism of fractals and music. It also provides information and a brief tutorial
on the implementation of components for Pure Data.
2.1 Componentes do Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 O código da direita sendo encapsulado no objeto "pd MusicStruct" . . . 15
2.3 Componentes do Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.4 Fractal de Mandelbrot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5 Fractal de Julia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
PD Pure Data
GEM Graphics Environment for Multimedia
CPU Central Processing Unit
GPU Graphics Processing Unit
MIDI Musical Instrument Digital Interface
GLSL GL Shading Language
SUMÁRIO
1 INTRODUÇÃO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.1 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2 Contribuições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3 Estrutura do Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2 CONCEITOS E TECNOLOGIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1 Pure Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1.1 Componentes visuais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1.2 Externals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.3 Recursos do Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.4 GEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2 Fractais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.1 Números Complexos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.2 Mandelbrot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.3 Fractal de Julia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3 Shading Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3 TRABALHOS RELACIONADOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1 Programas sobre Fractais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.1 Fractint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.2 Xaos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.3 Emndl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.4 Música Fractal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4 METODOLOGIA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.1 Gerando os fractais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.1.1 Criando externals para Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.2 Utilizando música para gerar o fractal. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2.1 Problemas Encontrados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.3 Implementação com Fragment Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3.1 Estrutura Utilizada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3.2 Objeto de Sincronização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.3.3 Movimentação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.3.4 Programação em Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.4 Utilizando outros fractais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5 CONCLUSÕES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
REFERÊNCIAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
APÊNDICE A CÓDIGOS FONTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
A.1 Implementação em C++ e Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
A.1.1 Códigos em C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
A.1.2 Código em Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
A.2 Implementação em Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
A.2.1 Programação do fragment shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
A.2.2 Programação do external de sincronização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
A.2.3 Programação em Pd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1 INTRODUÇÃO
para iniciantes. Como exemplos tem-se o Max/MSP (CYCLING74, 2011), Csound (CLE-
MENTS, 2011), Supercollider (MCCARTNEY, 2011) e Pure Data (Pd)(ARMFIELD,
2006).
Para este estudo escolheu-se o Pure Data, que é um ambiente de programação de alto
nível baseado em diagramas de fluxo. O caminho dos dados é visualizado graficamente
através de linhas que ligam os componentes, facilitando a prática de programação. Além
disso, a execução é em tempo real, podendo-se adicionar, remover e alterar componentes
no ambiente em tempo de execução. Os componentes no Pure Data são chamados de
externals, que são funções desenvolvidas em outras linguagens de programação e que
aparecem no ambiente como objetos.
1.1 Objetivos
Neste contexto, este trabalho consiste na criação de um objeto em Pure Data que sin-
cronizará fractais a partir de músicas. Utilizando os atributos da música como parâmetros
é possível criar uma animação em tempo real. Serão apresentadas técnicas usadas para
concorrência e para a movimentação do fractal, assim como técnicas usadas em outros
programas de geração de fractais. Além disso, serão apresentados conceitos de fractais e
uma visão geral sobre o Pure Data.
O objetivo geral deste trabalho é desenvolver um objeto para sincronizar música com
fractal, utilizando o ambiente de programação chamado Pure Data. A idéia é que esse
objeto alterará o fractal usando a freqüência e a amplitude da música como parâmetros.
Assim, os objetivos específicos incluem uma série de pontos:
1.2 Contribuições
volvedores iniciais. Este ensina a criar objetos gráficos para Pure. Tal tutorial foi escrito
devido à falta de material sobre o assunto.
• Object: principal componente do Pd. Executa funções sempre que algum inlet
recebe uma informação, este gera um callback e executa sua função específica. Os
resultados calculados pelo objeto são enviados através de outlets para os compo-
nentes seguintes. Em alguns casos, esses resultados são enviados diretamente para
um dispositivo de saída.
• Bang: componente do Pd que dispara "ações". Ele executa as funções dos objetos
enviado um sinal para as mesmas;
• Message: Envia uma string que é interpretada pelo objeto como uma entrada. Este
componente é executado através do usuário através do mouse ou um sinal emitido
pelo Bang;
Entre outros objetos gráficos como barra de rolagem vertical e horizontal, gráficos,
vetores, etc.
2.1.2 Externals
2.1.3 Recursos do Pd
2.1.4 GEM
O GEM (Graphics Environment for Multimedia) é uma biblioteca gráfica para o Pd ba-
seado em OpenGL, originalmente criado para plataformas win32 por Mark Danks, Gün-
ter Geiger portou o GEM para Linux e James Tittle para OS-X. Atualmente está sendo
gerenciado por Iohannes zmölnig (ZMÖLNIG, 2011). O GEM utiliza OpenGL entre ou-
tros recursos e praticamente todos os comandos de OpenGL já estão implementados para
GEM. Além do GEM existe outra biblioteca gráfica muito parecida chamada PDP (Pure
Data Package). PDP também foi implementado com OpenGL e muito utilizada no Pd
bem como o GEM.
17
2.2 Fractais
Para entender os fractais utilizados neste trabalho, é apresentada uma introdução sobre
números complexos.
Um número complexo é formado por duas partes, uma real e outra imaginária. A parte
√
imaginária permite tirar a raiz quadrada de um número negativo, por definição: −1 = i,
ou seja, i2 = −1.
Um número complexo, normalmente referenciado pela letra Z, é a soma de um número
real com, um número real multiplicado por um número imaginário (WEGNER; TYLER,
1995).
Ou seja:
Z = a + bi, onde "a"e "b" são números reais.
Podemos criar 2 eixos para mapear os números complexos, um eixo para a parte real e
outro para a parte imaginária.
O objetivo de estudar números complexos é determinar se um determinado ponto
pertence a um conjunto de Mandelbrot mostrado na Figura 2.4.
2.2.2 Mandelbrot
Para criar o fractal de Mandelbrot, é preciso verificar para cada pixel se ele pertence
ou não ao conjunto. Essa verificação se dá através de uma fórmula, onde os pixels são
testados se eles ultrapassam um raio pré-definido. Normalmente o pixel que pertence ao
conjunto não se distancia muito da posição inicial, formando uma órbita. Para o conjunto
18
de Mandelbrot, o menor raio usado é 2, pois é o menor raio para que o conjunto inteiro
seja calculado (WEGNER; TYLER, 1995). A seqüência de Mandelbrot é definida pela
fórmula:
Zn+1 = Zn2 + c
Onde c é um número complexo que recebe o valor do pixel analisado.
Para verificar se o pixel escapa da órbita, usamos a fórmula da distância do ponto à origem.
√
d = a2 + b 2
Assumindo "a" como a parte real, e "b" como a parte imaginária .
O conjunto de Julia foi nomeado devido aos estudos do matemático Francês Gaston
Julia onde ficou famoso por volta de 1920 devido ao seu artigo "Mémoire sur l’itération
des fonctions rationnelles", publicado no jornal de matemática em 1918 (COMMUNI-
CATIONS, 2011). Considerando a fórmula de iteração do conjunto de Mandelbrot, usa-se
um número complexo "c" onde varia a cada Zpixel . Gaston Julia modificou a fórmula de
Mandelbrot e manteve "c" constante. Este processo resultou em fractais diferentes para
cada ponto utilizado. O conjunto de Maldelbrot serve então como um catálogo para os
fractais de Julia. Cada ponto pertencente ao fractal de Maldelbrot serve como índice a ser
usado no fractal de Julia. Com isso:
Zn+1 = Zn2 + k
Onde k é um número complexo mantém-se constante para todos os pixels.
A Figura 2.5 mostra o fractal de Mandelbrot e os respectivos fractais de Julia de
acordo com o índice usado na criação do fractal.
Shader são instruções de máquina que rodam na GPU. Inicialmente a programação era
feita em ASSEMBLY, tornando a programação difícil. Com isso, foram surgindo lingua-
gens de alto nível para a programação em GPU. Como por exemplo HLSL da Microsoft e
GLSL da OpenGL (PASTOR, 2011).
A arquitetura do OpenGL Shading Language é constituída por vertex processor, res-
ponsável por instruções como transformações de vértices e normais, geração e transfor-
mação de coordenadas de texturas e iluminação. Outro processador pertencente é o frag-
19
ment processor, responsável pela definição da cor e da coordenada "Z" dos fragmentos
pixels. Atualmente esses processadores estão sendo substituídos por Stream Processor,
cujo processador desempenha ambas as funções. Cada um destes processadores opera em
paralelo aos demais SIMD (Single Instruction Multiple Data) (POZZER, 2009).
Um programa que usa a linguagem shader, utiliza um código GLSL que é compilado
e anexado ao programa principal. É possível ter apenas vários shaders de vértices e de
fragmentos, porém apenas um de cada ativo.
Programas que rodam em GPU são bem mais rápidos dos que rodam em CPU. Isto
porque a arquitetura de uma GPU é baseada em pipeline (um pipeline de um processador
Pentium 4 tem aproximadamente 10 estágios, enquanto o de uma GPU tem algo em torno
de 1000) (PASTOR, 2011).
3 TRABALHOS RELACIONADOS
3.1.1 Fractint
Fractint, foi o primeiro programa que gera fractais a ficar conhecido. Criado em 1988,
escrito em DOS e recebendo o nome por usar números inteiros, devido aos computadores
da época não trabalharem com ponto flutuante (JONES, 2004). O programa conta com
mais de mil fórmulas, onde o usuário pode gerar os fractais e dar vários zooms por uma
seleção da área desejada.
Com a popularização do Fractint, foram aparecendo outros programas para criação
de fractais, como Ultra Fractal, Xaos fractal, Terry W. Gintz’s programs, Mind-Boggling
Fractals, entre outros (JONES, 2004).
3.1.2 Xaos
3.1.3 Emndl
Figura 3.3: Tela principal do programa escrito em Pd para geração de música fractal
4 METODOLOGIA
Figura 4.1: Sequência de fractais de Julia utilizando o primeiro objeto criado na imple-
mentação
/ / .H
c l a s s GEM_EXTERN f r a c t a l : p u b l i c GemShape
{
CPPEXTERN_HEADER( f r a c t a l , GemShape )
...
/ / . CPP
/ / definindo quantos i n l e t s o external vai t e r
CPPEXTERN_NEW_WITH_THREE_ARGS( f r a c t a l ,
t _ f l o a t a r g , A_DEFFLOAT , / / i n l e t 1 , u s a d o p e l o GEM
t _ f l o a t a r g , A_DEFFLOAT , / / i n l e t 2 , r e c e b e k i m a g i n á r i o
t _ f l o a t a r g , A_DEFFLOAT ) ; / / i n l e t 3 , r e c e b e k r e a l
/ / método c o n s t r u t o r
f r a c t a l : : f r a c t a l ( t _ f l o a t a r g r , t _ f l o a t a r g Ki , t _ f l o a t a r g Kr )
: arg1 ( r ) , Kimag ( Ki ) , K r e a l ( Kr )
{
L _ i n l e t = i n l e t _ n e w ( t h i s −>x _ o b j , &t h i s −>x _ o b j −>ob_pd ,
&s _ f l o a t , gensym ( " i n L " ) ) ;
R _ i n l e t = i n l e t _ n e w ( t h i s −>x _ o b j , &t h i s −>x _ o b j −>ob_pd ,
&s _ f l o a t , gensym ( " inR " ) ) ;
}
v o i d f r a c t a l : : r e n d e r ( GemState ∗ s t a t e )
{
/ / desenha f r a c t a l
}
/ / c o n f i g u r a r os métodos dos i n l e t s
void f r a c t a l : : o b j _ s e t u p C a l l b a c k ( t _ c l a s s ∗ c l a s s P t r )
{
class_addmethod ( c l a s s P t r , r e i n t e r p r e t _ c a s t <t_method >
(& f r a c t a l : : ChangeARG2Callback ) , gensym ( " i n L " ) , A_FLOAT , A_NULL ) ;
v o i d f r a c t a l : : ChangeARG2Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r )
{
GetMyClass ( d a t a )−>ChangeARG2 ( v a l o r ) ;
}
/ / funções executadas pela callback , a t u a l i z a o v a l o r das v a r i á v e i s
v o i d f r a c t a l : : ChangeARG1 ( f l o a t v a l o r )
{
Kimag = s i z e ;
setModified ( ) ;
}
v o i d f r a c t a l : : ChangeARG2 ( f l o a t v a l o r )
{
Kreal = s i z e ;
setModified ( ) ;
}
A janela padrão do GEM possui um tamanho de 500 x 500 pixels. Como cada pixel é
testado aproximadamente 140 vezes para verificar se escapa de sua órbita, foi detectado
um problema na concorrência da renderização do fractal e a música. Este resultou em uma
interrupção constante na execução da música. O problema está basicamente relacionado
à grande quantidade de cálculos necessários para renderizar cada pixel. Foram estudadas
diversas possibilidades para resolver o problema, entre elas:
continuar os mesmos.
• Fragment shader - Usar a GPU para os cálculos do fractal, pois fragment shader
utiliza o pipeline da placa de vídeo para os cálculos dos pixels, pois cada pixel é
calculado em paralelo e transformado em uma textura, deixando a CPU rodando a
música e outros cálculos.
da cor de cada pixel seja independente dos demais, ou seja, cada pixel a ser calculado
executa o código escrito em GLSL do arquivo "fractal.frag" paralelamente.
A função criada detecta a coordenada do pixel corrente, chamando a função "isInside",
onde verifica o tempo de escape do pixel guardando a informação na variável "inside".
Caso a variável tenha um valor -1, o pixel é definido apenas com base no ponto complexo,
pois ele pertence ao conjunto de Júlia. Entretanto se a variável não for -1, a cor do pixel
é definida com base no tempo de escape, conforme Figura 4.7, onde mostra a função
principal do código em GLSL.
A função descrita na Figura 4.8 mostra a função utilizada para testar a órbita de escape
do pixel corrente. O pixel é testado por um número pré-definido de iterações através da
variável "MaxIterations", retornando "n" onde representa o tempo de escape do pixel. As
variáveis "radius", "cim" e "creal", são definidas externamente pelas variáveis "uniform
float".
29
v o i d main ( )
{
vec2 p o s i t i o n = gl_FragCoord ;
int inside= isInside ( position . x , position . y );
i f ( i n s i d e ==−1)
{
g l _ F r a g C o l o r = v e c 4 ( cim ∗ 2 / 3 , c r e a l ∗ 2 / 3 , ( cim+ c r e a l ) , 1 . 0 ) ;
}
else
{
gl_FragColor
= v e c 4 ( ( f l o a t ) ( cim+ c r e a l ) ∗ i n s i d e ∗ 2 / M a x I t e r a t i o n s + 0 . 1 ,
( f l o a t ) i n s i d e ∗2/ MaxIterations +0.2 ,
( f l o a t ) i n s i d e ∗2/ MaxIterations +0.4 ,1);
}
}
Foi criado um external em Pd para sincronizar a música com o fractal. Esse objeto
guarda o estado atual e utiliza para criar um novo estado, que é definido como um fractal
de Júlia criado a partir de um ponto complexo e um raio. A música quando é executada,
envia como parâmetros para o objeto, a amplitude e a frequência da nota musical. Com
esses parâmetros, o objeto é capaz de calcular o próximo fractal a ser criado, assim como
o seu tamanho. Este procedimento, quando bem configurado, sincronizará a música e o
fractal.
4.3.3 Movimentação
Para dar efeito de movimentação do fractal foram utilizadas duas técnicas, a primeira
é mudar o raio de acordo com a diferença de amplitude, este passo aproximará ou afastará
o fractal. Foi então criada uma função para gerar o raio:
Existem algumas observações sobre essa função:
• a função verifica se amplitude atual for maior que a anterior e se essa mudança é
significativa. Então o raio será aumentado;
u n i f o r m f l o a t cim , c r e a l , r a d i u s ;
int MaxIterations = 140;
int isInside ( int x , int y)
{
f l o a t MinRe , MaxRe , MinIm , MaxIm ,
Re_factor , Im_factor ,
Z_re , Z_im , c_im , c _ r e ,
Z_re2 , Z_im2 ;
i n t HEIGHT = 5 0 0 ;
i n t WIDTH = 5 0 0 ;
int n ;
MinRe = ( f l o a t )− r a d i u s ;
MaxRe = ( f l o a t ) r a d i u s ;
MinIm = ( f l o a t )− r a d i u s ;
MaxIm = ( f l o a t ) r a d i u s ;
R e _ f a c t o r = ( MaxRe−MinRe ) / ( WIDTH− 1 ) ;
I m _ f a c t o r = ( MaxIm−MinIm ) / ( HEIGHT− 1 ) ;
c_im = MaxIm − y ∗ I m _ f a c t o r ;
c _ r e = MinRe + x ∗ R e _ f a c t o r ;
Z_re = c _ r e ;
Z_im = c_im ;
f o r ( n = 0 ; n< M a x I t e r a t i o n s ; ++n )
{
Z_re2 = Z_re ∗ Z_re ;
Z_im2 = Z_im∗Z_im ;
i f ( Z _ r e 2 + Z_im2 > 4 )
{
return n ;
}
Z_im = 2∗ Z _ r e ∗Z_im + cim ;
Z _ r e = Z _ r e 2 − Z_im2 + c r e a l ;
}
r e t u r n −1;
}
• No final da função atribui-se um valor ao raio. Este valor sofre um ajuste, para não
deixar o raio zerar no caso da amplitude ser nula;
void g e r a r _ r a i o ( t _ m f r a c ∗x )
{
/ / s e v i e r uma a m p l i t u d e m a i o r que a a t u a l , e s e e s s a a m p l i t u d e .
/ / f o r s i g n i f i c a t i v a e n t ã o o r a i o aumenta r á p i d o
i f ( x−>Amp − x−>AmpAnt >TOLERANCIA)
{
/ / r a i o aumenta rápido , c a i devagar , p a r a dar maior e f e i t o p a r a
/ / amplitudes a l t a s ;
x−>AmpAnt +=INCREMENTO ;
}
x−>AmpAnt −= DECREMENTO;
/ / O a j u s t e do r a i o s e r v e p a r a a j u s t a r o tamanho do f r a c t a l
/ / sem a a p l i c a ç ã o da a m p l i t u d e
x−> r a d i u s = x−>AmpAnt / DIV + AJUSTE_DO_RAIO ;
o u t l e t _ f l o a t ( x−>R a d i u s _ o u t , x−> r a d i u s ) ;
}
4.3.4 Programação em Pd
A primeira parte da função calcula a velocidade que irá assumir, levando em conside-
ração a diferença de frequência. A primeira verificação é em relação a variável "count".
Esta variável guarda o "tempo" que o ponto tem limitações na direção. Durante este
tempo, o vetor direção irá ser gerado aleatoriamente entre as direções que são opostas
a borda que foi atingida. Quando o contador é zerado, todas as direções ficam disponí-
veis novamente. No final da função é feita a verificação se alguma borda foi atingida.
Esta borda esta definida pela constante "LIMITE", onde por padrão foi definida em 0.9, o
tempo de retorno é definido pela variável "RETORNA", que por padrão é 10;
A Figura 4.12 mostra a sincronização da música com o fractal utilizando as soluções
vistas no presente trabalho. Foi obtido uma animação dinâmica quando implementado
essa nova abordagem.
33
void g e r a r _ d e s l o c a m e n t o ( t _ m f r a c ∗x )
{
float d;
int r ;
d=x−>F r e q − x−>F r e q A n t ; / / lim 1
d=d / DIV_FREQ ; // _______
d=d ∗ d ; // |0 1 2|
x−>s p e e d =d ; / / lim 4 | 7 P 3 | lim 2
s r a n d ( t i m e (NULL ) ) ; // |6 5 4|
i f ( x−>c o u n t ) // −−−−−−−
{ // lim 3
s w i t c h ( x−>l i m ) {
c a s e 1 : / / g e r a 4 , 5 ou 6
r = ( i n t ) r a n d ()%3 + 4 ;
break ;
c a s e 2 : / / g e r a 6 , 7 ou 0
r =( i n t ) rand ()%3+6;
i f ( r ==8) r = 0 ;
break ;
c a s e 3 : / / g e r a 0 , 1 ou 2
r =( i n t ) rand ()%3;
break ;
c a s e 4 : / / g e r a 2 , 3 ou 4
r = ( i n t ) r a n d ()%3 + 2 ;
break ;
}
} e l s e r =( i n t ) rand ()%8;
x−> d e s l x = x−> d i r e c a o [ r ] [ 0 ] ;
x−> d e s l y = x−> d i r e c a o [ r ] [ 1 ] ;
i f ( x−>c_im >LIMITE ) {x−>l i m = 1 ; x−>c o u n t = RETORNA; }
i f ( x−> c _ r e a l >LIMITE ) {x−>l i m = 2 ; x−>c o u n t = RETORNA; }
i f ( x−>c_im<−LIMITE ) {x−>l i m = 3 ; x−>c o u n t = RETORNA; }
i f ( x−> c _ r e a l <−LIMITE ) { x−>l i m = 4 ; x−>c o u n t = RETORNA; }
x−>c o u n t −−;
}
Para utilização de fractais que possuem fórmulas fixas, a animação deve ser voltada à
transformações e aplicação de efeitos na textura do fractal. A partir da textura criada pelo
shader é possível aplicar efeitos e filtros à essa textura antes de mostrar na tela. Esses
efeitos devem ser sincronizados pela música.
34
REFERÊNCIAS
robotic-knives-patched-in-pd-circuit-bent-graphics-cards/.
Acesso em: Junho de 2011.
WEGNER, T.; TYLER, B. Criando Fractais. [S.l.]: Axcel Books do Brasil Editora,
1995.
# d e f i n e WIDTH 500
# d e f i n e HEIGHT 500
# d e f i n e M a x I t e r a t i o n s 30
CPPEXTERN_NEW_WITH_THREE_ARGS
( fractal ,
t _ f l o a t a r g , A_DEFFLOAT , / / i n l e t 1 , u s a d o p e l o GEM
t _ f l o a t a r g , A_DEFFLOAT , / / i n l e t 2 , r e c e b e k i m a g i n á r i o
t _ f l o a t a r g , A_DEFFLOAT ) ; / / i n l e t 3 , r e c e b e k r e a l
fractal :: f r a c t a l ( t _ f l o a t a r g r , t _ f l o a t a r g Ki , t _ f l o a t a r g Kr )
: arg1 ( r ) , Kimag ( Ki ) , K r e a l ( Kr )
{
L _ i n l e t = i n l e t _ n e w ( t h i s −>x _ o b j , &t h i s −>x _ o b j −>ob_pd , &s _ f l o a t , gensym ( " i n L " ) ) ;
R _ i n l e t = i n l e t _ n e w ( t h i s −>x _ o b j , &t h i s −>x _ o b j −>ob_pd , &s _ f l o a t , gensym ( " inR " ) ) ;
}
fractal :: ~ fractal ()
{ }
v o i d f r a c t a l : : r e n d e r ( GemState ∗ s t a t e )
{
/ / a j u s t e da c â m e r a p a r a a v i s u a l i z a ç ã o do f r a c t a l
g l C l e a r ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
g l M a t r i x M o d e ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
g l u O r t h o 2 D ( 0 , WIDTH, 0 , HEIGHT ) ;
g l M a t r i x M o d e (GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
/ / i n i c i a l i z a ç ã o das v a r i á v e i s
MinRe = −2; MaxRe = 2 . 0 ; MinIm = −2;
MaxIm = MinIm + ( MaxRe−MinRe )∗HEIGHT / WIDTH ;
R e _ f a c t o r = ( MaxRe−MinRe ) / ( WIDTH−1);
I m _ f a c t o r = ( MaxIm−MinIm ) / ( HEIGHT−1);
/ / l a ç o s que p e r c o r r e t o d o s o s p i x e l s
f o r ( y = 0 ; y<HEIGHT ; y ++)
{
c_im = MaxIm − y∗ I m _ f a c t o r ;
f o r ( x = 0 ; x<WIDTH ; x ++)
{
c _ r e = MinRe + x∗ R e _ f a c t o r ;
Z_re = c _ r e ;
Z_im = c_im ;
i s I n s i d e = true ;
/ / p a r a c a d a p i x e l v e r i f i c a s e nao e s c a p a do r a i o 2
f o r ( n = 0 ; n< M a x I t e r a t i o n s ; ++n )
{
/ / d= r a i z ( a ^2 + b ^ 2 )
/ / e l e v a ambos o s t e r m o s ao q u a d r a d o p a r a a c e l e r a r o s c á l c u l o s
/ / d ^2= a ^2 + b ^2
/ / v e r i f i c a s e a d ^2 > r ^2
Z _ r e 2 = Z _ r e∗Z _ r e ;
Z_im2 = Z_im∗Z_im ;
i f ( Z _ r e 2 + Z_im2 > 4 )
{
/ / s e e s c a p o u do r a i o e s c o l h e a c o r do p i x e l de a c o r d o com o n
40
isInside = false ;
glColor3f (( float ) n ∗2/ M a x I t e r a t i o n s ∗ K r e a l + 0 . 2 ,
( float ) n ∗2/ M a x I t e r a t i o n s ∗ K r e a l + 0 . 2 ,
( float ) ( n ∗2/ M a x I t e r a t i o n s )∗ Kimag + 0 . 3 ) ;
break ;
}
/ / s e nao e s c a p o u do r a i o c a l c u l a o p r ó x i m o Z
Z_im = 2∗ Z _ r e∗Z_im + ( d o u b l e ) ( K r e a l ) ;
Z _ r e = Z _ r e 2 − Z_im2 + ( d o u b l e ) ( Kimag ) ;
}
i f ( ! i s I n s i d e ){
/ / p i n t a o p i x e l c a s o t e n h a s a í d o de ó r b i t a
g l B e g i n ( GL_POINTS ) ;
glVertex2f (x , y );
glEnd ( ) ;
}
}
}
}
/ / f u n ç õ e s de c a l l b a c k
v o i d f r a c t a l : : ChangeARG2Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r )
{
GetMyClass ( d a t a )−>ChangeARG2 ( v a l o r ) ;
}
v o i d f r a c t a l : : ChangeARG1Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r )
{
GetMyClass ( d a t a )−>ChangeARG1 ( v a l o r ) ;
}
v o i d f r a c t a l : : ChangeARG1 ( f l o a t v a l o r )
{
Kimag = s i z e ;
setModified ( ) ;
}
/ / c o n f i g u r a r os métodos dos i n l e t s
void f r a c t a l : : o b j _ s e t u p C a l l b a c k ( t _ c l a s s ∗ c l a s s P t r )
{
c l a s s _ a d d m e t h o d ( c l a s s P t r , r e i n t e r p r e t _ c a s t < t _ m e t h o d >(& f r a c t a l : : ChangeARG2Callback ) ,
gensym ( " i n L " ) , A_FLOAT , A_NULL ) ;
c l a s s _ a d d m e t h o d ( c l a s s P t r , r e i n t e r p r e t _ c a s t < t _ m e t h o d >(& f r a c t a l : : ChangeARG1Callback ) ,
gensym ( " inR " ) , A_FLOAT , A_NULL ) ;
}
c l e b e r p e d r o z o @ g m a i l . com
T h i s i s a i m p l e m e n t a t i o n t e s t , i t s an e x t e r n a l f o r p u r e d a t a w i t c h r e c e i v e 2 f l o a t s and f o r e a c h p i x e l
i s made m a t h s t o d e t e c t i f t h e p i x e l i s i n s i d e o f f r a c t a l .
∗/
# i f n d e f INCLUDE_fractal_H_
# d e f i n e INCLUDE_fractal_H_
c l a s s GEM_EXTERN f r a c t a l : p u b l i c GemShape
{
CPPEXTERN_HEADER( f r a c t a l , GemShape )
public :
f r a c t a l ( t _ f l o a t a r g a r g 1 , t _ f l o a t a r g Kimag , t _ f l o a t a r g K r e a l ) ;
virtual ~ fractal ( ) ;
private :
// variáveis
t_inlet ∗L _ i n l e t ,∗ R _ i n l e t ;
f l o a t a r g 1 , Kimag , K r e a l ;
d o u b l e MinRe , MaxRe ,
MinIm , MaxIm ,
Re_factor , Im_factor ,
c_im , c _ r e ,
Z_re , Z_re2 ,
Z_im , Z_im2 ;
int x , y , n ;
bool i s I n s i d e ;
/ / funções :
/ / f u n ç ã o que d e s e n h a o f r a c t a l em t e l a
v i r t u a l void r e n d e r ( GemState ∗ s t a t e ) ;
/ / f u n ç õ e s de c a l l b a c k
s t a t i c v o i d ChangeARG2Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r ) ;
s t a t i c v o i d ChangeARG1Callback ( v o i d ∗ d a t a , t _ f l o a t a r g v a l o r ) ;
41
/ / f u n ç õ e s chamadas p e l a c a l l b a c k
v o i d ChangeARG2 ( f l o a t v a l o r ) ;
v o i d ChangeARG1 ( f l o a t v a l o r ) ;
};
# endif
A.1.2 Código em Pd
int n ;
MinRe = ( f l o a t )− r a d i u s ;
MaxRe = ( float ) radius ;
MinIm = ( f l o a t )− r a d i u s ;
MaxIm = ( float ) radius ;
Re_factor = ( MaxRe−MinRe ) / ( WIDTH−1);
Im_factor = ( MaxIm−MinIm ) / ( HEIGHT−1);
c_im = MaxIm − y∗ I m _ f a c t o r ;
c _ r e = MinRe + x∗ R e _ f a c t o r ;
Z_re = c _ r e ;
Z_im = c_im ;
f o r ( n = 0 ; n< M a x I t e r a t i o n s ; ++n )
{
Z _ r e 2 = Z _ r e∗Z _ r e ;
Z_im2 = Z_im∗Z_im ;
i f ( Z _ r e 2 + Z_im2 > 4 )
{
return n ;
}
Z_im = 2∗ Z _ r e∗Z_im + cim ;
Z _ r e = Z _ r e 2 − Z_im2 + c r e a l ;
}
r e t u r n −1;
}
v o i d main ( )
{
vec2 p o s i t i o n = gl_FragCoord ;
int inside= isInside ( position . x , position . y );
i f ( i n s i d e ==−1)
{
g l _ F r a g C o l o r = v e c 4 ( cim ∗ 2 / 3 , c r e a l ∗ 2 / 3 , ( cim+ c r e a l ) , 1 . 0 ) ;
}
else
{
gl_FragColor
= v e c 4 ( ( f l o a t ) ( cim+ c r e a l )∗ i n s i d e ∗2/ M a x I t e r a t i o n s + 0 . 1 ,
( f l o a t ) i n s i d e ∗2/ M a x I t e r a t i o n s + 0 . 2 ,
( f l o a t ) i n s i d e ∗2/ M a x I t e r a t i o n s +0.4 ,1);
}
}
typedef s t r u c t _mfrac {
t _ o b j e c t x_obj ;
t _ i n t count , lim ;
t _ f l o a t r a d i u s , Amp, Freq , s p e e d , d e s l x , d e s l y ;
t _ f l o a t mod , AmpAnt , FreqAnt , c_im , c _ r e a l , c_imAnt , c _ r e a l A n t ;
t _ o u t l e t ∗c _ o u t , ∗ R a d i u s _ o u t , ∗ c 2 _ o u t ;
int direcao [8][2];
/ / c_out é a saída r e l a t i v o à constante imaginária C,
/ / onde c _ o u t r e p r e s e n t a a p a r t e r e a l e c 2 _ o u t a p a r t e i m a g i n á r i a =>
/ / c= a+ b i ( a= c _ o u t , b= c 2 _ o u t )
} t_mfrac ;
v o i d g e r a r _ d e s l o c a m e n t o ( t _ m f r a c ∗x )
{
float d;
int r ;
d=x−>F r e q − x−>F r e q A n t ; / / lim 1
d=d / DIV_FREQ ; // _______
d=d∗d ; // |0 1 2|
x−>s p e e d =d ; / / lim 4 | 7 P 3 | lim 2
s r a n d ( t i m e (NULL ) ) ; // |6 5 4|
i f ( x−>c o u n t ) // −−−−−−−
{ // lim 3
s w i t c h ( x−>l i m ) {
c a s e 1 : / / g e r a 4 , 5 ou 6
r = ( i n t ) r a n d ()%3 + 4 ;
break ;
c a s e 2 : / / g e r a 6 , 7 ou 0
r =( i n t ) rand ()%3+6;
i f ( r ==8) r = 0 ;
break ;
c a s e 3 : / / g e r a 0 , 1 ou 2
r =( i n t ) rand ()%3;
43
break ;
c a s e 4 : / / g e r a 2 , 3 ou 4
r = ( i n t ) r a n d ()%3 + 2 ;
break ;
}
} e l s e r =( i n t ) rand ()%8;
x−>d e s l x = x−>d i r e c a o [ r ] [ 0 ] ;
x−>d e s l y = x−>d i r e c a o [ r ] [ 1 ] ;
i f ( x−>c_im >LIMITE ) {x−>l i m = 1 ; x−>c o u n t = RETORNA; }
i f ( x−>c _ r e a l >LIMITE ) {x−>l i m = 2 ; x−>c o u n t = RETORNA; }
i f ( x−>c_im<−LIMITE ) {x−>l i m = 3 ; x−>c o u n t = RETORNA; }
i f ( x−>c _ r e a l <−LIMITE ) { x−>l i m = 4 ; x−>c o u n t = RETORNA; }
x−>c o u n t −−;
}
v o i d g e r a r _ r a i o ( t _ m f r a c ∗x )
{
/ / s e v i e r uma a m p l i t u d e m a i o r que a a t u a l , e s e e s s a a m p l i t u d e f o r s i g n i f i c a t i v a e n t a o o r a i o a u m e n t a r a p i d o
i f ( x−>Amp − x−>AmpAnt >TOLERANCIA)
{
/ / r a i o aumenta rapido , c a i devagar , p a r a dar maior e f e i t o p a r a a m p l i t u d e s a l t a s ;
x−>AmpAnt +=INCREMENTO ;
}
x−>AmpAnt −= DECREMENTO;
/ / O a j u s t e do r a i o s e r v e p a r a a j u s t a r o tamanho do f r a c t a l
/ / sem a a p l i c a ç ã o da a m p l i t u d e
x−>r a d i u s = x−>AmpAnt / DIV + AJUSTE_DO_RAIO ;
o u t l e t _ f l o a t ( x−>R a d i u s _ o u t , x−>r a d i u s ) ;
}
v o i d m f r a c _ b a n g ( t _ m f r a c ∗x )
{
/ / gera o vetor deslocamento
gerar_deslocamento (x ) ;
/ / a p l i c a o deslocamento
x−>c_im = ( f l o a t ) ( x−>d e s l y ∗ x−>s p e e d + x−>c_im ) ; / / c_im ;
x−>c _ r e a l = ( f l o a t ) ( x−>d e s l x ∗ x−>s p e e d + x−>c _ r e a l ) ;
/ / g e r a o r a i o que s e r á p a s s a d o ao f r a c t a l
gerar_raio (x );
/ / a l g u m a s v e z e s quando a f r e q u ê n c i a e s t á m u i t o a l t a
/ / e começamos n o v a m e n t e a m ú s i c a a f r e q u ê n c i a c a i r a p i d a m e n t e
/ / a u m e n t a n d o m u i t o o s v a l o r e s do p o n t o complexo
/ / e n t a o s e e l a f o r m a i o r que o LIMITE ( d e f a u l t 1 . 3 ) e n t a o v o l t a a s e r 0
i f ( x−>c _ r e a l >LIMITE | | x−>c _ r e a l < −LIMITE ) x−>c _ r e a l = 0 ;
o u t l e t _ f l o a t ( x−>c _ o u t , x−>c _ r e a l ) ;
i f ( x−>c_im >LIMITE | | x−>c_im < −LIMITE ) x−>c_im= 0 ;
o u t l e t _ f l o a t ( x−>c 2 _ o u t , x−>c_im ) ;
v o i d m f r a c _ n e w f r e q ( t _ m f r a c ∗x , t _ f l o a t a r g f 1 )
{
x−>F r e q A n t =x−>F r e q ;
x−>F r e q = f 1 ;
}
v o i d m f r a c _ n e w A m p l i t u d e ( t _ m f r a c ∗x , t _ f l o a t a r g f 1 )
{
x−>AmpAnt=x−>Amp ;
x−>Amp= f 1 ;
}
v o i d ∗mfrac_new ( t _ s y m b o l ∗s , i n t a r g c , t _ a t o m ∗ a r g v )
{
t _ m f r a c ∗x = ( t _ m f r a c ∗) pd_new ( m f r a c _ c l a s s ) ;
/∗
1 2 3
8 P 4
7 6 5
∗/
x−>d i r e c a o [ 0 ] [ 0 ] = − 1 ; x−>d i r e c a o [ 0 ] [ 1 ] = 1 ;
x−>d i r e c a o [ 1 ] [ 0 ] = 0 ; x−>d i r e c a o [ 1 ] [ 1 ] = 1 ;
x−>d i r e c a o [ 2 ] [ 0 ] = 1 ; x−>d i r e c a o [ 2 ] [ 1 ] = 1 ;
x−>d i r e c a o [ 3 ] [ 0 ] = 1 ; x−>d i r e c a o [ 3 ] [ 1 ] = 0 ;
x−>d i r e c a o [ 4 ] [ 0 ] = 1 ; x−>d i r e c a o [ 4 ] [ 1 ] = − 1 ;
x−>d i r e c a o [ 5 ] [ 0 ] = 0 ; x−>d i r e c a o [ 5 ] [ 1 ] = − 1 ;
x−>d i r e c a o [ 6 ] [ 0 ] = − 1 ; x−>d i r e c a o [ 6 ] [ 1 ] = − 1 ;
x−>d i r e c a o [ 7 ] [ 0 ] = − 1 ; x−>d i r e c a o [ 7 ] [ 1 ] = 0 ;
x−>Amp= 0 ;
x−>AmpAnt = 0 ;
x−>c o u n t = 0 ;
x−>F r e q = 1 0 ;
x−>F r e q A n t = 1 0 0 ;
x−>l i m = 0 ;
x−>d e s l x = 0 ;
x−>d e s l y = 0 ;
x−>s p e e d = 0 . 0 2 1 2 4 ;
x−>c _ r e a l = 0 ;
x−>r a d i u s = 0 . 5 ;
f l o a t i n l e t _ n e w (&x−>x _ o b j , &x−>F r e q ) ;
f l o a t i n l e t _ n e w (&x−>x _ o b j , &x−>Amp ) ;
x−>R a d i u s _ o u t = o u t l e t _ n e w (&x−>x _ o b j , &s _ f l o a t ) ;
x−>c _ o u t = o u t l e t _ n e w (&x−>x _ o b j , &s _ f l o a t ) ;
x−>c 2 _ o u t = o u t l e t _ n e w (&x−>x _ o b j , &s _ f l o a t ) ;
r e t u r n ( v o i d ∗) x ;
}
0 , sizeof ( t_mfrac ) ,
CLASS_DEFAULT ,
A_GIMME, 0 ) ;
class_addbang ( mfrac_class , mfrac_bang ) ;
class_addmethod ( mfrac_class ,
( t _ m e t h o d ) m f r a c _ n e w f r e q , gensym ( " f r e q " ) ,
A_DEFFLOAT , 0 ) ;
class_addmethod ( mfrac_class ,
( t _ m e t h o d ) m f r a c _ n e w A m p l i t u d e , gensym ( "Amp" ) ,
A_DEFFLOAT , 0 ) ;
/ / c l a s s _ s e t h e l p s y m b o l ( m f r a c _ c l a s s , gensym ( " h e l p−m f r a c " ) ) ;
}
A.2.3 Programação em Pd