Ponto V!

Home OpenGL Luzes na prática – Parte 1
Vinícius Godoy de Mendonça
Luzes na prática – Parte 1Imprimir
Escrito por Vinícius Godoy de Mendonça

No artigo passado, estudamos como é o modelo de iluminação da OpenGL. Vimos que é formado por três tipos de luzes: especular, ambiente e difusa. Vimos que materiais “refletem” essas luzes e também tem seus componentes especular, difuso, ambiente, e um componente a mais, o emissivo.

Neste artigo finalmente veremos como aplicar isso num programa.

Habilitando luzes

Como você já deve ter imaginado, o primeiro passo para se trabalhar com luzes é habilitar essa capacidade na OpenGL. Fazemos isso através do comando glEnable, passando como parâmetro a constante GL_LIGHTING. Tome cuidado, uma vez dado esse comando, se não houver ainda coordenadas de luz e material em seu objeto, ele será desenhado inteiro de preto. Afinal, será um objeto que não reflete absolutamente nada sendo iluminado por quase nenhuma luz.

Definindo a luz ambiente global

Não confunda! Quanto falamos em “luz ambiente global” não estamos falando do “componente ambiente da luz”. A OpenGL possui uma luz especial, que afeta todos os objetos da cena. Essa luz só possui o componente ambiente e sua aplicação é totalmente gratuita.

Essa luz representa os raios luminosos que refletem tantas vezes, que acabam por se tornar homogêneos e espalhados por todo lugar. Também podemos imaginar essa luz como a “escuridão mínima” que um objeto pode atingir em sua cena. Abaixo, temos o exemplo da configuração de uma cena com a luz ambiente ligada:

//Luz avermelhada (sala com lava?)
GLfloat ambientLight[] = {0.40f, 0.15f, 0.15f, 1.00f};

//Habilitamos a capacidade de iluminação
glEnable(GL_LIGHTING);

//Configuramos a OpenGL para utilizar como luz ambiente global
//a iluminação definida por ambientLight[]
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
A variação de glLightModel mostrada aqui, glLightModelfv, aceita como primeiro parâmetro qual das propriedades do modelo de luz da OpenGL está sendo modificada. A segunda, aceita um vetor de valores contendo as cores RGBA dessa luz. Por padrão, a OpenGL usa {0.2, 0.2, 0.2, 1.0} para essa luz, o que é bastante apagado. Você também poderia modificar outros parâmetros do modelo de iluminação com essa função tais como se é a frente, a parte de trás ou os dois lados dos polígonos que são iluminados e como o cálculo dos ângulos da luzes especulares é realizado.

Definindo a propriedade dos materiais

Para que seus objetos passem a ser desenhados, é necessário dizer que eles refletem luz. É por isso que, mesmo a luz ambiente não sendo totalmente apagada por padrão, seu objeto é desenhado inteiro de preto. Afinal, tal como o monolito de 2001 – Uma Odisséia no Espaço, seu objeto absorve toda e qualquer luz.

Existem duas maneiras de definir propriedades de material. A primeira, é usando o comando glMaterial antes de especificar um polígono ou conjunto de polígonos. Veja o exemplo a seguir:

GLfloat yellow[] = {1.0f, 0.9f, 0.3f, 1.0f};
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellow);

glBegin(GL_TRIANGLES);
    ... //Desenhamos uma pirâmide usando glVertex3f()
glEnd();

O primeiro parâmetro da função glMaterialfv pode assumir três valores: GL_FRONT, GL_BACK ou GL_FRONT_AND_BACK e define para qual face do polígono está sendo aplicada a configuração de material fornecida. O segundo parâmetro, diz a quais componentes de luz refletidos pelo material se refere os valores passados, no caso, estamos aplicando para os componentes difuso e ambiente. Finalmente, o terceiro parâmetro é um array contendo os valores RGBA com as cores sendo refletidas pelo material. Todas as primitivas especificadas após o comando glMaterial serão afetadas pelos últimos valores fornecidos, até que uma nova chamada a glMaterial seja feita.

É muito comum que a os componentes de luz ambiente e difusa sejam definidos de maneira idêntica. Além disso, a menos que você queira pontos brilhantes, não haverá necessidade de configurar um componente de especular. Por isso, existe uma segunda maneira muito mais fácil de definir materiais, usando apenas chamadas ao comando glColor. Essa maneira é chamada de rastreamento de cor (color tracking) e geralmente é a maneira preferida quando se monta desenhos manualmente.

O primeiro passo para habilitar o rastreamento é ativar essa capacidade. Em seguida, devemos dizer que faces e componentes da luz serão afetados. Fazer isso é muito simples:

glEnable(GL_COLOR_MATERIAL);

glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
...
glColor3f(1.0f, 0.9f, 0.3f);
glBegin(GL_TRIANGLES);
    ... //Desenhamos uma pirâmide usando glVertex3f()
glEnd();

