Bem vindo ao tutorial número 7 nessa série de tutoriais WebGL, baseado na lição 7 do LearningWebGL. Vamos trabalhar com um dos assuntos mais importantes da computação gráfica: iluminação. Na verdade falaremos e faremos o básico. Vou apresentar um conteúdo mais matemático. Espero que seja compreensível para quem ainda não tem estudado álgebra linear e outras disciplinas.
Veja o resultado:
Um aviso (de novo): estas lições estão baseadas no conteúdo dado na disciplina de Introdução à Computação Gráfica do Instituto de Matemática e Estatística da USP. Mesmo assim, outras pessoas que não sejam alunos dessa disciplina podem aproveitar e compreender o conteúdo destes tutoriais. Faça os tutoriais anteriores para melhor compreensão do que está acontecendo. O código mostrado é apenas a diferença para o tutorial 7. Se houver falhas ou achar que falta alguma coisa para melhorar o tutorial, não hesite em me avisar.
Antes de trabalhar com iluminação, precisamos fortalecer um pouco nossa base matemática, pois as técnicas de iluminação que vamos utilizar necessitam delas. Eu não mostrei antes para que vocês pudessem experimentar a prática e verem o resultado o mais rápido possível, além de perceberem melhor a necessidade de se estudar álgebra linear (abordagem pedagógica top-down).
Como essa revisão de álgebra linear é grande, embora curta comparado aos livros-texto, criei outro post dedicado a ele. Se você quiser estudar, ou apenas dar uma revisada, sinta-se à vontade. Se você estiver seguro dos seus conhecimentos de álgebra linear, então pode seguir em frente.
Luzes
Uma má notícia: não existe funções pré-definidas em WebGL para iluminação. Mas há uma boa notícia: uma vez explicado um ou mais modelos de iluminação, é fácil aplicá-lo em WebGL por meio de shaders. Além disso, sombras podem ser adicionadas como objetos próprios (tu mesmo deves fazer isso manualmente) ou uma interação entre os raios e os objetos, atingindo o destino final (que pode ser outro objeto). Também nesse caso o desenvolvedor deve calcular isso.
O objetivo é simular um número de fontes de luz na cena. As fontes não precisam necessariamente aparecer, mas seus efeitos devem tornar os objetos mais realísticos. Se alguma face do objeto estiver direcionada à luz, ela será mais iluminada. Para cada objeto precisamos saber como interage com cada fonte de luz. Creio que neste ponto dos tutoriais você já sabe que todo este processo envolverá shaders. Neste tutorial você saberá como a luz afeta a cor de um vértice e dos seus intermediários. Vamos aproveitar o processo de interpolação dos shaders. Por enquanto vamos trabalhar com uma fonte de luz, todavia não é complicado adicionar outras fontes.
Quando a luz interage com um material, ela pode ser refletida, refratada (transmitida) ou absorvida. Tudo isso depende do ângulo do raio de luz, em que posição do material ela chega, do comprimento de onda que a luz é refletida/refratada/absorvida. Alguns modelos foram propostos. No caso da reflexão, que vamos trabalhar neste tutorial, o modelo é o Bi-directional Reflectance Distribution Function (BRDF). O artigo de Wynn dá uma boa noção sobre o modelo BRDF.
O modelo BRDF calcula a relação entre a energia que chega em uma determinada faixa de direções (determinado por dois ângulos em coordenadas esféricas), e a energia que sai a partir daquele ponto para uma faixa de direções (também determinado por dois ângulos em coordenadas esféricas).
Se parte da luz que chega for na verdade reflexões e refrações da luz por outros objetos, então significa que o modelo é de iluminação global. Se estiveres trabalhando apenas com a interação direta entre a luz e a superfície do objeto, então este modelo é de iluminação local. Uma simplificação do modelo BRDF para iluminação local é o Modelo de Reflexão Phong.
Preparar os Controles de Luz
Preparar o Uso da Luz
Editar o Fragment Shaders
varying vec2 vTextureCoord; varying vec3 vPotenciaLuz; uniform sampler2D uSampler; void main(void) { vec4 corTextura = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); //gl_FragColor = corTextura; gl_FragColor = vec4(corTextura.rgb * vPotenciaLuz, corTextura.a); }
Editar os Vertex Shadders
uniform vec3 uCorAmbiente; uniform vec3 uDirecaoLuz; uniform vec3 uCorDifusa; uniform bool uUsarLuz; varying vec2 vTextureCoord; varying vec3 vPotenciaLuz; void main(void) { gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aVertexPosition, 1.0); vTextureCoord = aTextureCoord; if(!uUsarLuz){ vPotenciaLuz = vec3(1.0,1.0,1.0); }else{ vec3 normalTransformado=uNMatrix * aVertexNormal; float potenciaLuz = max(dot(normalTransformado, uDirecaoLuz),0.0); vPotenciaLuz = uCorAmbiente + uCorDifusa * potenciaLuz; } }
Exercícios: