Skip navigation

a sessão de hoje anda em torno de 4 tópicos: revisão dos sistemas de partículas; leitura, scrubbing e gravação de filmes; introdução ao 3d e introdução ao fft.

1. sistemas de partículas

revimos os sistemas de partículas através de 3 novos sketchs. 

o primeiro sketch desenha apenas se o rato está pressionado. em vez de termos as funções mouseDragged() e mousePressed(), temos agora na função draw() principal um gate if (mousePressed) {…} que subsistui essas duas funções. as partículas decaiem e não são automaticamente re-instanciadas, por isso é que fazemos quando o rato é pressionado:

 

  if(mousePressed){

    sp.setPosForce(mouseX,mouseY,pmouseX,pmouseY);

    sp.reIginite();  

  }

 

o setPosForce vai calcular a força e passar o centro para dentro do SysPart, e quando as partículas morrem, esses valores são transmitidos às novas partículas através da função reIgnite do sistema de partículas. por isso é que conseguimos ter partículas com forças e velocidades diferentes, enquanto mexemos o rato na tela, umas têem uma força e um centro, e outras, outras variáveis.

syspartd01-000163

syspartd01-000228

para o segundo sketch, em vez de termos a posição activa do rato apenas, fomos criar uma class Centro que o rato controla, mas que também evolui sozinha através de movimento browniano. ainda vamos olhar com mais detalhe para o movimento browniano, para já fica o seu funcionamento imediato:

 

    // pos = lastpos + random(-offset,offset);

 

assim, em vez de este sistema de partículas ficar estático no mesmo sítio, ele move-se pelo ecran, se alguma coordenada sai do ecran, volta para o centro.

 

  void bounds(){

    if(x<0||x>width||y<0||y>height) {

     x = width/2;

     y = height/2; 

    }

  }

 

a função bounds é chamada automaticamente da update da classe Centro

 

  void update( float _x, float _y){

    px = x; 

    py = y; //primeiro copiar valores anteriores

    x = _x; 

    y = _y; //depois actualizar

    bounds();

  }

 

e a função que implementa o gerador browniano:

 

  void dwell(){

    // pos = lastpos + random(-offset,offset);

    update( (random(-xamount,xamount)+x), (random(-yamount,yamount)+y)  ); 

  }

 

