Vamos falar das técnicas utilizadas para iluminar a cena e os objetos. Antes, é importante ressaltar que a OpenGL trabalha apenas com luzes que impactam diretamente os objetos, ou seja, nenhum cálculo é feito sobre a cena (efeitos de radiosidade) e nem a refexão da luz por objetos é percebida (efeitos de ray tracing).
Implementei as principais e mais utilizadas técnicas de iluminação quando estamos trabalhando com OpenGL. São elas:
- Luz Ambiente Global: É a luz que irradia todo o ambiente de maneira igual. Pode ser definida como escuridão mínima que um objeto pode ter em cena.
- Luz Ambiente: Representa a luz que ilumina de forma igual todas os vértices do polígono em questão. Pode ser representada também como a escuridão mínima que o objeto no campo de atuação daquela luz pode ter em cena.
- Luz Difusa: É a luz angular do objeto. Esta depende da posição em que o objeto está e torna possível efeitos de atenuação. Com essa luz percebemos claramente as faces mais distantes da luz (menos iluminadas) e as mais próximas (mais iluminadas). Para definir essa luz com perfeição, é necessário calcular as normais de cada face para objetos poligonais e a media das normais para figuras arredondadas. Felizmente para o usuário, a paEngine trata de todos os cálculos das normais de luz por debaixo dos panos.
- Luz Especular: É a luz que define o toque especial do objeto, ou seja, o quanto as regiões atingidas por essa luz ficarão mais brilhantes dependendo do material do objeto. O efeito com a combinação das três luzes fica muito bonito se aplicado corretamente.
Exemplos de um poliedro com as três iluminações pode ser encontrado aqui:
É possível se inserir até 8 luzes na cena com a paEngine, seguindo a limitação da OpenGL...
Após configuradas as luzes da cena, é necessário posicioná-las no local desejado.
Por fim, ainda é necessário atribuir a cada objeto da cena um material. Este material pode ser definido manualmente ou através da sua cor. Para a primeira opção, implementei na engine a seguinte funcionalidade:
setMaterial(ambient[3], diffuse[3], specular[3], shininess, emissive[3]);
Aqui é que a coisa começa a fazer todo o sentido, pois é nesses componentes que define-se como o objeto refletirá cada tipo de luz que inside em sua superfície. Por exemplo, podemos definir a reflectância do material em specular, e em seguida atribuir a ele uma superfície com brilho localizado, como um metal, passando valores de 100 a 128 em shininess.
Ainda existem funções disponíveis para setar cada um desses componentes individualmente.
No caso do último componente (emissive), este definirá que o objeto, além de refletir as luzes recebidas, também brilha. Isso, combinado com uma luz posicionada no centro do objeto, pode produzir efeitos muito bonitos para a aplicação.
Para definir o material do objeto através de sua cor, deve-se habilitar o color tracking da engine através do método activeColorMaterial. Esta representa uma maneira mais fácil de definir a iluminação para polígonos desenhados pelo programador e para iluminar polígonos sem textura.
A maior dificuldade da implementação do cálculo da luz foi destrinchar o que significava cada uma das luzes, como se comportavam para determinados tipos de materiais e como calcular as normais de luz para cada face. Felizmente, com um pouco de aprofundamento, observação, leitura e abstração foi possível chegar-se a uma implementação mais clara para a engine.
Se eu fosse continuar as implentações, criaria métodos de reprodução de luzes spotlight, melhoraria efeitos de atenuação, inseriria um algoritmo de cálculo de normais mais preciso para objetos que sofrem escala na cena e adicionaria algumas poucas particularidades para modificar a forma de como a luz é tratada. Por hora, essas funcionalidades já suprem as necessidades do projeto.
Com essas implementações, fecho a parte gráfica da engine, faltando apenas a colisão para iniciar o gerador de mapas. Para tal, utilizarei a técnica de Picking. Rezem para que eu consiga!!!
Até lá...
Nenhum comentário:
Postar um comentário