Rasterização de Primitivas - Pontos, Retas e Triângulos
Este post é destinado ao primeiro trabalho da disciplina de Introdução à Computação Gráfica, ministrada pelo professor Christian Azambuja Pagot, o desenvolvedor do framework, que simula o acesso a memória (através do ponteiro FBptr), já que os sistemas operacionais não liberam este acesso.
Bem, neste trabalho foi solicitado a criação de três funções, listada abaixo:
PutPixel: Função que rasteriza um pixel na tela.
DrawLine: Função que rasteriza um conjunto de pixel na tela, formando linhas.
DrawTriangle: Função que rasteriza três linhas, formando triângulos.
Como se deu a implementação?
Primeiro de tudo, precisamos saber alguns conceito básico para melhor entendemos a implementação.
Rasterização, é a tarefa de converter uma imagem vetorial em uma imagem raster (pixels ou pontos) para a saída em vídeo ou impressora. O termo Rasterização também é utilizado para converter uma imagem formada por vetores para um arquivo de formato bitmap (SVG para PNG).
2- O que é Pixel?
Pixel ou Píxel (sendo o plural pixels ou píxeis) (aglutinação de Picture e Element, ou seja, elemento de imagem, sendo Pix a abreviatura em inglês para Pictures) é o menor elemento num dispositivo de exibição (como por exemplo um monitor), ao qual é possível atribuir-se uma cor. De uma forma mais simples, um pixel é o menor ponto que forma uma imagem digital, sendo que o conjunto de milhares de pixels formam a imagem inteira.
3- O que são primitivas geométrica?
São conceitos primitivos (e, portanto, aceitos sem definição) na Geometria espacial os conceitos de ponto, reta e plano. Neste trabalho precisaremos saber a característica de uma a reta, que é só possui uma dimensão, comprimento. E a característica do ponto, que é não possuir dimensão.
Depois de explicamos esse conceito vamos ao que realmente interesa, a implementação, mãos a massa.
Pintando o Pixel na tela
Para isso iremos criar uma função chamada de putpixel que terá como argumento x e y, ou seja, vamos converter a localização de um determinado ponto (descrito por coordenadas cartesianas discretas) em um espaço de memória, e escrever suas informações de cor neste espaço.
Considerando que a tela possui w pixels de largura e h pixels de altura, e que a origem do sistema de coordenadas esteja localizada no canto superior esquerdo da tela, como pode ser visto abaixo.
1- O que é Rasterização?
Representação da tela
Endereçamento do RGBA
Os pixels são endereçados como pontos de coordenadas (x, y), onde x varia entre 0 e w-1, e y varia entre 0 e h-1. Já no color buffer, o armazenamento é em série, a primeira posição corresponde ao primeiro componente do primeiro pixel, como poderá ser visto na imagem abaixo.
O primeiro byte do pixel (0,2) é 4*w*2+0. Com esse entendimento e generalizando, chegamos a fórmula para endereçamento de memória do 1º byte para pixel qualquer (x,y).
Como vamos pintar um pixels na tela?
Rasterização de Pontos O acesso aos pixels na região do framebuffer é realizado por meio do ponteiro FBptr, que está apontado inicialmente para a sua primeira posição de memória como vimos acima, ou seja, para o pixel de coordenadas (0,0) - canto superior esquerdo da tela. O framebuffer consiste em uma matriz unidimensional, com tamanho relativo a dimensão da tela. Com isso, para acessar o pixel que deseja-se pintar, o ponteiro FBptr move-se na direção horizontal, passando por um determinado número de bytes, até chegar ao pixel desejado. Todo pixel da tela é formado por quatro componentes (R,G,B,A), as quais em conjunto, ocupam um espaço em memória de 4 bytes (1 byte para cada componente). Assim, para acessarmos um pixel de coordenadas (x,y), em uma tela de dimensões w*h (largura*altura), usa-se a fórmula:
4*w*y + 4*x = 4*(w*y + x)
Antes de apresentar como se deu a implementação, foi apropriado fazer a modelagem dos pixels e das cores, isto é, agrupá-los em estruturas de forma que sejam identificáveis ao longo do programa como objetos, Assim, foram criadas as seguintes estruturas(Classes):
A seguir veremos a função PUTPIXEL que tem como argumentos coordenadas(X,Y) e Cor(RGBA) e a mesma é básica para qualquer algoritmo de rasterização:
Representação do pixel
Draw Line
Desenhando linhas fazendo uso da função PutPixel().
Conectando dois pixels: o algoritmo de Bresenham, esse é algoritmo mais clássico para desenhar linhas. Apesar de não ser fácil implementação, mas tem uma grande eficiência, pois não emprega nenhuma operação de divisão ou arredondamento, funções associadas diretamente à processos de discretização.
A função tem como objetivo desenhar um segmento de reta na tela, contudo seu maior desafio é identificar quais pixels devem ser pintados para que a reta obtenha a melhor representação.
Seu funcionamento ocorre da seguinte maneira: a cada iteração, a função recebe a duas coordenas e escolhe entre dois pontos, que são o final e inicial e com base no sinal da variável de decisão calculada na iteração anterior, na sequência a variável de decisão é incrementada de acordo com o valor do pixel escolhido. Inicialmente, o valor da variável de decisão é D = 2dy – dx. Onde dx = x final – x inicial e dy = y final – y inicial. Se D<=0, o pixel escolhido está acima da reta, caso contrário está abaixo da reta. Se o pixel escolhido estiver acima da reta, o valor da variável de decisão será incrementado com o erro da aproximação E = 2dy; caso contrário o erro será SE= 2*dy – dx. O procedimento se repete até desenhar toda a reta:
Comportamento Δx e o Δy
Agora, finalmente, depois de analisamos todos os casos iremos ao algoritmo, vale ressaltar que a implementação desse algoritmo em termos de código é "simples"mas compreender completamente como fazê-la, principalmente a parte de generalizá-lo.
A primeira coisa que eu implementei foram linhas que tinha alguma coordenadas contantes ou seja desenhar foram linhas verticais e horizontais. Por isso foi criado uma função
No caso das linhas horizontais, em que o delta Δy (dy) é zero. Portanto não há a necessidade de se incrementar y. Analogamente temos as linhas verticais o Δx (dx) é igual a zero , então logo não precisamos incrementar x. E assim foi criada a função DrawLineConst(Coordenadas *Pinicio, Coordenadas *Pfinal, Cor *cor)
Agora iremos mostrar de fato a função DrawLine(Coordenadas *Pinicio, Coordenadas *Pfinal, Cor *cor)
Desenhando triângulos fazendo uso da função DrawLine().
Agora, precisamos fazer uma função que recebe três retas(Coordenadas) a serem vértices do triângulo. Ela recebe como parâmetro a posição dos três vértices e a cor do triângulo e funciona da seguinte maneira: O primeiro vértice é ligado ao segundo através de uma chamada da função DrawLine(), o segundo vértice ligado ao terceiro e o terceiro vértice é ligado ao primeiro vértice.
E assim foi criada a função DrawTriangle(Coordenadas *coordenadasA, Coordenadas *coordenadasB, Coordenadas *coordenadasC, Cor *cor ).
Interpolação de Cores RGBA
Agora precisamos implementar a interpolação de cores, variar as cores gradativamente até chegar na cor da outra ponta, que preferi deixar pro final pra facilitar o raciocínio. A interpolação segue uma variação de cada componente RGBA até chegar a cor RGBA do final a partir de uma cor RGBA inicial. Para isso foi criado 2 funções, a primeira foi função distancia, que ira calcular a distancia total da reta. distancia(Coordenadas *Pinicio, Coordenadas *Pfinal);
Função interpolação de cores(IC) tem como parâmetro a distancia entre os pontos e suas respectivas cores. O argumento float P é calculo da distância entre os pontos, para poder ser utilizado como divisor para assim descobrir o valor de incremento de cada componente RGBA, obtido através da divisão da subtração do componente de cor final pelo inicial pela distância. e colocaremos o trecho de código sobe todas as chamada de função Putpixel.
Dificuldades encontradas no Trabalho
A maior dificuldade enfrentada nesse trabalho foi em relação a interpolar as cores.
Possíveis melhoras
"Limpar o código", tendo em vista que código é didático, foi criado variáveis sem utilidade efetiva.
Referências
PAGOT, Christian Azambuja. Material de aula . 30 mar. 2015, 11 may. 2015. Notas de Aula.
FLANAGAN, Colin. The Bresenham Line-Drawing Algorithm. 2015. Disponível em: http://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html. Acesso em: 30/04/2015
ELETRONICA, saber. Algoritmo de Bresenham: O Uso de Microcontroladores para Traçar Retas em LCDs. 2008. Disponível em: http://www.sabereletronica.com.br/artigos/2605-algoritmo-de-bresenham-o-uso-de-microcontroladores-para-traar-retas-em-lcd. Acesso em: 06/04/2015
BAGATELO, Harlen Costa. Algoritmos de Rasterização. 2008. Disponível em: http://www.dca.fee.unicamp.br/courses/IA725/1s2008/transparencias/raster.pdf. Acesso em: 06/04/2015
Tags: Rasterização de Primitivas em C++, Algorítmo de Bresenham, Computação Gráfica, Graphic Computer ,CG, Programação, programming, colorbuffer, framebuffer, Opengl, Pipeline Gráfico, C++, T1, Rasterização de Primitivas em C++ (Algorítmo de Bresenham), Primeiro trabalho de computação gráfica - UFPB, Rasterização de Primitivas.
Comentários
Postar um comentário
comenta aqui