agora, a nova mecânica, no programa principal(reparem que o rato actualiza as coordenadas do centro, e as variáveis para a função setPosForce são os campos do centro:

 

SysPart sp;

Centro centro;

  sp = new SysPart(100,width/2,height/2); //num parts, centerx, centery 

  centro = new Centro(mouseX,mouseY);

na draw:

  sp.update();

  sp.draw(); 

 

  if(mousePressed){

    centro.update(mouseX,mouseY);

  }

    centro.dwell();

//    centro.draw();

    sp.setPosForce(centro.x,centro.y,centro.px,centro.py);

    sp.reIginite();  

 

 

syspartd2-000082

syspartd2-000453

 

 

1 sistema de partículas com 100 partículas e 1 centro = 15%cpu. depois introduzimos o OPENGL, passamos para o sketch 3, onde em vez de 1 temos 10 sistemas de partículas e 10 centros, e em vez de 150% cpu, ficámos com 11%. alguns comandos gráficos são agora corridos no hardware da placa gráfica e libertam o cpu, o OPENGL torna as coisas mesmo rápidas (ainda mais num puro modo opengl)
syspart3-000405

syspart3-000520

syspart3-000656

 

 

 

2. leitura, scrubbing e gravação de filmes quicktime

 o  próximo tópico foi a introdução de leitura, scrubbing e gravação de filmes quicktime. para tal, temos de importar a biblioteca video do processing, que vai ser a mesma para ler imagens de câmaras:

 

import processing.video.*;

 

para ler filmes do disco,  declaramos objectos do tipo Movie, que se constroem com myMovie = new Movie(this, “station.mov”); e logo a seguir colocamo-los em loop() com a declaração myMovie.loop(); 

 

quando o filme está pronto para ler a próxima frame, o processing envia uma função callback que se chama movieEvent (um pouco como o mouseDragged), e é nessa função que devemos ler a próxima frame através de myMovie.read(); o sketch que vos passei tem um bug, mas é para perceberem que o filme é lido como se fosse nessa lógica. é necessário comentar o myMovie.read() na função draw, e descomentar o callback anterior, para que as coisas operem com normalidade.

 

depois, o myMovie funciona como uma PImage normal. pode ser representado no ecran com a função image() que recebe o nome da variável e posx e posy, e opcionalmente, tamanho x e tamanho y. se quiserem por o filme a fullscreen tem de ser image(myMovie,0,0,width,height); como está, a imagem está interactiva à posição do rato, apenas deslocando-se face às posições mouseX e Y.

 

no sketch a seguir fomos aprender a fazer scrubbing aos videos, com o rato. só precisamos de uma float global que indique a duração do filme, e assignamos o valor a esta float quando construímos o filme:

 

Movie myMovie;

float movieDur;

void setup(){

  …

  myMovie = new Movie(this, “station.mov”);

  myMovie.loop();

  movieDur = myMovie.duration(); //get the duration

no draw, normalizamos a posição do rato, assegurando que nunca sai dos limites:

   float pos = constrain( map(mouseX,0,width,0.,1.), 0.,1.);

logo a seguir, mulltimos este valor pela duração em segundos do filme, e mandamos o filme ir para esse sítio:

  pos = pos * movieDur;  

  myMovie.jump(pos);

 

a função jump dos objectos Movie é a que permite efectuar o scrubbing. salta para a posição temporal com n segundos. para que os filmes saltem bem para as posições, devem estar comprimidos com codecs que não introduzem compressões temporais, como os divx, ou h.264, devemos comprimir os nossos filmes fonte com o codec Photo-JPEG, que não introduz keyframes, e mantem uma qualidade fotográfica das imagens. neste codec podemos saltar imediatamente para as posições dos filmes, enquanto que outros codecs podem engonhar, e atrasar o programa.

video-000075

para a gravação de filmes quicktime, declaramos um objecto do tipo MovieMaker, que construímos apenas quando queremos começar a gravar (eu fiz isso com a tecla ‘g’ e a variável booleana gravar inicialmente a falsa):

 

  if (key == ‘g’) {

    if(!gravar){

      mm = new MovieMaker(this, width, height, “video.mov”, 30, 

      MovieMaker.JPEG, MovieMaker.HIGH);

      gravar = true;

    } 

    else 

      mm.finish();

 

este método permite gravar qualquer tipo de sketch processing, nas dimensões actuais da nossa tela digital. quando se constroi o objecto mm, este fica pronto a gravar frames, mas isso só acontece quando chamamos a função mm.addFrame(); no final da função draw(), para gravar os conteúdos que desenhamos. quando queremos terminar a gravação, chamamos a função mm.finish()

video_1

3. introdução ao 3d.

 

o processing vem com dois renderers gráficos que permitem desenhar coisas em 3d. o P3D e o OPENGL. o P3D funciona em software, enquanto que o OPENGL envia parte das coisas para a placa gráfica.

 

estes modos de renderização são activados na função size, passando como argumento o nome do renderizador que queremos usar. para o opengl temos de importa a library.

import processing.opengl.*;

agora, além das coordenadas x e y, vamos ter um novo eixo cartesiano, o z, que define a distância perpendicular à tela, na direcção negativa para dentro da tela, e positiva para fora da tela. usar este novo eixo é muito simples, e uma extensão mínima comparado com o eixo x y que temos vindo a utilizar. é preciso é ter sempre presente o sistema de coordenadas do processing, onde o ponto(0,0,0) vai ser no canto superior esquerdo da tela, o x cresce para a direita, o y cresce para baixo, e o z cresce na nossa direcção. x negativos vão para a esquerda, y negativos vão para cima, e z negativos para dentro da tela.

 

fomos fazer um remake dum clássico, um campo de estrelas com velocidade variável. para manter uma variável do tipo estrela, precisamos apenas de 4 floats: x, y, z  e s. xyz vão ser a posição no sistema 3d, s vai ser uma velocidade local de cada estrela. cada x, y e s são instanciados e mantêem-se estáticos. o z é que vai variando, vindo lá do fundo e aproximando-se com a soma da velocidade local de cada estrela, com a velocidade global.

 

as estrelas são linhas, e a dimensão da linha é tanto maior quanto é a sua velocidade. o comando que desenha linhas, como já vimos, é o line, e agora, em 3d, em vez de receber 4 parâmetros, dois pontos xy, vai receber 6 parâmetros, 2 pontos xyz. 

 

a função principal da estrela é a render que desenha e actualiza as coordenadas z de cada estrela.

 

  void render(){

    if(z>500)

      zz();

    else

      line(x,y,z,x,y, z – speed*s);

    z+=(s+speed);

  }

 

se o z for maior que 500, chamamos a função zz(), que repõe o z para o fundo da tela, até no máximo à posição -10000.

starfield-000087

starfield-001150

depois, evoluímos este sketch para representar uns planos na imagem, e tornar o sketch reactivo ao som, como temos vindo a fazer nas sessões anteriores. aqui o som varia a velocidade de todas as estrelas de maneira igual.

starfieldsom-000106

starfieldsom-001079

 

4. introdução ao fft

fast fourrier transform: é uma transformação que fazemos ao som onde conseguimos ter acesso à magnitude do contéudo espectral do som, as frequências distribuem-se por bandas de análise, e cada banda vai ter um valor fraccionário que corresponde à magnitude do som em tempo-real nessa região do espectro sonoro. em vez de um valor único, vamos ter tantos valores como bandas de frequência da nossa análise de fft, tipicamente 256, 512, ou 1024 bandas.

analisamos o sketch exemplo da minim que faz fft, e nele vimos que cada linha do espectro linear representado é uma linha vertical e sobe desde o fundo da tela até determinada altura, sendo que essa altura é uma escala da banda actual. aqui está a parte do program que calcula o fft e acede ao valor de cada banda e desenha as linhas:

  fft.forward(jingle.mix);

  for(int i = 0; i < fft.specSize(); i++){

     line(i, height, i, height – fft.getBand(i)*4);

  }

 

fft-000461

 

fft-000040

vamos usar agora este mecanismo na construção de um sketch 3d das estrelas, onde cada estrela reage a frequências diferentes do som em tempo real. para tal, umas modificações mínimas na class start para que cada estrela fique linkada a uma banda fft, e cada função render lê o valor dessa banda e faz variar a velocidade da estrela de acordo com essa velocidade. para que tal aconteça:

 

no construtor:

    fftband = (int) random(fft.specSize());

no render:

    local_speed = fft.getBand(fftband) * 100.;

    z+=(s+local_speed);

 

 

algumas imagens, notem como apenas algumas das estrelas reagem ao som nessas frequências…

starfieldfft-000208

starfieldfft-001031

finalmente, modificámos a class dos planos para permitir inserir uma imagem, e em vez de termos cores nos planos, vamos ter um png carregado para uma array de imagens e escolhido aleatoriamente para cada plano.

starfieldimg-000187

starfieldimg-001132

o exercício de hoje era modificar os sketches da aula e gravar um video dessa interacção. aqui ficam alguns stills dos vossos trabalhos (no post de exemplos sessão 6). até para a semana.

Anúncios

One Trackback/Pingback

  1. By sessão 17 « O Som do Pensamento on 27 Maio 2009 at 11:54 am

    […] introdução ao 3d com noções de coordenadas espaciais, onde está a câmara, onde estão os objectos no espaço, como criar algorimos que gerem formas que se movimentem em três dimensões. (sessão 6) […]

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s

%d bloggers like this: