关于Phong底纹的一些知识


“我们不能指望能够像纹理,阴影等那样完全真实地显示对象。 我们希望只创建足够接近的图像以达到一定程度的真实感。”

裴廷芳

Bui Thuong Fong出生于1941年,在越战期间成为计算机科学家。 在60年代的有毒环境中完成他的学业一定很困难,更不用说他被叫到前列了! 但是他设法生存并生存到1975年,直到白血病在他为现代照明和阴影理论( Fong的着色器)奠定了世界基础仅两年之后才得以生还。 越南名字由三部分组成:姓,中间名和个人名字。 也就是说,当人们说“ Fong shader”时,他们称呼个人名字Bui Tyong。 您可以在Wikipedia上阅读有关个人名称的更多信息。


我不确定是否是Phong,但Google表示可以。

“轻轻地让温暖的阳光
在我垂死的床上玩耍
昏暗的山谷
我必须用孤独的脚踩。 “

让光进入-弗朗西斯·哈珀(Francis Harper)的诗

Phong的着色器基于极其简洁的数学。 实际上,您不需要知道这些,除非您真诚地希望成为一名图形程序员。 但是,从长远来看,她的知识将是有用的。 以下摘自Graham Sellers的第七版OpenGL Superbible和Kronos Group ARB Foundation的摘录。

A)一些概念


首先,让我们弄清楚概念。 如果您一直在处理3D建模或游戏开发至少一分钟,那么您一定已经遇到过它们,但是重复并没有困扰任何人。

A-1)环境光

大多数书籍,尤其是低质量的书籍,都将这种照明与阳光进行了比较,但这是完全不正确的。 环境照明不是阳光。 它来自四面八方 ,也就是说无处不在,但是在计算中它只是一个包含三个分量的向量。 在“ Phong”的阴影中,它是最后添加的,但不会更改。

A-2)漫射/漫射光

漫射照明有方向。 这实际上是[sic]光源方向组件 。 在电影院中,光线是通过柔光箱散射的,而在计算机图形学中,光线是通过下面显示的公式散射的。 大小即散射照明的大小取决于表面。 例如,如果表面是粗糙的,即吸收的光大于反射的光,则该值将大于光滑表面的情况。


磨砂屏幕散射/吸收的环境光

A-3)镜面高光

像散射光一样,反射光是定向的,但基于表面的光泽度。 它留下了一个亮点,叫做发亮 。 在现实生活中,光泽度不是材料的组成部分。 实际上,薄膜涂料或一滴蜡会比其他任何东西都增加更多的光泽。 反射的光泽度是介于0到128之间的一个因子,因为在值大于128时,它将不会对着色器产生很大的影响。


带有胶片的胶片-厚厚的彩色纸,带有光滑的胶片涂层,是对孩子的真实礼物。

A- 4)反照率

这是表面反射的入射光的一部分。

A-5)防风配方

根据Phong计算物料的公式如下:


其中:

:环境材料

:扩散材料

:镜面材料和 :光泽度

:环境照明

:漫射照明

:间接照明

您可能会问,向量呢? 不用担心,现在我们将介绍它们:

:垂直于表面

:从阴影点到光源的单位向量(换句话说,光向量)

:反射光矢量的负值

:指向观看者的向量


B)Gouraud底纹


在开始使用Fong的着色器之前,让我们看看如何在GLSL上获得Gouro着色。 请注意,我在Superbible中使用的是GLSL 4.1版本,但如果您是www.learnopengl.com的粉丝,则可以使用3.3。 没关系 因此,让我们看看Gouraud底纹是什么。

这种着色方法是Henri Gouraud在1971年发明的。 它不会以任何方式超过Phong阴影,如今,它主要用作Cinema 4D等程序包中的无GPU加载预览方法。 他的问题是,他产生的耀斑看起来像是火花:


此问题是由顶点之间的颜色插值引起的,由于颜色是线性插值的,所以三角形之间会出现间隙。 仅在Phong着色器中解决了此问题。 让我们看看如何在GLSL 4.1上实现Gouro着色。

清单1 :GLSL 4.1上的Gourox顶点着色

#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; } 

现在是片段着色器。

清单2:相同概念片段着色器。

 #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)阴影


在继续之前,让我们记住,Phong 阴影和Phong 照明是两个不同的概念。 您可以通过添加更多顶点来摆脱Gouro耀斑的“雪花”,但是为什么在Fong中添加阴影呢? 在Phong着色器中,颜色不会在顶点之间进行插值(如清单1和2所示),我们在曲面法线的顶点之间进行插值,并使用生成的法线为每个像素 (而不是顶点)执行所有光照计算。 但是,这意味着片段着色器将不得不做更多的工作,如清单4所示。但是首先,让我们看一下顶点着色器。


清单3: GLSL 4.1上的Phong着色器顶点着色器。

 #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; } 

几乎没有任何变化。 但是在片段着色器中,情况完全不同。

清单4: Fong片段着色器着色器。

 #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); } 

好,这是本文的结尾,希望您喜欢它。 如果它激发了您对OpenGL的兴趣,您可以在亚马逊上购买OpenGL Superbible或浏览Learnopengl.com。 如果您不能处理着色器,建议您使用Book of Shaders

Source: https://habr.com/ru/post/zh-CN441862/


All Articles