Note que isso evita que tenhamos que especificar cada um dos 3 componentes de materiais o tempo todo. O que reduz o número de chamadas a função glMaterial, deixa o código mais limpo e possivelmente mais rápido.

Se definirmos o componente especular, também podemos definir se a luz que atinge o material será refletida de maneira uniforme por sua superfície, como no caso de uma borracha escolhar, ou de maneira concentrada, num único ponto, como numa bola de metal. Para fazer isso, usamos o expoente GL_SHININESS. Se quiséssemos que o material do exemplo anterior brilhasse como um metal, bastaria adicionar as seguintes linhas em sua declaração:

GLfloat[] specref = {1.0f, 1.0f, 1.0f, 1.0f};
glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
glMateriali(GL_FRONT,GL_SHININESS,128);

Quanto maior o parâmetro passado em GL_SHININESS, mais concentrado será o brilho na face do material.

Definindo uma fonte de luz

Até agora, usamos apenas a luz ambiente global. Como essa luz só afeta o componente ambiente de absolutamente todos os objetos, sem distinção, seu efeito é bastante sem graça.

Vamos tornar tudo mais interessante ao definir novas fontes de luz. Assim, poderemos colocar luzes localizadas e ver os demais componentes (difuso e especular) em ação.

A OpenGL suporta 8 luzes ligadas ao mesmo tempo. Isso não significa que a placa de vídeo do nosso jogador suporte. De fato, cada luz ligada simultaneamente adiciona um tempo significativo de processamento – e esse tempo cresce exponencialmente. Além disso, cada luz acima ligada acima do máximo da placa de vídeo provavelmente será ignorada pelo hardware. Então, tome cuidado e organize seu jogo para não ter de ligar várias luzes ao mesmo tempo.

Esse número também não é tão pequeno quanto parece. Em primeiro lugar, a luz ambiente global não entra na conta. Além disso, luzes só são realmente necessárias via código caso elas sejam dinâmicas, ou seja, caso sua intensidade, cor ou posição mudem durante o jogo, ou caso o objeto em questão se mova. Não é o caso da maior parte do cenário, que pode já ter os efeitos de luz pré-calculados em sua própria textura. Além disso, no caso da iluminação comum, dificilmente a aplicação de mais de 3 luzes num mesmo objeto terá um efeito significativo. Por isso, você pode organizar seu código para que ative sempre as três luzes mais próximas, ou 3 luzes num raio de x pixels, e desligue as demais, sem que isso cause um prejuízo significativo no resultado final.

Especificamos qual luz será ligada usando também o glEnable e passando como parâmetro GL_LIGHT#, onde # é um número de 0 até 7. É possível questionar a placa de vídeo a respeito da quantidade de luzes que podem ser ligadas ao mesmo tempo usando o método glGet e passando como atributo o valor GL_MAX_LIGHTS.

//Obtemos o número máximo de luzes
GLint maxLights;
glGetIntegerv(GL_MAX_LIGHTS, &maxLights);
...
//E ligamos, por exemplo, a quinta luz, se disponível
if (maxLights >= 5)
    glEnable(GL_LIGHT4);

Definindo as propriedades da origem de luz

Cada ponto de luz está associado a uma série de propriedades, tais como sua posição, direção, cores de seus componentes ou seu tipo. Quanto ao tipo, a OpenGL suporta três tipos de fontes de luz, da mais barata até a mais cara:

  • Luz direcional: Representam luzes infinitamente distantes da cena, mas com uma origem definida. Para defini-la, precisamos apenas saber a direção da luz. Um bom exemplo desse tipo de luz é o sol;
  • Luz ponto ou luz posicional: Representa um ponto luminoso, tal como uma lâmpada, ou uma tocha, onde a luz propaga-se em todas as direções a partir daquele ponto. Para defini-la, precisamos saber a posição da luz;
  • Spotlights: Representa um ponto luminoso, de onde a luz se propaga em uma única direção, abrindo-se num cone. O melhor exemplo dessa luz é uma lanterna, ou um holofote. Todos vértices que estiverem dentro do cone serão iluminados, ou de fora não. Não desenha nem o círculo e nem o rastro de uma lanterna. Para defini-la, precisamos saber a direção, posição da luz e o tamanho do cone.

Luzes direcional e posicionais

Na natureza luzes direcionais não existem. Mas algumas origens de luz, como o sol ou a lua, estão tão distantes que podem ser tratadas dessa forma. Para o computador, a simplificação de luzes na forma de uma luz direcional infinitamente distante é uma excelente forma de baratear custos relacionados ao processamento de luzes, afinal, para calcular uma luz direcional, a OpenGL só precisa saber a posição do objeto. Nem a distância e nem a posição da luz são relevantes, já que todos os objetos são igualmente iluminados.

No caso das luzes posicionais, a OpenGL já é obrigada a calcular também o vetor de direção entre a origem da luz e cada objeto na cena, já que esse vetor pode mudar. Se habilitada, ele também calcula a atenuação da luz, já que é interessante que quanto mais longe um objeto esteja da origem da luz, mais fracamente iluminado ele pareça.

