quinta-feira, 11 de julho de 2013



Computação Gráfica
(Pipeline Gráfico)

Transformação do Espaço Canónico para o espaço da tela

           No processo de modelagem de um ambiente grafico, várias primitivas precisam ser realizadas para que a rasterização da do objeto modelado possa gerar a imagem de forma correta na tela, ou seja, ao modelar um objeto pouco nos preocupamos com o o local onde esse objeto será rasterizado, na hora de modelar nós simplesmente criamos o modelo do objeto da forma preferida. Imagine que existe um modelo de objeto criado e suas dimensões são no formato 1024x768, mais o seu display de saída possui dimensões de 600x400, nessa caso seu modelo estaria danificado  e as caracteristicas inicialmente propostas estariam funcionando de maneira não desejada, a falta de um padrão dificulta as coisas para que uma única modelagem possa funcionar para os diversos tipos de dispositivos existentes, então para solucionar parte desses problemas é que o espaço canónico existe.
         O espaço canónico nada mais é que um espaço com dimensões finitas  variando de -1 até 1 em cada 1 dos eixos coordenado, onde a passagem do objeto modelado é traduzida de forma muito mais simplificada para o display de saída possibilitando também que um mesmo modelo possa funcionar nos diversos tipos de dispositivos por conta do seu padrão e da facilidade de manipular com o mesmo.
          Hoje em dia sempre modelamos inicialmente um objeto em um espaço euclidiano tridimencional com seu limite indeterminado, porém pelo limite de seus eixos serem indeterminados e sua dimensão ser tridimêncional enquanto o display de exibição é bidimêncional os objetos são convertídos para o espaço canónico depois de sua modelagem para posteriormente iniciar o processo de rasterização da imagem (o processo de modelagem no espaço euclidiano para o canónico e preparação da imagem a ser rasterizada será visto em futuras postagens), todos os processos gerados adiante é levando em consideração que estamos tratando do espaço canónico.
 
          O espaço canónico é o estágio anterior à passagem das informações para o espaço da tela. 
          Para realizar essa conversão uma série de transformações geométricas devem ser aplicadas à base canonica, fazendo com que essas transformações geométricas realizem na verdade transformações de base.
           Como podemos perceber pela imagem ao lado o espaço canónico possui uma variação de -1 a 1 e sua origem se localiza no centro do espaço enquanto o espaço da tela varia de sua origem até sua extremidade, onde a origem está localizada na outra.
          Quando nós tentamos formar um objeto gráfico nós temos o interesse de que o objeto que formamos seja mostrado da mesma forma com a qual foi gerado, então  precisamos aplicar transformações que satisfaçam essas necessidades.

  1. Transformação de Escala para Inverter o eixo Y.
  2. Transformação de escala para tornar o espaço equivalente o da Tela
  3. Translação da origem para que ela se localize no centro da Tela
           Como o espaço final será o espaço da tela teremos de aplicar as transformações na tela para que ela fique semelhante ao espaço canónico e o seu objeto poderá ser representado no espaço da tela como se estive-se sendo representado no espaço canónico.
 
Transformação de Escala para Inverter o eixo Y.
 
         Uma transformação de escala consiste em aumentar ou diminuir determinado objeto ou espaço, na figura percebemos que o eixo "y" dos espaços estão com suas direção trocadas, então para representar algo do espaço canónico no espaço da tela teremos de inverter o eixo-y da tela fazendo uma transformação escala que troque o eixo-y e mantenha os outros eixos.

Transformação de escala para tornar o espaço equivalente o da Tela
 
         Uma tela matricial possui um espaço de coordenadas que inicia no zero e se encerra no (Rt-1) onde Rt é a resolução da tela, como localizaremos a origem no centro da tela, então a tela possuirá coordenadas positivas em alguma região e negativa em outra, sabendo disso percebemos que a quantidade de valores das coordenadas estaram divididos em 2, os positivos e os negativos, nesse caso faremos uma escala que vai aumentar metade da posição final da tela (Rt-1)/2, se as dimensões dos eixos forem diferentes terá de ser tomado em relação a cada eixo na troca de escala.

