Un poco sobre el sombreado de Phong


“No podemos esperar que podamos mostrar el objeto exactamente como es en realidad, con texturas, sombras, etc. Solo esperamos crear una imagen lo suficientemente cercana como para lograr un cierto grado de realismo ".

Bui Tyong Fong

Bui Thuong Fong nació en 1941 y se convirtió en informático durante la Guerra de Vietnam. ¡Debe haber sido difícil para él completar sus estudios en el ambiente tóxico de los años 60, sin mencionar el hecho de que fue llamado al frente! Pero logró sobrevivir y sobrevivir hasta 1975, antes de que la leucemia le quitara la vida solo dos años después de sentar las bases del mundo de la teoría moderna de la iluminación y el sombreado: el sombreador de Fong . Los nombres vietnamitas constan de tres partes: apellido, segundo nombre y nombre personal. Es decir, cuando la gente dice "Fong shader", llaman al nombre personal Bui Tyong. Puede leer más sobre nombres personales en Wikipedia .


No estoy seguro de si esto es Phong, pero según Google, sí.

"Suavemente deja que la cálida luz del sol
Juega alrededor de mi cama moribunda
E'er el valle débilmente iluminado
Yo con pies solitarios debo pisar. "

Let The Light Enter - un poema de Francis Harper

El sombreador de Phong se basa en matemáticas extremadamente concisas. Lo que, de hecho, no necesita saber, a menos que desee sinceramente convertirse en un programador de gráficos. Sin embargo, a la larga, su conocimiento será útil. A continuación se presentan extractos de OpenGL Superbible, séptima edición de Graham Sellers y la Fundación ARB de Kronos Group.

A) algunos conceptos


En primer lugar, descubramos los conceptos. Si ha estado lidiando con el modelado 3D o el desarrollo del juego incluso por un minuto, entonces ya debe haberlos encontrado, pero la repetición no ha molestado a nadie.

A-1) Luz ambiental

La mayoría de los libros, especialmente los de baja calidad, comparan esta iluminación con la luz solar, pero esto es completamente falso. La iluminación ambiental no es la luz solar. Proviene de todas las direcciones , es decir, es omnipresente, pero en los cálculos es solo un vector con tres componentes. En el sombreado de Phong, se agrega al final, pero no cambia.

A-2) Luz difusa / difusa

La iluminación difusa tiene una dirección. Esto es en realidad un componente direccional de la fuente de luz [sic] . En el cine, la luz se dispersa usando una caja suave, y en los gráficos de computadora, la luz se dispersa usando una fórmula, que mostraremos a continuación. La magnitud, es decir, el tamaño de la iluminación difusa, depende de la superficie. Por ejemplo, si la superficie es mate, es decir, absorbe más de lo que refleja la luz, entonces el valor será mayor que en el caso de una superficie lisa.


Luz ambiental dispersada / absorbida de una pantalla esmerilada

A-3) Destacado especular

Al igual que la iluminación difusa, la luz reflejada es direccional, pero se basa en el brillo de la superficie; deja un punto culminante llamado brillo . En la vida real, el brillo no es una parte integral del material. De hecho, un recubrimiento de película o una gota de cera agregarán mucho más brillo que cualquier otra cosa. El brillo reflejado es un factor que varía de 0 a 128, porque a valores superiores a 128 no afectará en gran medida al sombreador.


Película con película: papel de color grueso con un recubrimiento de película brillante, un verdadero regalo para un niño.

A- 4) Albedo

Esta es la fracción de luz incidente reflejada por la superficie.

A-5) Fórmula Phong

La fórmula para calcular el material según Phong es la siguiente:

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


Donde:

ka: Material ambiental

kd: Material difuso

ks: Material especular y  alpha: valor de brillo

ia: iluminación ambiental

id: iluminación difusa

is: iluminación indirecta

Usted puede preguntar, ¿qué pasa con los vectores? No te preocupes, ahora te contaremos sobre ellos:

 vecN: normal a la superficie

 vecL: el vector unitario desde el punto sombreado hasta la fuente de luz (en otras palabras, el vector de luz)

 vecR: reflejo del valor negativo del vector de luz

 overrightarrowV: vector dirigido hacia el espectador


B) Sombreado de Gouraud


Antes de embarcarse en el sombreador de Fong, veamos cómo puede obtener el sombreado de Gouro en GLSL. Tenga en cuenta que uso la versión GLSL 4.1, como en Superbible, pero si es fanático de www.learnopengl.com , puede usar 3.3. No importa Entonces, veamos qué es el sombreado de Gouraud.

Este método de sombreado fue inventado por Henri Gouraud en 1971. No supera el sombreado de Phong de ninguna manera, y hoy se usa principalmente como un método de vista previa de carga sin GPU en paquetes como Cinema 4D. Su problema es que la llamarada que genera parece una chispa:


Este problema es causado por la interpolación de colores entre vértices y se producen espacios entre triángulos porque los colores se interpolan linealmente. Este problema solo se resolvió en el sombreador Phong. Veamos cómo puede implementar el sombreado Gouro en GLSL 4.1.

Listado 1 : sombreado de vértices Gourox en 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; } 

Y ahora el sombreador de fragmentos.

Listado 2: El sombreador de fragmentos del mismo concepto.

 #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) sombreado de Phong


Antes de continuar, recordemos que el sombreado y la iluminación de Phong son dos conceptos diferentes. Puedes deshacerte del "copo de nieve" de la llamarada de Guro agregando más vértices, pero ¿por qué si tenemos sombra en Fong? En el sombreador Phong, el color no se interpola entre los vértices (como en el Listado 1 y 2), interpolamos entre los vértices de lo normal a la superficie , y usamos la normal generada para realizar todos los cálculos de iluminación para cada píxel , no el vértice. Sin embargo, esto significa que el sombreador de fragmentos tendrá que hacer más trabajo, como se muestra en el Listado 4. Pero primero, veamos el sombreador de vértices.


Listado 3: el sombreador de vértices del sombreador de Phong en 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; } 

Casi nada ha cambiado. Pero en el fragment shader, la situación es completamente diferente.

Listado 4: Fong 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); } 

Bueno, este es el final del artículo, espero que lo hayan disfrutado. Si ha despertado una chispa de interés en OpenGL en usted, puede comprar OpenGL Superbible en Amazon o explorar learnopengl.com. Si no puede lidiar con shaders, le recomiendo Book of Shaders .

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


All Articles