Un peu sur l'ombrage Phong


«Nous ne pouvons pas nous attendre à pouvoir afficher l'objet exactement tel qu'il est en réalité, avec des textures, des ombres, etc. Nous espérons seulement créer une image suffisamment proche pour atteindre un certain réalisme. "

Bui Tyong Fong

Bui Thuong Fong est né en 1941 et est devenu informaticien pendant la guerre du Vietnam. Il a dû lui être difficile de terminer ses études dans l'environnement toxique des années 60, sans parler du fait qu'il a été appelé au front! Mais il a réussi à survivre et à survivre jusqu'en 1975, avant que la leucémie ne prenne sa vie seulement deux ans après avoir jeté les bases du monde de la théorie moderne de l'éclairage et de l'ombrage: le shader de Fong . Les noms vietnamiens se composent de trois parties: nom, deuxième prénom et nom de personne. Autrement dit, lorsque les gens disent «Fong shader», ils appellent le nom personnel Bui Tyong. Vous pouvez en savoir plus sur les noms de personnes sur Wikipedia .


Je ne sais pas si c'est Phong, mais selon Google, oui.

"Laissez doucement le soleil doux
Joue autour de mon lit mourant,
E'er la vallée faiblement éclairée
Je dois marcher avec des pieds seuls. "

Laissez entrer la lumière - un poème de Francis Harper

Le shader de Phong est basé sur des mathématiques extrêmement concises. Ce que vous n'avez en fait pas besoin de savoir, à moins que vous ne souhaitiez sincèrement devenir programmeur graphique. Cependant, à long terme, ses connaissances seront utiles. Vous trouverez ci-dessous des extraits de l' OpenGL Superbible, 7th Edition de Graham Sellers et de la Kronos Group ARB Foundation.

A) Quelques concepts


Tout d'abord, découvrons les concepts. Si vous vous occupez de la modélisation 3D ou du développement de jeux depuis une minute, vous devez les avoir déjà rencontrés, mais la répétition n'a dérangé personne.

A-1) Lumière ambiante

La plupart des livres, en particulier ceux de faible qualité, comparent cet éclairage à la lumière du soleil, mais c'est complètement faux. L'éclairage ambiant n'est pas la lumière du soleil. Il vient de toutes les directions , c'est-à-dire qu'il est omniprésent, mais dans les calculs, ce n'est qu'un vecteur à trois composantes. Dans l'ombrage de Phong, il est ajouté à la fin, mais ne change pas.

A-2) Lumière diffuse / diffuse

L'éclairage diffus a une direction. Il s'agit en fait d'une composante directionnelle de la source de lumière [sic] . Au cinéma, la lumière est diffusée à l'aide d'une boîte à lumière, et en infographie, la lumière est diffusée à l'aide d'une formule, que nous montrerons ci-dessous. L'amplitude, c'est-à-dire la taille de l'éclairage diffusé, dépend de la surface. Par exemple, si la surface est mate, c'est-à-dire qu'elle absorbe plus qu'elle ne réfléchit la lumière, alors la valeur sera plus élevée que dans le cas d'une surface lisse.


Lumière ambiante diffusée / absorbée à partir d'un écran dépoli

A-3) Surbrillance spéculaire

Comme la lumière diffuse, la lumière réfléchie est directionnelle, mais basée sur la brillance de la surface; il laisse un point culminant appelé brillance . Dans la vraie vie, le brillant ne fait pas partie intégrante du matériau. En fait, un revêtement de film ou une goutte de cire ajoutera beaucoup plus à la brillance qu'autre chose. Le brillant réfléchi est un facteur compris entre 0 et 128, car à des valeurs supérieures à 128, il n'affectera pas considérablement le shader.


Film avec film - papier de couleur épaisse avec une pellicule brillante, un vrai cadeau pour un enfant.

A- 4) Albédo

Il s'agit de la fraction de lumière incidente réfléchie par la surface.

A-5) Formule Phong

La formule de calcul du matériau selon Phong est la suivante:

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


Où:

ka : Matériau ambiant

kd : Matériau diffus

ks : Matériau spéculaire et  alpha : valeur de brillance

ia : éclairage ambiant

id : éclairage diffus

is : éclairage indirect

Vous pouvez demander, qu'en est-il des vecteurs? Ne vous inquiétez pas, nous allons maintenant vous en parler:

 vecN : normal à la surface

 vecL : le vecteur unitaire du point ombré à la source lumineuse (en d'autres termes, le vecteur lumière)

 vecR : réflexion de la valeur négative du vecteur lumière

 overrightarrowV : vecteur dirigé vers le spectateur


B) Ombrage Gouraud


Avant de vous lancer dans le shader de Fong, voyons comment obtenir l'ombrage Gouro sur GLSL. Veuillez noter que j'utilise la version GLSL 4.1, comme dans Superbible, mais si vous êtes un fan de www.learnopengl.com , vous pouvez utiliser 3.3. Peu importe. Voyons donc ce qu'est l'ombrage Gouraud.

Cette méthode d'ombrage a été inventée par Henri Gouraud en 1971. Il n'est en aucun cas supérieur à l'ombrage Phong, et aujourd'hui, il est principalement utilisé comme méthode d'aperçu de chargement sans GPU dans des packages comme Cinema 4D. Son problème est que la fusée qu'il génère ressemble à une étincelle:


Ce problème est dû à l'interpolation des couleurs entre les sommets et les écarts entre les triangles se produisent car les couleurs sont interpolées linéairement. Ce problème n'a été résolu que dans le shader de Phong. Voyons comment vous pouvez implémenter l'ombrage Gouro sur GLSL 4.1.

Listing 1 : Ombrage de vertex Gourox sur 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; } 

Et maintenant, le fragment shader.

Listing 2: Le fragment shader du même concept.

 #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) Ombrage Phong


Avant de poursuivre, rappelons que l' ombrage Phong et l' éclairage Phong sont deux concepts différents. Vous pouvez vous débarrasser du «flocon de neige» de l'éclat de Gouro en ajoutant plus de sommets, mais pourquoi si nous avons un ombrage à Fong? Dans l'ombrage Phong, la couleur n'est pas interpolée entre les sommets (comme dans les Listing 1 et 2), nous interpolons entre les sommets de la normale à la surface , et utilisons la normale générée pour effectuer tous les calculs d'éclairage pour chaque pixel , pas le sommet. Cependant, cela signifie que le fragment shader devra faire plus de travail, comme indiqué dans le Listing 4. Mais d'abord, regardons le vertex shader.


Listing 3: le vertex shader du Phong shader sur 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; } 

Presque rien n'a changé. Mais dans le fragment shader, la situation est complètement différente.

Listing 4: Shader 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); } 

Eh bien, c'est la fin de l'article, j'espère qu'il vous a plu. Si cela a déclenché chez vous une étincelle d'intérêt pour OpenGL, vous pouvez acheter OpenGL Superbible sur Amazon ou explorer learnopengl.com. Si vous ne pouvez pas gérer les shaders, je vous recommande Book of Shaders .

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


All Articles