Translação da origem para que ela se localize no centro da Tela
 
        Depois de aplicado as primeiras transformações o sistema ja está convertido para o sistema de coordenadas canónico, porém o seu centro não está localizado no centro da tela, então é necessário fazer uma translação do centro da tela que se localiza na estremidade para que ele se localize no centro, como ele está na extremidade temos de deslocar a mesma quantidade usada na escala anterior pois a mudança de escala informa quantas coordenadas existem do centro a uma das extremidades.
 
Resumo:
 
          Um resumo de cada transformação está indicado abaixo.

xc=coodenada x no espaço canônico
yc=coodenada y no espaço canônico
xt=coodenada x no espaço da tela
yt=coodenada y no espaço da tela
T1=Transformação de escala 1
T2=Transformação de escala 2
T3=Translação da origem do sistema de coordenadas
W=largura  da tela
H=Altura da tela

Podemos concluir por tudo que foi falado que a transformação de espaço será a sequencia de transformações de forma ordenada.


Para o xc a T1 não vai fazer nada com o eixo-x pois x ja está alinhado, ja com o yc ele será invertido.

Podemos concluir que T2 para x vai ser (W-1)/2 e para y vai ser (H-1)/2 então.
 
 
Por fim a translação será  a soma de (W-1)/2 para x e (H-1)/2 para y

Podemos tambem chamar Pt de vetor com as coordenadas da tela e Pc como vetor com as coodendas do espaço canónico e agora as transformações serão matrizes de transformação
 
 
Se eu pré multiplicar as matrizes na ordem em que estão agrupadas o resultado será uma matriz que gera toda a conversão do espaço canónico para o espaço da tela
 
Mct=Matriz de conversão do espaço canónico para o espaço da tela.
 
Vamos ver como seria o corpo da matriz.
 
            
 
Atividade

          Para a visualização do funcionamento de tudo explicado, vou utilizar um framework criado pelo professor Christian Azambuja Pagot que leciona o conteudo de Introdução a Computação Grafica na Universidade federal da paraíba.
          O framework funciona de tal maneira que permite simular ações que hoje em dia os sistemas operacionais não permitem a modificação direta, como o acesso direto ao FrameBuffer responssável por armazenar as informações de posição e de cor de cada pixel que aparece na tela, essa virtualização foi gerada usando as bibliotecas gráficas OpenGL e GLUT.
          Como as conversões de espaço funcionam atravez de matriz e vetor foi necessário a criação de uma biblioteca especial de matrizes para realizar operações basicas como multiplicação de matriz por matriz multiplicação de vetor com matriz, etc.
 
Funções da Biblioteca "matriz.h" necessárias para realizar as operações descritas anteriormente:
 
ordem = 4;//é uma constante para indicar a ordem da matriz.
 
void multiplicaMatriz(float A1[ordem][ordem], float A2[ordem][ordem],float matrizMultiplicada[ordem][ordem]);
 
void multiplicaMatrizVetor(float matriz[ordem][ordem], float vetor[ordem], float vetorMultiplicado[ordem]);
 
void identidadeMatriz(float matrizIdentidade[ordem][ordem]);
 
void atribuiEscalaMatriz(float matrizEscala[ordem][ordem], float x, float y, float z);

void atribuiTranslacao(float matrizTranslacao[ordem][ordem], float x, float y, float z);

Na biblioteca "mygl.h" que é a biblioteca que contem as funções para pintar pixels, linhas e triângulos foram inseridas algumas variáveis que vão receber as matrizes T1, T2 , T3, etc.
As funções e variáveis utilizadas na atividade pela biblioteca "mygl.h" estão descritas adiante:

#include "matriz.h"
float MUDANCA_BASE[ordem][ordem];
float MUDANCA_ESCALA[ordem][ordem];
float MATRIZ_TRANSLACAO[ordem][ordem];
float Mct[ordem][ordem];
float CANONICO_TELA_X = (IMAGE_WIDTH-1)/2;  //IMAGE_WIDTH = W
float CANONICO_TELA_Y = (IMAGE_HEIGHT-1)/2; //IMAGE_HEIGHT = H
 
void DrawLine(int x0,int y0,int x1,int y1,float r0, float g0, float b0, float r1, float g1, float b1) ; //função para desenhar linha na tela pelo framework
 
void DrawLineTriangle(int x0, int y0, int x1, int y1, int x2,int y2, float r0, float g0, float b0, float r1, float g1,float b1, float r2, float g2, float b2)  //função para desenhar triangulo //utiizando o framework
 
          A parte de implementação para fazer a conversão do espaço canónico se baseia na multiplicação de matrizes para obtenção de uma matriz principal, que multiplicado por qualquer vetor no espaço canónico gerando um vetor no espaço da tela com as características do espaço canónico.
           No arquivo "main.cpp", estão a inicializações do framework e o local para inserção das funções que trabalhão com a memória virtual, acessando o FrameBuffer virtual.
 main.cpp:
 
int main(int argc, char **argv)
{

 identidadeMatriz(Mct);
//Nesse momemto A matriz resultante é iniciada com identidade
atribuiEscalaMatriz(MUDANCA_BASE, 1, -1, 1);
//agora atribuo a escala especificada pelos parametros a x, y e z respectivamente
atribuiEscalaMatriz(MUDANCA_ESCALA,CANONICO_TELA_X,CANONICO_TELA_Y,1);
//agora atribuo a escala com as variáveis alteradas pelo "W" e "H",  em x,y e z //respectivamente, como o z não entra nesse caso então ele não se altera
atribuiTranslacao(MATRIZ_TRANSLACAO, CANONICO_TELA_X,CANONICO_TELA_Y,1);
//agora atribuo a translação na matriz de translação.
 
//como a ordem importa muito no momento da multiplicação a ultima multiplicação é a //primeira que vai ser feita no vetor, então multiplico primeiro na ordem abaixo.
   
    multiplicaMatriz(Mct, MATRIZ_TRANSLACAO, Mct);
    multiplicaMatriz(Mct, MUDANCA_ESCALA, Mct);
    multiplicaMatriz(Mct, MUDANCA_BASE, Mct);

//nesse momento a Matriz Mct possui todos as transformações vista anteriormente
    
//agora vou receber as variáveis que indiquem as posições x e y dos dois vetores que eu quero mudar de espaço
    printf("x1: ");
    scanf("%f", &P1[0]);
    printf("y1: ");
    scanf("%f", &P1[1]);
    printf("x2: ");
    scanf("%f", &P2[0]);
    printf("y2: ");
    scanf("%f", &P2[1]);
//como z não importa nesse caso eu o coloco como 0 e o w permanece em 1 nos dois //vetores
    P1[2]=0;
    P2[2]=0;
    P1[3]=1;
    P2[3]=1;
    multiplicaMatrizVetor(Mct, P1, P1);
    multiplicaMatrizVetor(Mct, P2, P2); 
 //Nesse momento estou com os dois vetores multiplicados para assumirem valores no //espaço da tela como se estivessem no espaçoo canonico

Em cima eu possuo uma função que vai realizar tal test para imprimir as linhas e triangulos baseados nos vetores.
 
void MyGlDraw(void)
{
    //*************************************************************************
    // Chame aqui as funções do mygl.h
    //*************************************************************************
    DrawLine( P1[0], P1[1], P2[0], P2[1], 255, 0, 0, 0, 255, 0);
    DrawLineTriangle(
P1[0], P1[1], P2[0], P2[1], 0.7,-0.22, 255, 0, 0, 0, 255, 0,0, 0, 255);
   
   
}
Executando o programa e escolhemos alguns valores temos os seguintes resultados:



 Com esse caso é perceptível que o centro está no meio da tela