Um pouco sobre o sombreamento Phong


“Não podemos esperar que possamos exibir o objeto exatamente como ele é na realidade, com texturas, sombras etc. Esperamos apenas criar uma imagem suficientemente próxima para alcançar um certo grau de realismo ".

Bui Tyong Fong

Bui Thuong Fong nasceu em 1941 e se tornou cientista da computação durante a Guerra do Vietnã. Deve ter sido difícil para ele concluir seus estudos no ambiente tóxico dos anos 60, sem mencionar o fato de que ele foi chamado para a frente! Mas ele conseguiu sobreviver e sobreviver até 1975, antes que a leucemia se matasse apenas dois anos depois de lançar as bases para o mundo da moderna teoria da iluminação e sombreamento: o sombreador de Fong . Os nomes vietnamitas consistem em três partes: sobrenome, nome do meio e nome pessoal. Ou seja, quando as pessoas dizem "Fong shader", chamam o nome pessoal de Bui Tyong. Você pode ler mais sobre nomes pessoais na Wikipedia .


Não sei se é Phong, mas, de acordo com o Google, sim.

“Deixe suavemente o sol agradável
Brincar na minha cama moribunda,
E'er o vale mal iluminado
Eu, com os pés solitários, devo pisar. "

Let The Light Enter - um poema de Francis Harper

O shader de Phong é baseado em matemática extremamente concisa. O que, de fato, você não precisa saber, a menos que queira sinceramente se tornar um programador de gráficos. No entanto, a longo prazo, seu conhecimento será útil. Abaixo, trechos do OpenGL Superbible, 7ª edição de Graham Sellers e da Kronos Group ARB Foundation.

A) Alguns conceitos


Primeiro, vamos descobrir os conceitos. Se você lida com modelagem 3D ou desenvolvimento de jogos há um minuto, então já deve ter encontrado, mas a repetição não incomodou ninguém.

A-1) Luz ambiente

A maioria dos livros, especialmente os de baixa qualidade, compara essa iluminação com a luz solar, mas isso é completamente falso. A iluminação ambiente não é luz solar. Ele vem de todas as direções , ou seja, é onipresente, mas nos cálculos é apenas um vetor com três componentes. No sombreamento de Phong, é adicionado no final, mas não muda.

A-2) Luz difusa / difusa

A iluminação difusa tem uma direção. Este é realmente um componente direcional da fonte de luz [sic] . No cinema, a luz é espalhada usando uma caixa flexível e, na computação gráfica, a luz é espalhada usando uma fórmula, que mostraremos abaixo. A magnitude, isto é, o tamanho da iluminação difusa, depende da superfície. Por exemplo, se a superfície é fosca, ou seja, absorve mais do que reflete a luz, então o valor será maior do que no caso de uma superfície lisa.


Luz ambiente dispersa / absorvida em uma tela fosca

A-3) Destaque Especular

Como a iluminação difusa, a luz refletida é direcional, mas baseada no brilho da superfície; deixa um destaque chamado brilho . Na vida real, o brilho não é parte integrante do material. De fato, um revestimento de filme ou uma gota de cera adicionará muito mais brilho ao que qualquer outra coisa. O brilho refletido é um fator que varia de 0 a 128, porque em valores acima de 128 não afetará muito o sombreador.


Filme com papel colorido de espessura de filme com revestimento de filme brilhante, um verdadeiro presente para uma criança.

A- 4) Albedo

Esta é a fração da luz incidente refletida pela superfície.

A-5) Fórmula de Phong

A fórmula para calcular o material de acordo com Phong é a seguinte:

Ip=kaia+kd left( vecL. VecN right)id+ks left( vecR. VecV right) alphais


Onde:

ka: Material ambiente

kd: Material difuso

ks: Material especular e  alpha: valor do brilho

ia: iluminação ambiente

id: iluminação difusa

is: iluminação indireta

Você pode perguntar, e os vetores? Não se preocupe, agora vamos falar sobre eles:

 vecN: normal à superfície

 vecL: o vetor unitário do ponto sombreado até a fonte de luz (em outras palavras, o vetor de luz)

 vecR: reflexão do valor negativo do vetor de luz

 overrightarrowV: vetor direcionado ao espectador


B) sombreamento de Gouraud


Antes de embarcar no sombreador de Fong, vamos ver como você pode obter sombreamento do Gouro no GLSL. Observe que eu uso a versão GLSL 4.1, como em Superbible, mas se você é fã do www.learnopengl.com , pode usar o 3.3. Isso não importa. Então, vamos ver o que é o sombreamento Gouraud.

Este método de sombreamento foi inventado por Henri Gouraud em 1971. Ele não supera o sombreamento Phong e, atualmente, é usado principalmente como um método de visualização de carregamento sem GPU em pacotes como o Cinema 4D. O problema dele é que a chama que ele gera parece uma faísca:


