diff --git a/source/10-let-there-be-light.md b/source/10-let-there-be-light.md index d259c9f..40313aa 100644 --- a/source/10-let-there-be-light.md +++ b/source/10-let-there-be-light.md @@ -26,15 +26,15 @@ Phong算法提供了三种光照分量: * **镜面反射(Specular Reflectance)**:模拟光线如何在抛光表面或金属表面上反射。 -最后,我们还要知道的规律是,乘以分配给片段的颜色,将根据接收的光线将该颜色变得更亮或更暗。我们令$A$为环境组光、$D$为漫射、$S$为高光。 以上规律对于分量的加法表示如下: +最后,我们还要知道的规律是,乘以分配给片段的颜色,将根据接收的光线将该颜色变得更亮或更暗。我们令$A$为环境组光、$D$为漫反射、$S$为高光。 以上规律对于分量的加法表示如下: $$L = A + D + S$$ 这些分量其实就是颜色,也就是每个光分量所贡献的颜色分量。 这是因为光分量不仅会提供一定程度的强度,还会改变模型的颜色。在我们的片段着色器中,我们只需将该光的颜色与原始片段颜色(从纹理或基色获得)相乘即可。 -我们也可以为相同的材质分配不同的颜色,这些颜色将用于环境,漫射和高光分量。 因此,这些分量将由材质相关的颜色而受到调整。 如果材质具有纹理,我们将简单地为每个分量使用单个纹理。 +我们也可以为相同的材质分配不同的颜色,这些颜色将用于环境,漫反射和镜像反射。 因此,这些分量将由材质相关的颜色而受到调整。 如果材质具有纹理,我们将简单地为每个分量使用单个纹理。 -所以对于非纹理材质的最终颜色将是:$L = A * 环境光色 + D * 漫射的颜色 + S * 高光颜色$ +所以对于非纹理材质的最终颜色将是:$L = A * 环境光色 + D * 漫反射的颜色 + S * 高光颜色$ 对于有纹理材质的最终颜色将是: @@ -46,11 +46,11 @@ $$L = A * 材质颜色 + D * 材质颜色 + S * 材质颜色$$ 环境光是运算最简单的分量,我们只需要传递一种颜色,并乘以基本颜色,以调整该基本颜色。 假如我们已经确定片段的颜色是$(1.0,0.0,0.0)$,即红色。 如果没有环境光时,它将显示为完全红色的片段。 如果我们将环境光设置为$(0.5,0.5,0.5)$,则最终颜色将为$(0.5,0,0)$,其实就是变暗的红色。 这种光会以同样的方式使所有片段变暗(说光照暗了物体似乎有点奇怪,实际上这就是我们得到的效果)。除此之外,如果光色的RGB分量不相同,它还可以为片段添加一些颜色,所以我们只需要一个向量来调节环境光强度和颜色。 -## 漫射 +## 漫反射 -现在我们来谈谈漫射。 它模拟了这样的规律,即与光源垂直的面看起来比以更接近光的角度接收光的面更亮。 一个物体接收的光线越多,其光密度(让我这样称呼)就越高。 +现在我们来谈谈漫反射。 它模拟了这样的规律,即与光源垂直的面看起来比以更接近光的角度接收光的面更亮。 一个物体接收的光线越多,其光密度(让我这样称呼)就越高。 -![漫射光](_static/10/diffuse_light.png) +![漫反射光](_static/10/diffuse_light.png) 但是,我们该如何计算它? 你还记得上一章我们介绍过的法线概念吗? 法线是垂直于平面并且长度为1的向量。 因此,让我们在上图中绘制三个点的法线,如你所见,每个点的法线将是垂直于每个点的切平面的向量。 我们不去绘制来自光源的光线,而是绘制从每个点到光源(即相反的方向)的向量。 @@ -68,11 +68,11 @@ $P2$点的法线$N2$,与指向光源的向量的夹角约为30度,所以它 ![点积](_static/10/dot_product.png) -如果两个向量都归一化,即它们的长度,它们的模块将等于1,它们的点积即为夹角的余弦值。 我们同样使用该运算来计算漫射分量。 +如果两个向量都归一化,即它们的长度,它们的模块将等于1,它们的点积即为夹角的余弦值。 我们同样使用该运算来计算漫反射分量。 所以我们需要计算指向光源的向量。 我们如何做到这一点? 假如我们有每个点的位置(即顶点位置),我们有光源的位置。首先,这两个坐标必须位于相同的坐标系中。 为了简化,让我们假设它们都处于世界坐标系中,那么这些位置是指向顶点位置($VP$)和光源($VS$)的矢量的坐标,如下图所示: -![漫射光照运算](_static/10/diffuse_calc_i.png) +![漫反射光照运算](_static/10/diffuse_calc_i.png) 如果我们从$VP$中减去$VS$,我们就得到了$L$向量。 @@ -88,19 +88,19 @@ $P2$点的法线$N2$,与指向光源的向量的夹角约为30度,所以它 首先,我们需要计算从当前位置指向光源的向量:$toLightDirection = lPos - vPos$。该操作的结果需要进行归一化。 -然后我们需要计算漫射因子(标量):$diffuseFactor = normal \cdot toLightDirection$。计算两个向量之间的点积,我们希望它在$-1$和$1$之间,所以两个向量都需要进行归一化。颜色需要在$0$到$1$之间,所以如果值低于$0$,我们将它设置为$0$。 +然后我们需要计算漫反射因子(标量):$diffuseFactor = normal \cdot toLightDirection$。计算两个向量之间的点积,我们希望它在$-1$和$1$之间,所以两个向量都需要进行归一化。颜色需要在$0$到$1$之间,所以如果值低于$0$,我们将它设置为$0$。 -最后,我们只需要通过漫射因子和光强来调制光色: +最后,我们只需要通过漫反射因子和光强来调制光色: $$ color = diffuseColour * lColour * diffuseFactor * intensity$$ -## 高光分量 +## 镜像反射 -现在我们来看看高光分量,但首先我们需要知道光线是如何反射的。 当光照射到一个平面时,它的一部分被吸收,另一部分被反射,如果你还记得你的物理课内容,反射就是光子从物体反弹回来。 +现在我们来看看镜像反射,但首先我们需要知道光线是如何反射的。 当光照射到一个平面时,它的一部分被吸收,另一部分被反射,如果你还记得你的物理课内容,反射就是光子从物体反弹回来。 ![反射光](_static/10/light_reflection.png) -当然,平面不是完全抛光的,如果你近距离仔细观察,你会看到很多不平整的地方。 除此之外,有许多射线光(实际上是光子),会撞击这个平面,并且会以各种各样的角度进行反射。 因此,我们看到的就像是一束光照射一平面并散射出去。 也就是说,光线在撞击平面时会发散,这就是我们之前讨论过的漫射分量。 +当然,平面不是完全抛光的,如果你近距离仔细观察,你会看到很多不平整的地方。 除此之外,有许多射线光(实际上是光子),会撞击这个平面,并且会以各种各样的角度进行反射。 因此,我们看到的就像是一束光照射一平面并散射出去。 也就是说,光线在撞击平面时会发散,这就是我们之前讨论过的漫反射分量。 ![平面](_static/10/surface.png) @@ -108,11 +108,11 @@ $$ color = diffuseColour * lColour * diffuseFactor * intensity$$ ![抛光平面](_static/10/polished_surface.png) -这就是高光分量模型,它取决于材质特性。关于镜面反射,要注意的一点是,只有当摄像机处于适当的位置时,即反射光的发射区域内,反射光才可见。 +这就是镜像反射模型,它取决于材质特性。关于镜面反射,要注意的一点是,只有当摄像机处于适当的位置时,即反射光的发射区域内,反射光才可见。 ![高光](_static/10/specular_lightining.png) -解释了反射的机制,我们接下来准备计算这个分量。首先,我们需要一个从光源指向顶点的向量。当我们计算漫射分量时,我们使用的是方向与之相反的向量,它指向的是光源。 $toLightDirection$,所以让我们将其计算为$fromLightDirection = -(toLightDirection)$。 +解释了反射的机制,我们接下来准备计算这个分量。首先,我们需要一个从光源指向顶点的向量。当我们计算漫反射分量时,我们使用的是方向与之相反的向量,它指向的是光源。 $toLightDirection$,所以让我们将其计算为$fromLightDirection = -(toLightDirection)$。 然后我们需要计算正常情况下由$fromLightDirection$到平面所产生的反射光。有一个名为reflect的GLSL函数。所以,$reflectLight = reflect(fromLightSource, normal)$。 @@ -209,8 +209,8 @@ struct Material 材质由一组颜色定义(假如我们不使用纹理为片段着色): * 用于环境分量的颜色。 -* 用于漫射分量的颜色。 -* 用于高光分量的颜色。 +* 用于漫反射分量的颜色。 +* 用于镜像反射的颜色。 材质也由一个标志来定义,该标志控制它是否具有相关的纹理以及反射率指数。我们将在片段着色器中使用以下uniform。 @@ -231,7 +231,7 @@ uniform vec3 camera_pos; * 材质特性。 * 相机在视图空间坐标系中的位置。 -我们还将定义一些全局变量,它们将保存要在环境、漫射和高光分量中使用的材质颜色分量。我们使用这些变量是因为如果分量具有纹理,我们将对所有分量使用相同的颜色,并且我们不希望进行冗余的纹理查找。这些变量是这样定义的: +我们还将定义一些全局变量,它们将保存要在环境、漫反射和镜像反射中使用的材质颜色分量。我们使用这些变量是因为如果分量具有纹理,我们将对所有分量使用相同的颜色,并且我们不希望进行冗余的纹理查找。这些变量是这样定义的: ```glsl vec4 ambientC; @@ -259,7 +259,7 @@ void setupColours(Material material, vec2 textCoord) } ``` -现在我们要定义一个函数,以点光源、顶点位置及其法线为输入并返回前面描述的漫射和高光分量计算的颜色。 +现在我们要定义一个函数,以点光源、顶点位置及其法线为输入并返回前面描述的漫反射和镜像反射计算的颜色。 ```glsl vec4 calcPointLight(PointLight light, vec3 position, vec3 normal) @@ -267,7 +267,7 @@ vec4 calcPointLight(PointLight light, vec3 position, vec3 normal) vec4 diffuseColour = vec4(0, 0, 0, 0); vec4 specColour = vec4(0, 0, 0, 0); - // 漫射 + // 漫反射 vec3 light_direction = light.position - position; vec3 to_light_source = normalize(light_direction); float diffuseFactor = max(dot(normal, to_light_source ), 0.0); @@ -289,9 +289,9 @@ vec4 calcPointLight(PointLight light, vec3 position, vec3 normal) } ``` -前面的代码相对比较直白简单,它只是计算了漫射分量的颜色,另一个是计算高光分量的颜色,并通过光线在行进到我们正在处理的顶点时受到的衰减来调制它们。 +前面的代码相对比较直白简单,它只是计算了漫反射分量的颜色,另一个是计算镜像反射的颜色,并通过光线在行进到我们正在处理的顶点时受到的衰减来调制它们。 -请注意,顶点坐标是位于视图空间中的。在计算高光分量时,我们必须指出视角,即相机。这可以这样做: +请注意,顶点坐标是位于视图空间中的。在计算镜像反射时,我们必须指出视角,即相机。这可以这样做: ```glsl vec3 camera_direction = normalize(camera_pos - position); @@ -322,9 +322,9 @@ void main() } ``` -调用setupColours函数将使用适当的颜色来设置变量ambientC、diffuseC和speculrC。然后,我们计算漫射和高光分量,并考虑衰减。为了方便,我们使用单个函数调用来完成此操作,如上所述。最终的颜色是通过添加环境光分量来计算的(将ambientC乘以环境光)。正如你所看到的,环境光不受衰减的影响。 +调用setupColours函数将使用适当的颜色来设置变量ambientC、diffuseC和speculrC。然后,我们计算漫反射和镜像反射,并考虑衰减。为了方便,我们使用单个函数调用来完成此操作,如上所述。最终的颜色是通过添加环境光分量来计算的(将ambientC乘以环境光)。正如你所看到的,环境光不受衰减的影响。 -在着色器中我们引入了一些需要进一步解释的新概念,定义结构体并将它们用作uniform。但我们要怎么传递这些结构体?首先,我们将定义两个新类,它们模拟点点光源和材质的特性,名为`PointLight`和`Material`。它们只是普通的POJO,所以你可以在本书附带的源代码中查看它们。然后,我们需要在ShaderProgram类中创建新方法,首先要能够为点光源和材质结构创建uniform。 +在着色器中我们引入了一些需要进一步解释的新概念,定义结构体并将它们用作uniform。但我们要怎么传递这些结构体?首先,我们将定义两个新类,它们模拟点点光源和材质的特性,名为`PointLight`和`Material`。它们只是普通的POJO(普通的Java对象),所以你可以在本书附带的源代码中查看它们。然后,我们需要在ShaderProgram类中创建新方法,首先要能够为点光源和材质结构创建uniform。 ```java public void createPointLightUniform(String uniformName) throws Exception {