Criamos uma luz direcional ou posicional usando o parâmetro GL_POSITION para a função glLightfv e fornecendo um array de 4 floats. Os três primeiros valores representam as coordenadas x, y e z. Passe 0 no último valor caso você esteja definindo uma luz direcional ou 1 se você estiver definindo uma luz posicional. No primeiro caso, x, y z representação o vetor de direção da luz em relação a origem, e no segundo, x, y e z representam a coordenada do ponto luminoso. É importante ressaltar que coordenadas do ponto de luz são afetadas pela matriz de transformação modelview. Assim, costuma-se a definir a posição da luz logo depois da inicialização da câmera, antes de se mexer nas matriz para posicionar os objetos do mundo.

Se você ativar uma luz sem especificar os seus parâmetros, ela será uma luz direcional, que vai em direção ao eixo z.

Componentes da luz

Assim como os materiais, definimos a cor da luz através de seus componentes. Como vimos anteriormente, no modelo da OpenGL é luz é formada pelos componentes ambiente, difuso e especular. Por isso, chamamos uma das versões de glLight passando como parâmetro GL_LIGHT, GL_DIFFUSE ou GL_SPECULAR. Por padrão, todas as luzes da OpenGL estão com a cor preta, com exceção da luz 0, que tem cor branca.

O exemplo abaixo mostra como definir uma luz verde com um especular branco. Branco é a cor da maioria dos brilhos especulares. Note que praticamente qualquer plástico que brilhe reluz com a cor branca. A exceção é apenas para metais, como o ouro ou o cobre, onde o brilho especular segue o tom da cor difusa.

GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; //Fully white
GLfloat green[] = {0.0, 1.0, 0.0, 1.0}; //Bright green

glLightfv(GL_LIGHT0, GL_AMBIENT, green);
glLightfv(GL_LIGHT0, GL_DIFFUSE, green);
glLightfv(GL_LIGHT0, GL_SPECULAR, white);

Concluindo

Neste artigo, vimos como definir as propriedades básicas das luzes e dos materiais. Infelizmente, ele ainda não é suficiente para que iluminemos a cena. No próximo artigo, veremos como dizer à OpenGL como a luz se reflete nos materiais, usando para isso vetores normais.


Comentários (8)
  • Koolen  - Vixi.. Parei por hoje..
    avatar

    Já estou na quarta cerveja, e agora comecei a confundir os comandos.

    Já adicionei aqui no meu favoritos esta página, onde eu parei, amanhã vou continuar.

    Show de bola, to adorando o code::block, OpenGL, tudo que eu esperva de uma forma bem intuitiva, esta de parabens!

    Seus posts estam em uma classificação de alto nivel em nossa lingua. Em breve pretendo participar dos eventos.

    Vinicios, um abraço, até amanhã, quando continuo o curso.

  • Vinícius Godoy de Mendonça
    avatar

    Muito obrigado. Se tiver qualquer problema, seja nos exemplos ou no entendimento é só postar. :)

  • Irving Muller Rodrigues  - Problema ao mudar posição da janela
    avatar

    Ola vinny , estou com um problema que não tem nada ver com post.

    Você sabe o porquê de quando eu seguro a janela do programa e mudo-a de lugar,simplesmente o programa trava. O engraçado é que quando eu deixo rodando normal o programa , ele roda normalmente.

    valews abracus

  • Bruno Crivelari Sanches
    avatar

    Como você tem tratado as mensagens da janela? SDL?

    Isso depende de como são processadas as mensagens, o sistema de janelas notifica seu programa de tudo que estiver ocorrendo e se for SDL por exemplo, ela pode estar "travando" a thread quando esta perde o foco.

    T+

  • Augusto  - Setar luz a um objeto
    avatar

    Bem eu estou criando um mod de minecraft e estava precisando setar luz a um item mas o minecraft é dividido em Itens, Blocos e Entytis
    acontece que luz no minecraft apenas Entytis e blocos podem ser dados luz então vim pesquisar um pouco sobre isso e vi que a luz posicional é o que eu preciso só que não entendi bem como se usa, vc poderia me dar uma dica? lembrando que o minecraft é escrito em java vlw!

  • Antonio  - Problema
    avatar

    Ae blz cara.
    Muito bom o post!! só que aqui ocorreu um erro.
    O seguinte eu li esse post ate a parte 3 e fiz no open gles(android)
    a luz ambiente coloquei preta e a luz difusa branca.
    O problema é que só uma face fica iluminada quando rotaciono o objeto.
    Como se a luz rotaciona-se junto com o objeto , dai a outra face fica na luz ambiente.
    O que pode ser ?

  • ViniGodoy
    avatar

    Posta o código no pastebin. Sem ele fica difícil imaginar o que você está fazendo.

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter