Cores, Luzes e Materiais

5 04 2008

No artigo anterior, vimos em detalhes o que são cores, e vimos rapidamente como o hardware gráfico evoluiu para representa-las. Chegou a hora de usar esse conhecimento no OpenGL.

Definindo a cor da pintura

O comando usado para definir a cor de pintura é o comando void glColor<a><t>(red, green, blue, alfa);. A letra <a> representa o número de argumentos, que pode ser 3, caso você queira especificar apenas os valores de verde, vermelho e azul, ou 4, caso você queira colocar também a transparência (alfa). Veremos a transparência com mais detalhes no futuro.

O parâmetro <t> representa o tipo de dados da função. Ele pode ser b (byte), d (double), f (float), i (integer), s (short), ub (unsigned byte), ui (unsigned int) ou us (unsigned short). Outras versões da função também aceitam a letra v ao final, indicando que os dados serão enviados dentro de um vetor.

Uma prática comum é fornecer os dados como floats. Nesse formato, especificamos 0.0f para a ausência total de cor e 1.0f para a máxima intensidade daquele componente de cor. Muitos programadores que iniciam o estudo de computação gráfica podem preferir a função glColorub, já que nela você pode especificar valores de 0 até 255, como faria na programação Windows tradicional, ou numa página HTML. Na verdade, essa é uma forma fácil de fazer com que as cores do OpenGL sejam similares aos da sua aplicação, no caso de você estar construindo um CAD, por exemplo.

Não é o caso dos jogos. Até porque, essa abordagem também tem desvantagens. A primeira é que não é adotada pela comunidade. Várias documentações e fóruns na internet se referirão a outra forma, então é bom se acostumar com ela. Em segundo lugar, a forma com floats é usada internamente pelo OpenGL. Usar a forma com bytes gerará conversões o tempo todo, o que pode representar uma pequena perda de performance. Finalmente, esse formato é mais consistente caso o número de bits de cor mude, especialmente se a mudança for para mais bits.

O comando, como tudo no OpenGl, define a cor na máquina de estados. Assim, todos os que forem desenhados após ele, até a execução de um novo glColor, terão a mesma cor.

Shading

Como já vimos na prática, ao especificar num polígono ou linha vértices de cores diferentes, o OpenGL preenche o interior desse polígono com uma mudança gradual de cor. A forma como essa mudança ocorre é chamada de Shading Model.

O shading model pode ser alterado através do comando glShadeModel, bastando para isso passar o parâmetro FL_FLAT. A palavra flat significa “liso, chapado”. Com ele, a cor do interior do polígono será preenchida somente com a cor do último vértice especificado, não havendo qualquer tipo de cálculo de cor no interior do polígono.

O mundo real e o OpenGL

Como vimos, no mundo real a cor é formada por reflexão da luz sobre os materiais. Os materiais têm propriedades reflexívas e absorsivas diferentes, para cada componente da luz. Da mesma forma, a luz também pode ter cores diferentes de acordo com o seu espectro.

Modelar a luz real é uma tarefa extremamente cara em termos computacionais. Isso porque um objeto não recebe apenas luz direta, mas também parte da luz refletida nos objetos a sua volta. Alguns algoritmos como o de radiosidade ou ray-tracing tentam fazer essa aproximação mais precisa, mas seriam impeditivamente caros numa aplicação onde a renderização é feita em tempo real, como os jogos.

O OpenGL, assim como a maioria das APIs gráficas, adotaram então um modelo de iluminação muitíssimo mais simples. Nesse modelo, a luz é calculada sobre os polígonos individuais, portanto, ela não é barrada e nem os objetos deixam sombra.

Também dizemos que cada luz é formada por três componentes: ambiente, difusa e especular. No mundo real, esses componentes obviamente não existem, mas eles serão bastante úteis em nosso modelo simplificado, já que permitem regular com boa precisão o efeito que a luz tem em nossos objetos.

Luz ambiente

A luz ambiente não vem de nenhuma direção específica. Seria o caso da luz que teve uma origem, mas já rebateu tanto até chegar no local que a direção se perdeu. A face de todos os polígonos iluminados dessa forma fica exatamente igual. Por exemplo, seria muito difícil distinguir uma esfera de um círculo se só houvesse esse tipo de luz na sala, já que não conseguiriamos distinguir o seu volume. Você pode pensar nesse tipo de luz como um fator de brilho geral.

Note que a luz ambiente, para ser calculada, não depende nem da posição do objeto e nem da posição do observador. Por isso, é o tipo mais barato de luz em termos computacionais.

Luz difusa

O componente difuso representa a luz que parece ter vindo de uma origem, mas que reflete com intensidade proporcional ao ângulo que o raio de luz atinge a superfície do objeto. Assim, a superfície do objeto parecerá mais brilhosa se a luz estiver posicionada diretamente na superfície do que a luz que pega de raspão, num ângulo maior. Exemplos origem desse tipo de luz incluem uma vela, a luz direta do sol, etc. Com esse tipo de luz, existe shading (variação de cor) entre uma área mais iluminada e outra menos iluminada, o que nos permite distinguir mais facilmente objetos tridimensionais. Na figura abaixo, temos um exemplo de objeto iluminado por luz difusa:

Luz difusa

O cálculo da luz difusa já depende da posição da origem da luz e do objeto no mundo sendo, portanto, um pouco mais caro.

Luz especular

Como a luz difusa, a luz especular tem um componente fortemente direcional, portanto, reflete-se praticamente numa única direção. Um componente especular forte faz com que haja um brilho num único ponto da figura, tal como ocorre com os metais. Já um componente fraco, torna a figura fosca, como no caso da borracha escolar, usada para apagar texto.

O cálculo desse componente de luz leva em consideração não só a origem do ponto de luz e a posição do objeto iluminado, como também a posição do espectador. Afinal, a luz especular é fortemente direcional e será mais visível se o olho estiver diretamente voltado a sua origem. A figura abaixo mostra melhor esse conceito. Nela o espectador A vê o brilho especular, enquanto B não.

A vê a luz, B não.

Por depender de tantos fatores, o componente especular é o mais caro de ser calculado.

Como a luz é representada

Ao descrevermos a nossa fonte de luz, temos que informar todos os três componentes recém apresentados. E é muito pouco provável que uma fonte de luz conterá apenas um deles. Um exemplo extremo seria um laser, como esses usados por palestrantes.

Evidentemente, ela tem um forte componente especular vermelho, o que produz um brilho muito intenso, mas apenas no ponto onde ela atinge o objeto. Se usarmos o laser no escuro, perceberemos também que ele chega a iluminar fracamente os objetos em volta dele, o que indica também um fraco componente direcional. Caso a sala tenha algum tipo de vapor ou fumaça, também poderíamos associar a esse laser um componente de luz ambiente, já que essas particulas espalhariam parte da luz, tornando quase todos os objetos na sala fracamente avermelhados.

Em cada componente da luz (especular, difuso e ambiente) fornecemos cada componente de cor desejado, usando também os três valores RGB. No caso da luz, não faz sentido falarmos em fator de transparência (alfa). Para o laser descrito anteriormente, na sala com um leve vapor, teríamos:

Especular: 0.99 vermelho, 0 verde, 0 azul
Difuso: 0.10 vermelho, 0 verde, 0 azul
Ambiente: 0.05 vermelho, 0 verde, 0 azul.

Note que o laser, por ser uma fonte de luz muito pura, é completamente desprovido de azul ou verde. Cada componente da luz também é representado por um número, que varia de 0 até 1.

Materiais

Dizer que um determinado vértice tem uma cor é interessante, mas está muito longe de como as cores funcionam no mundo real. Quando estamos preocupados com a iluminação não descrevemos os polígonos através de cores, mas dizemos que um polígono é feito de um material que reflete a maior parte da cor desejada.

Fazemos isso especificando como o material reflete os componentes ambiente, difuso e especular das luzes que recebem. Um material poderia ser brilhante, refletindo a maior parte a luz especular, enquanto absorve boa parte da luz ambiente e difusa, enquanto outro poderia ser opaco, sem refletir a luz especular em nenhuma circunstância. Além desses três componentes, um material também pode representar um componente emissivo, que indica que ele não só reflete luz, como também brilha.

No caso, o componente emissivo fará com que o objeto pareça brilhar, mas não iluminará os objetos envolta dele. Para que isso seja possível, é necessário definir uma origem de luz no centro do objeto. Veremos como definir origem de luz no próximo artigo.

Iluminando os materiais

Definir as luzes e os materiais para atingir um efeito específico requer prática. Não existe uma regra simples que te diga exatamente como o objeto vai ficar. Aqui é o ponto onde nos afastamos da ciência exata e damos lugar ao lado artístico. É por isso que programadores, que tem um talento artístico próximo ao nulo, geralmente constróem ou aceitam arquivos de ferramentas que permitam que um designer aplique esses conceitos (tal como o 3D Studio Max e o Blender).

De maneira geral, o que o OpenGL faz é multiplicar cada componente da luz em R, G e B pelo seu respectivo componente do material (essa regra só pode ser aplicada diretamente para a luz ambiente). Por isso, os números de luzes e materiais variam entre 0 e 1. Veremos mais detalhes sobre os cálculos com luzes no futuro.

Em resumo

Nesse artigo, relembramos a forma direta de definir cores. Mas vimos que ela não é muito precisa para objetos sólidos. Então, vimos o como o OpenGL modela a luz de maneira simplificada. Vimos os três componentes básicos da luz nesse modelo: ambiente, difuso e especular.

Também foi explicado que os materiais refletem cada um desses componentes, além de ter um componente a mais, o emissivo, usado para dar a sensação de que o objeto está brilhando.

Nos próximos artigo, veremos de maneira mais prática como aplicar esses conceitos dentro de nosso programa. Depois, veremos um pouco mais a fundo a matemática envolvida, o que nos ajudará a entender como exatamente a iluminação funciona.


Ações

Informações

8 respostas

6 04 2008
Diogo_RBG

Não sei de onde você encontra tanta inspiração e clareza nas explicações.
O assunto está se tornando cada vez mais complexo, mas vejo que você tira de letra.
Excelente trabalho !

6 04 2008
vinigodoy

Metade é da minha pós e do fato de eu já ter sentado a bunda na cadeira e estudo o assunto por várias horas.

E outra metade é do OpenGL Super Bible e do Beginning OpenGL Game Programming, que já citei em vários posts.

Não tem jeito, só com esforço e estudo para aprender e falar bem de alguma coisa! :)

Mas teu blog também é muito legal. Sou leitor de carteirinha!

11 04 2008
skhaz

Concordo com o que o Diogo disse acima, eu já ate o chamo de Mestre/Professor Vinicius :D

15 05 2008
Tiago

SOCORRO!!!

Alguma sugestão???

Criar um modelo simplificado para o interior de uma parte de um prédio.
Um visitante poderá caminhar pelos corredores, abrir portas, entrar nas salas, circular dentro delas, ligar e desligar as luzes.
Pelo menos algumas salas de aula e algumas salas de professores devem poder ser abertas e visitadas. As demais salas do setor podem estar fechadas.
As janelas devem estar presentes, com suas esquadrias e vidraças, mas não precisam abrir.
Em uma das salas a janela deve ter persianas que abrem e fecham.
As cores de paredes, vigas, portas e móveis devem ser aproximadas.

O visitante deve poder escolher entre cena noturna e cena diurna. A primeira deve considerar apenas iluminação interna, sem nenhuma influência do meio externo. Na cena diurna o efeito da iluminação externa deve estar presente e alguns itens externos devem ser visíveis através das janelas.

A área escolhida deve ser exclusiva e deve ser comunicada juntamente com a composição do grupo. Se houver duplicidade na escolha, o grupo será comunicado para que possa escolher outra área.

Vlw.

15 05 2008
vinigodoy

Só uma… sente a bunda na cadeira, estude a matéria e faça… E prepare-se porque vai dar um bocado de trabalho.

Infelizmente, não tem jeito fácil de aprender. Um pouco de suor as vezes é beeem necessário. ;)

8 07 2008
Bruno

Muito bom o artigo.
So um reparo: No red book (Opengl Programming Guide), woo diz:

The OpenGL lighting model considers the lighting to be divided into four independent components: emitted, ambient, diffuse, and specular. All four components are computed independently, and then added together.

Falta por isso falar na componente emissiva da luz.

8 07 2008
Bruno

Peço desculpa. Li o teu artigo de relance e agora, depois de uma leitura mais completa vejo que falas na componente emissiva. Mais uma vez as minhas desculpas. Muito bom artigo.

8 07 2008
vinigodoy

Olá.

Você leu o subtópico que fala dos materiais? Ali estou falando do componente emissivo.

Coloquei lá porque ele só é aplicado a materiais e ainda deixei uma observação muito importante: embora o material pareça estar brilhando, ele não é considerado pelo OpenGL uma fonte de luz, assim, não iluminará o que está em volta dele.

Deixe um comentário