Esse problema é causado pela interpolação de cores entre os vértices e as lacunas entre triângulos ocorrem porque as cores são interpoladas linearmente. Esse problema foi resolvido apenas no shader Phong. Vamos ver como você pode implementar o sombreamento do Gouro no GLSL 4.1.

Listagem 1 : sombreamento de vértice Gourox no GLSL 4.1

#version 410 core // Per-vertex inputs layout (location = 0) in vec4 position; layout (location = 1) in vec3 normal; // Matrices we'll need layout (std140) uniform constants { mat4 mv_matrix; mat4 view_matrix; mat4 proj_matrix; }; // Light and material properties uniform vec3 light_pos = vec3(100.0, 100.0, 100.0); uniform vec3 diffuse_albedo = vec3(0.5, 0.2, 0.7); uniform vec3 specular_albedo = vec3(0.7); uniform float specular_power = 128.0; uniform vec3 ambient = vec3(0.1, 0.1, 0.1); // Outputs to the fragment shader out VS_OUT { vec3 color; } vs_out; void main(void) { // Calculate view-space coordinate vec4 P = mv_matrix * position; // Calculate normal in view space vec3 N = mat3(mv_matrix) * normal; // Calculate view-space light vector vec3 L = light_pos - P.xyz; // Calculate view vector (simply the negative of the view-space position) vec3 V = -P.xyz; // Normalize all three vectors N = normalize(N); L = normalize(L); V = normalize(V); // Calculate R by reflecting -L around the plane defined by N vec3 R = reflect(-L, N); // Calculate the diffuse and specular contributions vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo; vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo; // Send the color output to the fragment shader vs_out.color = ambient + diffuse + specular; // Calculate the clip-space position of each vertex gl_Position = proj_matrix * P; } 

E agora o fragmento shader.

Listagem 2: O shader de fragmento do mesmo conceito.

 #version 410 core // Output layout (location = 0) out vec4 color; // Input from vertex shader in VS_OUT { vec3 color; } fs_in; void main(void) { // Write incoming color to the framebuffer color = vec4(fs_in.color, 1.0); } 

C) sombreamento de Phong


Antes de prosseguir, lembremos que o sombreamento Phong e a iluminação Phong são dois conceitos diferentes. Você pode se livrar do "floco de neve" do flare do Gouro adicionando mais vértices, mas por que se temos sombreamento no Fong? No sombreamento Phong, a cor não é interpolada entre os vértices (como nas Listagens 1 e 2), interpolamos entre os vértices normais à superfície e usamos o normal gerado para executar todos os cálculos de iluminação para cada pixel , não os vértices. No entanto, isso significa que o shader de fragmento precisará fazer mais trabalho, conforme mostrado na Listagem 4. Mas primeiro, vejamos o shader de vértice.


Listagem 3: o vertex shader do Phong shader no GLSL 4.1.

 #version 410 core // Per-vertex inputs layout (location = 0) in vec4 position; layout (location = 1) in vec3 normal; // Matrices we'll need layout (std140) uniform constants { mat4 mv_matrix; mat4 view_matrix; mat4 proj_matrix; }; // Inputs from vertex shader out VS_OUT { vec3 N; vec3 L; vec3 V; } vs_out; // Position of light uniform vec3 light_pos = vec3(100.0, 100.0, 100.0); void main(void) { // Calculate view-space coordinate vec4 P = mv_matrix * position; // Calculate normal in view-space vs_out.N = mat3(mv_matrix) * normal; // Calculate light vector vs_out.L = light_pos - P.xyz; // Calculate view vector vs_out.V = -P.xyz; // Calculate the clip-space position of each vertex gl_Position = proj_matrix * P; } 

Quase nada mudou. Mas no shader de fragmentos, a situação é completamente diferente.

Listagem 4: Fong fragment shader shader.

 #version 410 core // Output layout (location = 0) out vec4 color; // Input from vertex shader in VS_OUT { vec3 N; vec3 L; vec3 V; } fs_in; // Material properties uniform vec3 diffuse_albedo = vec3(0.5, 0.2, 0.7); uniform vec3 specular_albedo = vec3(0.7); uniform float specular_power = 128.0; uniform vec3 ambient = vec3(0.1, 0.1, 0.1); void main(void) { // Normalize the incoming N, L and V vectors vec3 N = normalize(fs_in.N); vec3 L = normalize(fs_in.L); vec3 V = normalize(fs_in.V); // Calculate R locally vec3 R = reflect(-L, N); // Compute the diffuse and specular components for each fragment vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo; vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo; // Write final color to the framebuffer color = vec4(ambient + diffuse + specular, 1.0); } 

Bem, este é o fim do artigo, espero que tenham gostado. Se isso despertou um interesse no OpenGL, você pode comprar o OpenGL Superbible na Amazon ou explorar o learnopengl.com. Se você não consegue lidar com shaders, recomendo o Book of Shaders .

Source: https://habr.com/ru/post/pt441862/


All Articles