Ferramentas de Usuário

Ferramentas de Site


dev_geral:sdl:motion_blur

Motion blur

Introdução

O motion blur consiste no desfoque criado pela visão humana quando se dá um movimento rápido. Este efeito acontece quando a taxa de actualização da visão humana não é suficiente para acompanhar o movimento, levando o cérebro a criar uma imagem intermédia desfocada (resultante da sobreposição e composição de duas keyframes) de forma a dar a sensação de que as duas imagens representem movimento fluído (e perceptível) e não apenas uma mudança abrupta de posição de um objecto.

Uma das razões para implementar motion blur é o facto de estarmos a simular aquilo que o próprio cérebro utiliza para representar movimentos rápidos: podemos assim recriar com mais naturalidade o movimento de objectos rápidos, mesmo que a framerates inferiores ao normal.

Existem várias formas de recriar o motion blur, umas mais simples, outras mais complexas.

Neste tutorial vai ser abordada a forma mais simples de motion_blur, desenhar o frame anterior sobre o frame actual.

Tutorial

Em primeiro lugar, como é óbvio, devemos tratar dos #includes, da iniciação da SDL e da declaração das variáveis:

#include <SDL/SDL.h>
#include <cstdlib>
#include <iostream>
 
int main(int argc,char* args[]) {
   bool quit=false; // Quando este for igual a true, a execução termina
 
   if (SDL_Init(SDL_INIT_EVERYTHING)==-1) {return 1;}
 
   SDL_Surface *ecra=NULL;
   ecra = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);
   SDL_WM_SetCaption("Motion Blur","Motion Blur");

Depois é necessário carregar algumas imagens, de forma a poder ver o efeito. Neste caso irei carregar uma imagem de fundo (640x480) e uma sprite(20x20) que se irá acompanhar o rato, de forma a que o efeito seja bem visível:

   SDL_Surface *Fundo=NULL;
   Fundo=SDL_DisplayFormat(SDL_LoadBMP("fundo.bmp"));
 
   SDL_Rect fundor={0,0,640,480}; // SDL_Rect da imagem de fundo
 
   SDL_Surface *Sprite=NULL;
   Sprite=SDL_DisplayFormat(SDL_LoadBMP("sprite.bmp"));
   SDL_Rect spriter={0,0,20,20}; // SDL_Rect da sprite;

Agora vem a parte importante: o ciclo principal.

  • Primeiro iniciamos um SDL_Event, de forma a receber a posição do rato e a poder terminar a execução do programa a qualquer altura;
  • Depois vamos precisar de uma surface para guardar a informação do frame anterior, para formar o motion blur;
  • Ao iniciar cada frame, a surface blur vai receber todas as informações do desenho.
  • Depois definimos a transparência desta surface. 128 normalmente é um número muito elevado, mas vai ser usado neste exemplo só para o efeito ser bem visível;
  • De seguida desenhamos o fundo e a sprite na posição do rato, aplicando depois o blur;
  • Por fim, libertamos a imagem do blur, de forma a não haver uma leak.
   SDL_Event evento;
   SDL_Surface *blur=NULL;
   while (quit==false) {
      blur=SDL_DisplayFormat(SDL_GetVideoSurface()); // Captura do último frame desenhado
      SDL_SetAlpha(blur,SDL_SRCALPHA|SDL_RLEACCEL,128); // Transparência do blur
 
      SDL_BlitSurface(Fundo,NULL,ecra,&fundor); // Desenho do fundo
 
      spriter.x=evento.button.x; // Colocação da sprite
      spriter.y=evento.button.y; // na posição do rato
      SDL_BlitSurface(Sprite,NULL,ecra,&spriter);
 
      while (SDL_PollEvent(&evento)) {
         if (evento.type==SDL_QUIT) {quit=true;} // Evento de saída
      }
 
      SDL_BlitSurface(blur,NULL,ecra,&fundor); // Aplicação do blur
 
      SDL_Delay(1000/60); // Cerca de 60 FPS
      SDL_Flip(ecra);
      SDL_FreeSurface(blur); // Libertação do blur
    }

Por fim, liberta-se a memória das imagens, termina-se o SDL e o programa termina a sua execução:

    SDL_FreeSurface(Fundo);
    SDL_FreeSurface(Sprite);
    SDL_FreeSurface(blur);
    SDL_Quit();
    return 0;
}

Código completo

#include <SDL/SDL.h>
#include <cstdlib>
#include <iostream>
 
int main(int argc,char* args[]) {
   bool quit=false; // Quando este for igual a true, a execução termina
 
   if (SDL_Init(SDL_INIT_EVERYTHING)==-1) {return 1;}
 
   SDL_Surface *ecra=NULL;
   ecra = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);
   SDL_WM_SetCaption("Motion Blur","Motion Blur");
 
   SDL_Surface *Fundo=NULL;
   Fundo=SDL_DisplayFormat(SDL_LoadBMP("fundo.bmp"));
 
   SDL_Rect fundor={0,0,640,480}; // SDL_Rect da imagem de fundo
 
   SDL_Surface *Sprite=NULL;
   Sprite=SDL_DisplayFormat(SDL_LoadBMP("sprite.bmp"));
   SDL_Rect spriter={0,0,20,20}; // SDL_Rect da sprite;
 
SDL_Event evento;
   SDL_Surface *blur=NULL;
   while (quit==false) {
      blur=SDL_DisplayFormat(SDL_GetVideoSurface()); // Captura do último frame desenhado
      SDL_SetAlpha(blur,SDL_SRCALPHA|SDL_RLEACCEL,128); // Transparência do blur
 
      SDL_BlitSurface(Fundo,NULL,ecra,&fundor); // Desenho do fundo
 
      spriter.x=evento.button.x; // Colocação da sprite
      spriter.y=evento.button.y; // na posição do rato
      SDL_BlitSurface(Sprite,NULL,ecra,&spriter);
 
      while (SDL_PollEvent(&evento)) {
         if (evento.type==SDL_QUIT) {quit=true;} // Evento de saída
      }
 
      SDL_BlitSurface(blur,NULL,ecra,&fundor); // Aplicação do blur
 
      SDL_Delay(1000/60); // Cerca de 60 FPS
      SDL_Flip(ecra);
      SDL_FreeSurface(blur); // Libertação do blur
    }
 
    SDL_FreeSurface(Fundo);
    SDL_FreeSurface(Sprite);
    SDL_FreeSurface(blur);
    SDL_Quit();
    return 0;
}

Conclusão

Como podem ver, este é um efeito bastante simples de aplicar, e que pode dar um efeito bastante apelativo em alguns jogos. Existem algumas técnicas mais avançadas, que têm em conta a distância dos objectos à visão do utilizador, mas para duas dimensões esta técnica deve ser suficiente.

dev_geral/sdl/motion_blur.txt · Última modificação em: 2018/05/14 21:37 (edição externa)