mirror of
https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git
synced 2025-08-23 04:35:28 +08:00
校对02/03 修改前后文的“像素着色器”为“片段着色器”
This commit is contained in:
@@ -83,7 +83,7 @@ glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
//设置灯立方体的顶点属性指针(仅设置灯的顶点数据)
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindVertexArray(0);
|
||||
glBindVertexArray(0);
|
||||
```
|
||||
|
||||
这段代码对你来说应该是相对简单的。现在我们创建了表示灯和被照物体的立方体,最后需要做的事就是定义片段着色器:
|
||||
@@ -91,7 +91,7 @@ glBindVertexArray(0);
|
||||
```c++
|
||||
#version 330 core
|
||||
out vec4 color;
|
||||
|
||||
|
||||
uniform vec3 objectColor;
|
||||
uniform vec3 lightColor;
|
||||
|
||||
@@ -122,7 +122,7 @@ void main()
|
||||
color = vec4(1.0f); //设置四维向量的所有元素为 1.0f
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
当我们想绘制容器(或者其他对象)时,使用前面定义的光照着色器;当我们要绘制灯对象时,使用这个特制的着色器。在接下来的教程中我们将逐步修改这个着色器,让它慢慢地展示出更真实的效果。
|
||||
|
||||
使用这个灯立方体的主要目的是为了让我们知道光源在场景中的具体位置。我们通常在场景中定义一个光源的位置,但这只是一个位置,没有视觉意义。我们将表示光源的灯立方体放在光源的位置只是为了表示光源的具体位置,请使用我们为它新建的片段着色器让它保持它一直处于白色状态,不受场景中的光照影响。
|
||||
@@ -149,7 +149,7 @@ lampShader.Use();
|
||||
...
|
||||
// 绘制灯立方体对象
|
||||
glBindVertexArray(lightVAO);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||
glBindVertexArray(0);
|
||||
```
|
||||
|
||||
@@ -161,4 +161,4 @@ glBindVertexArray(0);
|
||||
|
||||
如果你在把上述代码片段放到一起编译遇到困难,可以去认真地看看我的[源代码](http://learnopengl.com/code_viewer.php?code=lighting/colors_scene)。你好最自己实现一遍这些操作。
|
||||
|
||||
现在我们有了一些关于颜色的知识,并且创建了一个基本的场景能够绘制一些性感的光线。你现在可以阅读[下一个教程](http://learnopengl-cn.readthedocs.org/zh/latest/02%20Lighting/02%20Basic%20Lighting/),真正的魔法即将开始!
|
||||
现在我们有了一些关于颜色的知识,并且创建了一个基本的场景能够绘制一些性感的光线。你现在可以阅读[下一个教程](http://learnopengl-cn.readthedocs.org/zh/latest/02%20Lighting/02%20Basic%20Lighting/),真正的魔法即将开始!
|
||||
|
@@ -49,7 +49,7 @@ void main()
|
||||
你可能记得在[变换教程](http://learnopengl-cn.readthedocs.org/zh/latest/01%20Getting%20started/07%20Transformations/)里,我们知道两个单位向量的角度越小,它们点乘的结果越倾向于1。当两个向量的角度是90度的时候,点乘会变为0。这同样适用于θ,θ越大,光对片段颜色的影响越小。
|
||||
|
||||
!!! Important
|
||||
|
||||
|
||||
注意,我们使用的是单位向量(长度是1的向量)取得两个向量夹角的余弦值,所以我们需要确保所有的向量都被标准化,另一方面,点乘返回的不仅是余弦(查看[变换](http://learnopengl-cn.readthedocs.org/zh/latest/01%20Getting%20started/07%20Transformations/))。
|
||||
|
||||
点乘返回一个标量,我们用它计算光线对片段颜色的影响力,基于不同片段所朝向光源的方向的不同,这些片段被照亮的情况也不同。
|
||||
@@ -82,10 +82,10 @@ glEnableVertexAttribArray(0);
|
||||
我们只想使用每个顶点的前三个浮点数,忽略后三个浮点数,所以我们只需要把步长参数改成GLfloat尺寸的6倍。
|
||||
|
||||
!!! Important
|
||||
|
||||
|
||||
发光物着色器顶点数据的不完全使用看起来有点低效,但是这些顶点数据已经从立方体对象载入到GPU的内存里了,所以GPU内存不是必须再储存新数据。相对于重新给发光物分配VBO,实际上却是更高效了。
|
||||
|
||||
所有光照的计算需要在片段着色器里进行,所以我们需要把法线向量由顶点着色器传递到像素着色器。我们这么做:
|
||||
所有光照的计算需要在片段着色器里进行,所以我们需要把法线向量由顶点着色器传递到片段着色器。我们这么做:
|
||||
|
||||
```c++
|
||||
out vec3 Normal;
|
||||
@@ -104,7 +104,7 @@ in vec3 Normal;
|
||||
|
||||
### 计算环境光照
|
||||
|
||||
每个顶点现在都有了法线向量,但是我们仍然需要光的位置向量和片段的位置向量。由于光的位置是一个静态变量,我们可以简单的在像素着色器中把它声明为uniform:
|
||||
每个顶点现在都有了法线向量,但是我们仍然需要光的位置向量和片段的位置向量。由于光的位置是一个静态变量,我们可以简单的在片段着色器中把它声明为uniform:
|
||||
|
||||
```c++
|
||||
uniform vec3 lightPos;
|
||||
@@ -122,7 +122,7 @@ glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos,z);
|
||||
```c++
|
||||
out vec3 FragPos;
|
||||
out vec3 Normal;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * view * model * vec4(position, 1.0f);
|
||||
@@ -137,7 +137,7 @@ void main()
|
||||
in vec3 FragPos;
|
||||
```
|
||||
|
||||
现在,所有需要的变量都设置好了,我们可以在像素着色器中开始光照的计算了。
|
||||
现在,所有需要的变量都设置好了,我们可以在片段着色器中开始光照的计算了。
|
||||
|
||||
我们需要做的第一件事是计算光源和片段位置之间的方向向量。前面提到,光的方向向量是光的位置向量与片段的位置向量之间的向量差。你可能记得,在变换教程中,我们简单的通过两个向量相减的方式计算向量差。我们同样希望确保所有相关向量最后都转换为单位向量,所以我们把法线和方向向量这个结果都进行标准化:
|
||||
|
||||
@@ -199,7 +199,7 @@ Normal = mat3(transpose(inverse(model))) * normal;
|
||||
!!! Attention
|
||||
|
||||
对于着色器来说,逆矩阵也是一种开销比较大的操作,因此,无论何时,在着色器中只要可能就应该尽量避免逆操作,因为它们必须为你场景中的每个顶点进行这样的处理。以学习的目的这样做很好,但是对于一个对于效率有要求的应用来说,在绘制之前,你最好用CPU计算出法线矩阵,然后通过uniform把值传递给着色器(和模型矩阵一样)。
|
||||
|
||||
|
||||
## 镜面光(Specular)
|
||||
|
||||
如果你还没被这些光照计算搞得精疲力尽,我们就再把镜面高光加进来,这样冯氏光照才算完整。
|
||||
@@ -216,12 +216,12 @@ Normal = mat3(transpose(inverse(model))) * normal;
|
||||
|
||||
我们选择在世界空间(world space)进行光照计算,但是大多数人趋向于在观察空间(view space)进行光照计算。在观察空间计算的好处是,观察者的位置总是(0, 0, 0),所以这样你直接就获得了观察者位置。可是,我发现出于学习的目的,在世界空间计算光照更符合直觉。如果你仍然希望在视野空间计算光照的话,那就使用观察矩阵应用到所有相关的需要变换的向量(不要忘记,也要改变法线矩阵)。
|
||||
|
||||
为了得到观察者的世界空间坐标,我们简单地使用摄像机对象的位置坐标代替(它就是观察者)。所以我们把另一个uniform添加到像素着色器,把相应的摄像机位置坐标传给像素着色器:
|
||||
为了得到观察者的世界空间坐标,我们简单地使用摄像机对象的位置坐标代替(它就是观察者)。所以我们把另一个uniform添加到片段着色器,把相应的摄像机位置坐标传给片段着色器:
|
||||
|
||||
```c++
|
||||
uniform vec3 viewPos;
|
||||
|
||||
GLint viewPosLoc = glGetUniformLocation(lightingShader.Program, "viewPos");
|
||||
|
||||
GLint viewPosLoc = glGetUniformLocation(lightingShader.Program, "viewPos");
|
||||
glUniform3f(viewPosLoc, camera.Position.x, camera.Position.y, camera.Position.z);
|
||||
```
|
||||
|
||||
@@ -267,9 +267,9 @@ color = vec4(result, 1.0f);
|
||||
!!! Important
|
||||
|
||||
早期的光照着色器,开发者在顶点着色器中实现冯氏光照。在顶点着色器中做这件事的优势是,相比片段来说,顶点要少得多,因此会更高效,所以(开销大的)光照计算频率会更低。然而,顶点着色器中的颜色值是只是顶点的颜色值,片段的颜色值是它与周围的颜色值的插值。结果就是这种光照看起来不会非常真实,除非使用了大量顶点。
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
在顶点着色器中实现的冯氏光照模型叫做Gouraud着色,而不是冯氏着色。记住由于插值,这种光照连起来有点逊色。冯氏着色能产生更平滑的光照效果。
|
||||
|
||||
现在你可以看到着色器的强大之处了。只用很少的信息,着色器就能计算出光照,影响到为我们所有物体的片段颜色。[下一个教程](http://learnopengl-cn.readthedocs.org/zh/latest/02%20Lighting/03%20Materials/),我们会更深入的研究光照模型,看看我们还能做些什么。
|
||||
@@ -283,4 +283,3 @@ color = vec4(result, 1.0f);
|
||||
在观察空间中计算冯氏光照:[解决方案](http://learnopengl.com/code_viewer.php?code=lighting/basic_lighting-exercise2)。
|
||||
|
||||
尝试实现一个Gouraud光照来模拟冯氏光照,[解决方案](http://learnopengl.com/code_viewer.php?code=lighting/basic_lighting-exercise3)
|
||||
|
||||
|
@@ -1,28 +1,32 @@
|
||||
本文作者JoeyDeVries,由[Django](http://bullteacher.com/14-materials.html)翻译自[http://learnopengl.com](http://learnopengl.com/#!Lighting/Materials)
|
||||
|
||||
# 材质
|
||||
|
||||
在真实世界里,每个物体会对光产生不同的反作用。钢比陶瓷花瓶更闪闪发光。比如一块木头不会和钢一样对光做出相同反作用。每个物体对specular高光也有不同的反应。有些物体不会散射很多光却会反射很多光,结果看起来就有一个较小的高光点,其他物体散射的更多,就会产生一个半径更大的高光。如果我们想要在OpenGL中模拟几种类型的物体,我们必须为每个物体定义材质属性。
|
||||
原文 | [Materials](http://learnopengl.com/#!Lighting/Materials)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Django](http://bullteacher.com/)
|
||||
校对 | Geequlim
|
||||
|
||||
在前面的教程中,我们指定一个物体和一个光的颜色来定义物体的图像输出,并使之结合ambient和specular亮度元素。当描述物体的时候,我们可以为3种光照元素:ambient、diffuse、specular光照分别定义一个材质颜色。通过为每个元素指定一个颜色,我们已经对物体的颜色输出有了精密的控制。现在把一个发亮元素添加到这三个颜色里,这是我们需要的所有材质属性:
|
||||
在真实世界里,每个物体会对光产生不同的作用,钢看起来比陶瓷花瓶更闪闪发光。比如一块木头不会和钢一样对光做出相同反光,每个物体对镜面高光也有不同的反应。有些物体不会散射很多光却会反射很多光,结果看起来就有一个较小的高光点,其他物体散射的更多,就会产生一个半径更大的高光。如果我们想要在OpenGL中模拟几种类型的物体,我们必须为每个物体定义材质属性。
|
||||
|
||||
在前面的教程中,我们指定一个物体和一个光的颜色来定义物体的图像输出,并使之结合ambient和specular亮度元素。当描述物体的时候,我们可以使用3种光照元素:环境光(ambient)、散射光(diffuse)、镜面光(specular)定义一个材质颜色。通过为每个元素指定一个颜色,我们已经对物体的颜色输出有了精密的控制。现在把一个镜面高亮元素添加到这三个颜色里,这是我们需要的所有材质属性:
|
||||
|
||||
```c++
|
||||
#version 330 core
|
||||
struct Material
|
||||
{
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
float shininess;
|
||||
};
|
||||
#version 330 core
|
||||
struct Material
|
||||
{
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
float shininess;
|
||||
};
|
||||
uniform Material material;
|
||||
```
|
||||
|
||||
在像素着色器中,我们创建一个结构体,来储存物体的材质属性。我们也可以把它们储存为独立的uniform值,但是作为一个结构体来储存可以更有条理。我们首先定义结构体的布局,然后简单声明一个uniform变量,以新近创建的结构体作为它的类型。
|
||||
在片段着色器中,我们创建一个结构体,来储存物体的材质属性。我们也可以把它们储存为独立的uniform值,但是作为一个结构体来储存可以更有条理。我们首先定义结构体的布局,然后简单声明一个uniform变量,以新创建的结构体作为它的类型。
|
||||
|
||||
就像你所看到的,我们为每个Phong光照的元素都定义一个颜色向量。ambient材质向量定义了在ambient光照下这个物体反射的是什么颜色;通常这是和物体颜色相同的颜色。diffuse材质向量定义了在diffuse光照下物体的颜色。diffuse颜色被设置为(和ambient光照一样)物体要求的颜色。specular材质向量设置的是物体受到的specular光的影响的颜色(或者可能是反射一个物体特定的specular高光颜色)。最后,shininess影响specular高光的散射/半径。
|
||||
就像你所看到的,我们为每个冯氏光照模型的元素都定义一个颜色向量。`ambient`材质向量定义了在环境光照下这个物体反射的是什么颜色;通常这是和物体颜色相同的颜色。`diffuse`材质向量定义了在散射光照下物体的颜色。`diffuse`颜色被设置为(和环境光照一样)物体要求的颜色。`specular`材质向量设置的是物体受到的镜面光的影响的颜色(或者可能是反射一个物体特定的镜面高光颜色)。最后,`shininess`影响镜面高光的半径。
|
||||
|
||||
这四个元素定义了一个物体的材质,通过它们我们能够模拟很多真实世界的材质。这里有一个列表devernay.free.fr展示了几种材质属性,这些材质属性模拟外部世界的真实材质。下面的图片展示了几种真实世界材质对我们的立方体的影响:
|
||||
这四个元素定义了一个物体的材质,通过它们我们能够模拟很多真实世界的材质。这里有一个列表[devernay.free.fr](http://devernay.free.fr/cours/opengl/materials.html)展示了几种材质属性,这些材质属性模拟外部世界的真实材质。下面的图片展示了几种真实世界材质对我们的立方体的影响:
|
||||
|
||||

|
||||
|
||||
@@ -35,26 +39,26 @@ uniform Material material;
|
||||
|
||||
## 设置材质
|
||||
|
||||
我们在像素着色器中创建了一个uniform材质结构体,所以下面我们希望改变光照计算来顺应新的材质属性。由于所有材质变量都是储存在结构体中,我们可以从uniform变量material取得它们:
|
||||
我们在片段着色器中创建了一个uniform材质结构体,所以下面我们希望改变光照计算来顺应新的材质属性。由于所有材质元素都储存在结构体中,我们可以从uniform变量`material`取得它们:
|
||||
|
||||
```c++
|
||||
void main()
|
||||
{
|
||||
// Ambient
|
||||
{
|
||||
// 环境光
|
||||
vec3 ambient = lightColor * material.ambient;
|
||||
|
||||
// Diffuse
|
||||
|
||||
// 漫反射光
|
||||
vec3 norm = normalize(Normal);
|
||||
vec3 lightDir = normalize(lightPos - FragPos);
|
||||
float diff = max(dot(norm, lightDir), 0.0);
|
||||
vec3 diffuse = lightColor * (diff * material.diffuse);
|
||||
|
||||
// Specular
|
||||
|
||||
// 镜面高光
|
||||
vec3 viewDir = normalize(viewPos - FragPos);
|
||||
vec3 reflectDir = reflect(-lightDir, norm);
|
||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||
vec3 specular = lightColor * (spec * material.specular);
|
||||
|
||||
|
||||
vec3 result = ambient + diffuse + specular;
|
||||
color = vec4(result, 1.0f);
|
||||
}
|
||||
@@ -62,21 +66,21 @@ void main()
|
||||
|
||||
就像你所看到的,我么现在获得所有材质结构体的属性,无论在哪儿我们都需要它们,这次通过材质颜色的帮助,计算结果输出的颜色。物体的每个材质属性都乘以它们对应的光照元素。
|
||||
|
||||
通过设置适当的uniform,我们可以在应用中设置物体的材质。当设置uniform时,在GLSL中的一个结构体不会被认为有什么特别之处。一个结构体值扮演uniform变量的封装体,所以如果我们希望填充这个结构体,我们就仍然必须设置单独的uniform,但是这次带有结构体名字作为前缀:
|
||||
通过设置适当的uniform,我们可以在应用中设置物体的材质。当设置uniform时,在GLSL中的一个结构体不会被认为有什么特别之处。一个结构体值扮演uniform变量的封装体,所以如果我们希望填充这个结构体,我们就仍然必须设置结构体中的各个元素的uniform值,但是这次带有结构体名字作为前缀:
|
||||
|
||||
```c++
|
||||
GLint matAmbientLoc = glGetUniformLocation(lightingShader.Program, "material.ambient");
|
||||
GLint matDiffuseLoc = glGetUniformLocation(lightingShader.Program, "material.diffuse");
|
||||
GLint matSpecularLoc = glGetUniformLocation(lightingShader.Program, "material.specular");
|
||||
GLint matShineLoc = glGetUniformLocation(lightingShader.Program, "material.shininess");
|
||||
|
||||
glUniform3f(matAmbientLoc, 1.0f, 0.5f, 0.31f);
|
||||
glUniform3f(matDiffuseLoc, 1.0f, 0.5f, 0.31f);
|
||||
glUniform3f(matSpecularLoc, 0.5f, 0.5f, 0.5f);
|
||||
GLint matAmbientLoc = glGetUniformLocation(lightingShader.Program, "material.ambient");
|
||||
GLint matDiffuseLoc = glGetUniformLocation(lightingShader.Program, "material.diffuse");
|
||||
GLint matSpecularLoc = glGetUniformLocation(lightingShader.Program, "material.specular");
|
||||
GLint matShineLoc = glGetUniformLocation(lightingShader.Program, "material.shininess");
|
||||
|
||||
glUniform3f(matAmbientLoc, 1.0f, 0.5f, 0.31f);
|
||||
glUniform3f(matDiffuseLoc, 1.0f, 0.5f, 0.31f);
|
||||
glUniform3f(matSpecularLoc, 0.5f, 0.5f, 0.5f);
|
||||
glUniform1f(matShineLoc, 32.0f);
|
||||
```
|
||||
|
||||
我们设置ambient和diffuse元素我们喜欢物体所呈现的颜色,设置物体的specular元素为中等亮度颜色;我们不希望specular元素对这个指定物体产生过于强烈的影响。我们同样保持光亮为32。我们现在可以简单的在应用中影响物体的材质。
|
||||
我们为`ambient`和`diffuse`元素设置成我们喜欢物体所呈现的颜色,设置物体的`specular`元素为中等亮度颜色;我们不希望`specular`元素对这个指定物体产生过于强烈的影响。我们同样保持光亮为32。我们现在可以简单的在应用中影响物体的材质。
|
||||
|
||||
运行程序,会得到下面这样的结果:
|
||||
|
||||
@@ -90,49 +94,49 @@ glUniform1f(matShineLoc, 32.0f);
|
||||
这个物体太亮了。物体过亮的原因是ambient、diffuse和specular颜色被从任何一个光源全力地反射。光源对ambient、diffuse和specular元素同时有着不同的亮度。前面的教程,我们通过使用一个强度值改变ambient和specular亮度的方式,解决了这个问题,但是这次为每个光照元素指定了亮度向量。如果我们想象lightColor是vec3(1.0),代码看起来像是这样:
|
||||
|
||||
```c++
|
||||
vec3 ambient = vec3(1.0f) * material.ambient;
|
||||
vec3 diffuse = vec3(1.0f) * (diff * material.diffuse);
|
||||
vec3 ambient = vec3(1.0f) * material.ambient;
|
||||
vec3 diffuse = vec3(1.0f) * (diff * material.diffuse);
|
||||
vec3 specular = vec3(1.0f) * (spec * material.specular);
|
||||
```
|
||||
|
||||
所以物体的每个材质属性返回了每个光照元素的全亮度。这些vec3(1.0)值可以各自独立的影响每个光源,这通常就是我们想要的。现在物体的ambient元素完全地影响了立方体的颜色,可视ambient元素uyinggai对最终颜色有这么大的影响,所以我们要通过设置光的ambient亮度为一个小一点的值的方式,限制ambient颜色:
|
||||
所以物体的每个材质属性返回了每个光照元素的全亮度。这些vec3(1.0)值可以各自独立的影响每个光源,这通常就是我们想要的。现在物体的`ambient`元素完全地展示了立方体的颜色,可是`ambient`元素不应该对最终颜色有这么大的影响,所以我们要通过设置光的`ambient`亮度为一个小一点的值的方式,限制ambient颜色:
|
||||
|
||||
```c++
|
||||
vec3 result = vec3(0.1f) * material.ambient;
|
||||
```
|
||||
|
||||
我们可以用同样的方式影响光源的diffuse和specular亮度。这和我们前面教程所做的极为相似;你可以说我们已经创建了一些光的属性各自独立地来影响每个光照元素。我们希望为光的属性创建一些与材质结构体相似的东西:
|
||||
我们可以用同样的方式影响光源的`diffuse`和`specular`亮度。这和我们前面教程所做的极为相似;你可以说我们已经创建了一些光的属性各自独立地来影响每个光照元素。我们希望为光的属性创建一些与材质结构体相似的东西:
|
||||
|
||||
```c++
|
||||
struct Light
|
||||
{
|
||||
vec3 position;
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
struct Light
|
||||
{
|
||||
vec3 position;
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
};
|
||||
uniform Light light;
|
||||
```
|
||||
|
||||
一个光源的ambient、diffuse和specular光都有不同的亮度。ambient光通常设置为一个比较低的亮度,因为饿哦们不希望ambient颜色成为主导。光源的diffuse元素通常设置为我们希望光所具有的颜色;经常是一个明亮的白色。specular元素通常设置为vec3(1.0f)的全亮度的发光度。要记住的是我们同样把光的位置添加到结构体中。
|
||||
一个光源的`ambient`、`diffuse`和`specular`光都有不同的亮度。`ambient`光通常设置为一个比较低的亮度,因为我们不希望`ambient`颜色成为主导。光源的`diffuse`元素通常设置为我们希望光所具有的颜色;经常是一个明亮的白色。`specular`元素通常设置为`vec3(1.0f)`的全亮度的发光度。要记住的是我们同样把光的位置添加到结构体中。
|
||||
|
||||
就像材质uniform一样,我么你需要更新像素着色器:
|
||||
就像材质uniform一样,需要更新片段着色器:
|
||||
|
||||
```c++
|
||||
vec3 ambient = light.ambient * material.ambient;
|
||||
vec3 diffuse = light.diffuse * (diff * material.diffuse);
|
||||
vec3 ambient = light.ambient * material.ambient;
|
||||
vec3 diffuse = light.diffuse * (diff * material.diffuse);
|
||||
vec3 specular = light.specular * (spec * material.specular);
|
||||
```
|
||||
|
||||
然后我们要在应用里设置光的亮度:
|
||||
|
||||
```c++
|
||||
GLint lightAmbientLoc = glGetUniformLocation(lightingShader.Program, "light.ambient");
|
||||
GLint lightDiffuseLoc = glGetUniformLocation(lightingShader.Program, "light.diffuse");
|
||||
GLint lightSpecularLoc = glGetUniformLocation(lightingShader.Program, "light.specular");
|
||||
|
||||
glUniform3f(lightAmbientLoc, 0.2f, 0.2f, 0.2f);
|
||||
glUniform3f(lightDiffuseLoc, 0.5f, 0.5f, 0.5f); // Let's darken the light a bit to fit the scene
|
||||
GLint lightAmbientLoc = glGetUniformLocation(lightingShader.Program, "light.ambient");
|
||||
GLint lightDiffuseLoc = glGetUniformLocation(lightingShader.Program, "light.diffuse");
|
||||
GLint lightSpecularLoc = glGetUniformLocation(lightingShader.Program, "light.specular");
|
||||
|
||||
glUniform3f(lightAmbientLoc, 0.2f, 0.2f, 0.2f);
|
||||
glUniform3f(lightDiffuseLoc, 0.5f, 0.5f, 0.5f);
|
||||
glUniform3f(lightSpecularLoc, 1.0f, 1.0f, 1.0f);
|
||||
```
|
||||
|
||||
@@ -142,29 +146,33 @@ glUniform3f(lightSpecularLoc, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
现在改变物体的外观相对简单了些。我们做点更有趣的事!
|
||||
|
||||
|
||||
|
||||
## 不同的光的颜色
|
||||
## 不同的光源颜色
|
||||
|
||||
目前为止,我们只是使用光的颜色去改变它们的独立元素,选择的是从白到灰到黑范围的颜色,不是动感的物体的真实颜色(只是亮度)。由于我们现在简单的取得了光的属性,我们可以随着时间改变它们的颜色,获得的效果有很意思。由于没见识都已经在像素着色器做好了,改变光的颜色很简单,可以立即创建出一些有趣的效果:
|
||||
目前为止,我们只是使用光的颜色去改变它们的独立元素,选择的是从白到灰到黑范围的颜色,不是动感的物体的真实颜色(只是亮度)。由于我们现在简单的取得了光的属性,我们可以随着时间改变它们的颜色,获得的效果有很意思。由于每件事都已经在片段着色器做好了,改变光的颜色很简单,可以立即创建出一些有趣的效果:
|
||||
|
||||
<video src="http://www.learnopengl.com/video/lighting/materials.mp4" controls="controls">
|
||||
</video>
|
||||
|
||||
就像你所看见的,不同的光的颜色极大地影响了物体的颜色输出。由于光的颜色直接影响物体反射的颜色(你可能想起颜色教程),它对视觉输出有显著的影响。
|
||||
就像你所看见的,不同的光的颜色极大地影响了物体的颜色输出。由于光的颜色直接影响物体反射的颜色(你可能想起在颜色教程中有讨论过),它对视觉输出有显著的影响。
|
||||
|
||||
利用sin和glfwGetTime,改变光的ambient和diffuse颜色,我们可以随着时间流逝简单的改变光的颜色:
|
||||
利用`sin`和`glfwGetTime`,改变光的`ambient`和`diffus`e颜色,我们可以随着时间流逝简单的改变光源颜色:
|
||||
|
||||
```c++
|
||||
glm::vec3 lightColor; lightColor.x = sin(glfwGetTime() * 2.0f);
|
||||
lightColor.y = sin(glfwGetTime() * 0.7f);
|
||||
lightColor.z = sin(glfwGetTime() * 1.3f);
|
||||
|
||||
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // Decrease the influence
|
||||
glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // Low influence
|
||||
|
||||
glUniform3f(lightAmbientLoc, ambientColor.x, ambientColor.y, ambientColor.z);
|
||||
glm::vec3 lightColor; lightColor.x = sin(glfwGetTime() * 2.0f);
|
||||
lightColor.y = sin(glfwGetTime() * 0.7f);
|
||||
lightColor.z = sin(glfwGetTime() * 1.3f);
|
||||
|
||||
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f);
|
||||
glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f);
|
||||
|
||||
glUniform3f(lightAmbientLoc, ambientColor.x, ambientColor.y, ambientColor.z);
|
||||
glUniform3f(lightDiffuseLoc, diffuseColor.x, diffuseColor.y, diffuseColor.z);
|
||||
```
|
||||
|
||||
尝试和实验使用这些光照和材质值,看看它们怎样影响图像输出的。你可以从这里找到应用,和像素着色器的源码。
|
||||
尝试和实验使用这些光照和材质值,看看它们怎样影响图像输出的。你可以从这里找到[应用的源代码](http://learnopengl.com/code_viewer.php?code=lighting/materials),[片段着色器](http://learnopengl.com/code_viewer.php?code=lighting/materials&type=fragment)的源码。
|
||||
|
||||
## 练习
|
||||
|
||||
你能像我们教程一开始那样根据一些材质的属性来模拟一个真实世界的物体吗?
|
||||
注意[材质表](http://devernay.free.fr/cours/opengl/materials.html)中的环境光颜色与漫反射光的颜色可能不一样,因为他们并没有把光照强度考虑进去来模拟,你需要将光照颜色的强度改为vec(1.0f)来输出正确的结果:[解决方案,一个蓝绿色的塑料盒子](http://learnopengl.com/code_viewer.php?code=lighting/materials-exercise1)
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
所以,前面的材质系统对于除了最简单的模型以外都是不够的,所以我们需要扩展前面的系统,我们要介绍diffuse和specular贴图。它们允许你对一个物体的diffuse(对于简洁的ambient成分来说,它们几乎总是是一样的)和specular成分能够有更精确的影响。
|
||||
|
||||
|
||||
|
||||
|
||||
## 漫反射贴图
|
||||
|
||||
@@ -25,17 +25,17 @@
|
||||
要记住的是sampler2D也叫做模糊类型,这意味着我们不能以某种类型对它实例化,只能用uniform定义它们。如果我们用结构体而不是uniform实例化(就像函数的参数那样),GLSL会抛出奇怪的错误;这同样也适用于其他模糊类型。
|
||||
我们也要移除amibient材质颜色向量,因为ambient颜色绝大多数情况等于diffuse颜色,所以不需要分别去储存它:
|
||||
```c++
|
||||
struct Material
|
||||
{
|
||||
sampler2D diffuse;
|
||||
vec3 specular;
|
||||
float shininess;
|
||||
};
|
||||
...
|
||||
struct Material
|
||||
{
|
||||
sampler2D diffuse;
|
||||
vec3 specular;
|
||||
float shininess;
|
||||
};
|
||||
...
|
||||
in vec2 TexCoords;
|
||||
```
|
||||
如果你非把ambient颜色设置为不同的值不可(不同于diffuse值),你可以继续保持ambient的vec3,但是整个物体的ambient颜色会继续保持不变。为了使每个原始像素得到不同ambient值,你需要对ambient值单独使用另一个纹理。
|
||||
注意,在像素着色器中我们将会再次需要纹理坐标,所以我们声明一个额外输入变量。然后我们简单地从纹理采样,来获得原始像素的diffuse颜色值:
|
||||
注意,在片段着色器中我们将会再次需要纹理坐标,所以我们声明一个额外输入变量。然后我们简单地从纹理采样,来获得原始像素的diffuse颜色值:
|
||||
```c++
|
||||
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
|
||||
```
|
||||
@@ -43,28 +43,28 @@ vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords))
|
||||
```c++
|
||||
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
|
||||
```
|
||||
这就是diffuse贴图的全部内容了。就像你看到的,这不是什么新的东西,但是它却极大提升了视觉品质。为了让它工作,我们需要用到纹理坐标更新顶点数据,把它们作为顶点属性传递到像素着色器,把纹理加载,把纹理绑定到合适的纹理单元。
|
||||
这就是diffuse贴图的全部内容了。就像你看到的,这不是什么新的东西,但是它却极大提升了视觉品质。为了让它工作,我们需要用到纹理坐标更新顶点数据,把它们作为顶点属性传递到片段着色器,把纹理加载,把纹理绑定到合适的纹理单元。
|
||||
|
||||
更新的顶点数据可以从这里找到。顶点数据现在包括了顶点位置,法线向量和纹理坐标,每个立方体的顶点都有这些属性。让我们更新顶点着色器来接受纹理坐标作为顶点属性,然后发送到像素着色器:
|
||||
更新的顶点数据可以从这里找到。顶点数据现在包括了顶点位置,法线向量和纹理坐标,每个立方体的顶点都有这些属性。让我们更新顶点着色器来接受纹理坐标作为顶点属性,然后发送到片段着色器:
|
||||
```c++
|
||||
#version 330 core
|
||||
layout (location = 0) in vec3 position;
|
||||
layout (location = 1) in vec3 normal;
|
||||
layout (location = 2) in vec2 texCoords;
|
||||
...
|
||||
#version 330 core
|
||||
layout (location = 0) in vec3 position;
|
||||
layout (location = 1) in vec3 normal;
|
||||
layout (location = 2) in vec2 texCoords;
|
||||
...
|
||||
out vec2 TexCoords;
|
||||
|
||||
void main()
|
||||
{
|
||||
...
|
||||
TexCoords = texCoords;
|
||||
|
||||
void main()
|
||||
{
|
||||
...
|
||||
TexCoords = texCoords;
|
||||
}
|
||||
```
|
||||
要保证更新的顶点属性指针,不仅是VAO匹配新的顶点数据,也要把箱子图片加载为纹理。在绘制箱子之前,我们希望首选纹理单元被赋为material.diffuse这个uniform采样器,并绑定箱子的纹理到这个纹理单元:
|
||||
```c++
|
||||
glUniform1i(glGetUniformLocation(lightingShader.Program, "material.diffuse"), 0);
|
||||
...
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
...
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, diffuseMap);
|
||||
```
|
||||
现在,使用一个diffuse贴图,我们在细节上再次获得惊人的提升,这次添加到箱子上的光照开始闪光了(名符其实)。你的箱子现在可能看起来像这样:
|
||||
@@ -73,7 +73,7 @@ glBindTexture(GL_TEXTURE_2D, diffuseMap);
|
||||
|
||||
你可以在这里得到应用的全部代码。
|
||||
|
||||
|
||||
|
||||
|
||||
## 镜面贴图
|
||||
|
||||
@@ -83,38 +83,38 @@ glBindTexture(GL_TEXTURE_2D, diffuseMap);
|
||||
|
||||

|
||||
|
||||
一个specular高光的亮度可以通过图片中每个纹理的亮度来获得。specular贴图的每个像素可以显示为一个颜色向量,比如:在那里黑色代表颜色向量vec3(0.0f),灰色是vec3(0.5f)。在像素着色器中,我们采样相应的颜色值,把它乘以光的specular亮度。像素越“白”,乘积的结果越大,物体的specualr部分越亮。
|
||||
一个specular高光的亮度可以通过图片中每个纹理的亮度来获得。specular贴图的每个像素可以显示为一个颜色向量,比如:在那里黑色代表颜色向量vec3(0.0f),灰色是vec3(0.5f)。在片段着色器中,我们采样相应的颜色值,把它乘以光的specular亮度。像素越“白”,乘积的结果越大,物体的specualr部分越亮。
|
||||
|
||||
由于箱子几乎是由木头组成,木头作为一个材质不会有镜面高光,整个不透部分的diffuse纹理被用黑色覆盖:黑色部分不会包含任何specular高光。箱子的铁边有一个修改的specular亮度,它自身更容易受到镜面高光影响,木纹部分则不会。
|
||||
|
||||
从技术上来讲,木头也有镜面高光,尽管这个闪亮值很小(更多的光被散射),影响很小,但是为了学习目的,我们可以假装木头不会有任何specular光反射。
|
||||
使用Photoshop或Gimp之类的工具,剪切一些部分,非常容易变换一个diffuse纹理,为specular图片,以增加亮度/对比度的方式,可以把这个部分变换为黑色或白色。
|
||||
|
||||
|
||||
|
||||
|
||||
###15.2.1 specular贴图采样
|
||||
|
||||
一个specular贴图和其他纹理一样,所以代码和diffuse贴图的代码也相似。确保合理的加载了图片,生成一个纹理对象。由于我们在同样的像素着色器中使用另一个纹理采样器,我们必须为specular贴图使用一个不同的纹理单元(查看纹理),所以在渲染前让我们把它绑定到合适的纹理单元
|
||||
一个specular贴图和其他纹理一样,所以代码和diffuse贴图的代码也相似。确保合理的加载了图片,生成一个纹理对象。由于我们在同样的片段着色器中使用另一个纹理采样器,我们必须为specular贴图使用一个不同的纹理单元(查看纹理),所以在渲染前让我们把它绑定到合适的纹理单元
|
||||
```c++
|
||||
glUniform1i(glGetUniformLocation(lightingShader.Program, "material.specular"), 1);
|
||||
...
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glUniform1i(glGetUniformLocation(lightingShader.Program, "material.specular"), 1);
|
||||
...
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, specularMap);
|
||||
```
|
||||
然后更新像素着色器材质属性,接受一个sampler2D作为这个specular部分的类型,而不是vec3:
|
||||
然后更新片段着色器材质属性,接受一个sampler2D作为这个specular部分的类型,而不是vec3:
|
||||
```c++
|
||||
struct Material
|
||||
{
|
||||
sampler2D diffuse;
|
||||
sampler2D specular;
|
||||
float shininess;
|
||||
struct Material
|
||||
{
|
||||
sampler2D diffuse;
|
||||
sampler2D specular;
|
||||
float shininess;
|
||||
};
|
||||
```
|
||||
最后我们希望采样这个specular贴图,来获取原始像素相应的specular亮度:
|
||||
```c++
|
||||
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
|
||||
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
|
||||
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
|
||||
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
|
||||
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
|
||||
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
|
||||
color = vec4(ambient + diffuse + specular, 1.0f);
|
||||
```
|
||||
通过使用一个specular贴图我们可以定义极为精细的细节,物体的这个部分会获得闪亮的属性,我们可以设置它们相应的亮度。specular贴图给我们一个附加的高于diffuse贴图的控制权限。
|
||||
@@ -124,6 +124,6 @@ color = vec4(ambient + diffuse + specular, 1.0f);
|
||||
|
||||

|
||||
|
||||
你可以在这里找到全部源码。也对比一下你的顶点着色器和像素着色器。
|
||||
你可以在这里找到全部源码。也对比一下你的顶点着色器和片段着色器。
|
||||
|
||||
使用diffuse和specular贴图,我们可以给相关但简单物体添加一个极为明显的细节。我们可以使用其他纹理贴图,比如法线/bump贴图或者反射贴图,给物体添加更多的细节。但是这些在后面教程才会涉及。把你的箱子给你所有的朋友和家人看,有一天你会很满足,我们的箱子会比现在更漂亮!
|
||||
使用diffuse和specular贴图,我们可以给相关但简单物体添加一个极为明显的细节。我们可以使用其他纹理贴图,比如法线/bump贴图或者反射贴图,给物体添加更多的细节。但是这些在后面教程才会涉及。把你的箱子给你所有的朋友和家人看,有一天你会很满足,我们的箱子会比现在更漂亮!
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
我们首先讨论定向光(directional light),接着是作为之前学到知识的扩展的点光(point light),最后我们讨论聚光灯(spot light)。下面的教程我们会把这几种不同的光类型整合到一个场景中。
|
||||
|
||||
|
||||
|
||||
|
||||
## 定向光
|
||||
|
||||
@@ -63,7 +63,7 @@ glUniform3f(lightDirPos, -0.2f, -1.0f, -0.3f);
|
||||
```c++
|
||||
if(lightVector.w == 0.0) // Note: be careful for floating point errors
|
||||
// Do directional light calculations
|
||||
|
||||
|
||||
else if(lightVector.w == 1.0)
|
||||
// Do light calculations using the light’s position (like last tutorial)
|
||||
```
|
||||
@@ -72,9 +72,9 @@ else if(lightVector.w == 1.0)
|
||||
|
||||

|
||||
|
||||
你可以在这里获得应用的所有代码,这里是顶点和像素着色器代码。
|
||||
你可以在这里获得应用的所有代码,这里是顶点和片段着色器代码。
|
||||
|
||||
|
||||
|
||||
|
||||
##16.2 点光
|
||||
|
||||
@@ -86,7 +86,7 @@ else if(lightVector.w == 1.0)
|
||||
|
||||
如果你把10个箱子添加到之前教程的光照场景中,你会注意到黑暗中的每个箱子都会有同样的亮度,就像箱子在光照的前面;没有公式定义光的距离衰减。我们想让黑暗中与光源比较近的箱子被轻微地照亮。
|
||||
|
||||
|
||||
|
||||
|
||||
##16.3 衰减
|
||||
|
||||
@@ -107,7 +107,7 @@ else if(lightVector.w == 1.0)
|
||||
|
||||
你可以看到当距离很近的时候光有最强的亮度,但是随着距离增大,亮度明显减弱,大约接近100的时候,就会慢下来。这就是我们想要的。
|
||||
|
||||
|
||||
|
||||
|
||||
###16.3.1 选择正确的值
|
||||
|
||||
@@ -152,7 +152,7 @@ glUniform1f(glGetUniformLocation(lightingShader.Program, "light.linear"), 0.09);
|
||||
glUniform1f(glGetUniformLocation(lightingShader.Program, "light.quadratic"), 0.032);
|
||||
|
||||
```
|
||||
在像素着色器中实现衰减很直接:我们根据公式简单的计算衰减值,在乘以ambient、diffuse和specular元素。
|
||||
在片段着色器中实现衰减很直接:我们根据公式简单的计算衰减值,在乘以ambient、diffuse和specular元素。
|
||||
|
||||
我们需要光源的距离提供给公式;记得我们能够计算向量的长度吗?我们可以通过获取片段和光源之间的不同向量把向量的长度结果作为距离项。我们可以使用GLSL的内建length函数做这件事:
|
||||
```c++
|
||||
@@ -175,7 +175,7 @@ light_casters_point_light
|
||||
|
||||
电光就是一个可配的置位置和衰减值应用到光照计算中。还有另一种类型光可用于我们照明库当中。
|
||||
|
||||
|
||||
|
||||
|
||||
##16.4 聚光灯
|
||||
|
||||
@@ -185,20 +185,20 @@ OpenGL中的聚光灯用世界空间位置,一个方向和一个指定了聚
|
||||
|
||||

|
||||
|
||||
* LightDir:从片段指向光源的向量。
|
||||
* LightDir:从片段指向光源的向量。
|
||||
* SpotDir:聚光灯所指向的方向。
|
||||
* Phiφ:定义聚光灯半径的切光角。每个落在这个角度之外的,聚光灯都不会照亮。
|
||||
* Thetaθ:LightDir向量和SpotDir向量之间的角度。θ值应该比φ值小,这样才会在聚光灯内。
|
||||
|
||||
所以我们大致要做的是,计算LightDir向量和SpotDir向量的点乘(返回两个单位向量的点乘,还记得吗?),然后在和遮光角φ对比。现在你应该明白聚光灯是我们下面将创建的手电筒的范例。
|
||||
|
||||
|
||||
|
||||
|
||||
##16.5 手电筒
|
||||
|
||||
手电筒是一个坐落在观察者位置的聚光灯,通常瞄准玩家透视图的前面。基本上说,一个手电筒是一个普通的聚光灯,但是根据玩家的位置和方向持续的更新它的位置和方向。
|
||||
|
||||
所以我们需要为像素着色器提供的值,是聚光灯的位置向量(来计算光的方向坐标),聚光灯的方向向量和遮光角。我们可以把这些值储存在Light结构体中:
|
||||
所以我们需要为片段着色器提供的值,是聚光灯的位置向量(来计算光的方向坐标),聚光灯的方向向量和遮光角。我们可以把这些值储存在Light结构体中:
|
||||
```c++
|
||||
struct Light
|
||||
{
|
||||
@@ -214,7 +214,7 @@ glUniform3f(lightPosLoc, camera.Position.x, camera.Position.y, camera.Position.z
|
||||
glUniform3f(lightSpotdirLoc, camera.Front.x, camera.Front.y, camera.Front.z);
|
||||
glUniform1f(lightSpotCutOffLoc, glm::cos(glm::radians(12.5f)));
|
||||
```
|
||||
你可以看到,我们为遮光角设置一个角度,但是我们根据一个角度计算了余弦值,把这个余弦结果传给了像素着色器。这么做的原因是在像素着色器中,我们计算LightDir和SpotDir向量的点乘,而点乘返回一个余弦值,不是一个角度,所以我们不能直接把一个角度和余弦值对比。为了获得这个角度,我们必须计算点乘结果的反余弦,这个操作开销是很大的。所以为了节约一些性能,我们先计算给定切光角的余弦值,然后把结果传递给像素着色器。由于每个角度都被表示为余弦了,我们可以直接对比它们,而不用进行任何开销高昂的操作。
|
||||
你可以看到,我们为遮光角设置一个角度,但是我们根据一个角度计算了余弦值,把这个余弦结果传给了片段着色器。这么做的原因是在片段着色器中,我们计算LightDir和SpotDir向量的点乘,而点乘返回一个余弦值,不是一个角度,所以我们不能直接把一个角度和余弦值对比。为了获得这个角度,我们必须计算点乘结果的反余弦,这个操作开销是很大的。所以为了节约一些性能,我们先计算给定切光角的余弦值,然后把结果传递给片段着色器。由于每个角度都被表示为余弦了,我们可以直接对比它们,而不用进行任何开销高昂的操作。
|
||||
|
||||
现在剩下要做的是计算θ值,用它和φ值对比,以决定我们是否在或不在聚光灯的内部:
|
||||
```c++
|
||||
@@ -237,11 +237,11 @@ color = vec4(light.ambient*vec3(texture(material.diffuse,TexCoords)), 1.0f);
|
||||
|
||||
`[](http://www.learnopengl.com/img/lighting/light_casters_spotlight_hard.png)
|
||||
|
||||
你可以在这里获得全部源码和像素着色器的源码。
|
||||
你可以在这里获得全部源码和片段着色器的源码。
|
||||
|
||||
它看起来仍然有点假,大部分原因是聚光灯有了一个硬边。片段着色器一旦到达了聚光灯的圆锥边缘,它就立刻黑了下来,却没有任何平滑减弱的过度。一个真实的聚光灯的光会在它的边界处平滑减弱的。
|
||||
|
||||
它看起来仍然有点假,大部分原因是聚光灯有了一个硬边。像素着色器一旦到达了聚光灯的圆锥边缘,它就立刻黑了下来,却没有任何平滑减弱的过度。一个真实的聚光灯的光会在它的边界处平滑减弱的。
|
||||
|
||||
|
||||
|
||||
##16.6 平滑/软化边缘
|
||||
|
||||
@@ -267,7 +267,7 @@ color = vec4(light.ambient*vec3(texture(material.diffuse,TexCoords)), 1.0f);
|
||||
0.966|15|0.9978|12.5|0.953|17.5|0.966 - 0.953 = 0.0448|0.966 - 0.953 / 0.0448 = 0.29
|
||||
就像你看到的那样我们基本是根据θ在外余弦和内余弦之间插值。如果你仍然不明白怎么继续,不要担心。你可以简单的使用这个公式计算,当你更加老道和明白的时候再来看。
|
||||
|
||||
由于我们现在有了一个亮度值,当在聚光灯外的时候是个负的,当在内部圆锥以内大于1。如果我们适当地把这个值固定,我们在像素着色器中就再不需要if-else了,我们可以简单地用计算出的亮度值乘以光的元素:
|
||||
由于我们现在有了一个亮度值,当在聚光灯外的时候是个负的,当在内部圆锥以内大于1。如果我们适当地把这个值固定,我们在片段着色器中就再不需要if-else了,我们可以简单地用计算出的亮度值乘以光的元素:
|
||||
```c++
|
||||
float theta = dot(lightDir, normalize(-light.direction));
|
||||
float epsilon = light.cutOff - light.outerCutOff;
|
||||
@@ -286,4 +286,4 @@ specular* = intensity;
|
||||
|
||||
看起来好多了。仔细看看内部和外部遮光角,尝试创建一个符合你求的聚光灯。可以在这里找到应用源码,以及片段的源代码。
|
||||
|
||||
这样的一个手电筒/聚光灯类型的灯光非常适合恐怖游戏,结合定向和点光,环境会真的开始被照亮了。下一个教程,我们会结合所有我们目前讨论了的光和技巧。
|
||||
这样的一个手电筒/聚光灯类型的灯光非常适合恐怖游戏,结合定向和点光,环境会真的开始被照亮了。下一个教程,我们会结合所有我们目前讨论了的光和技巧。
|
||||
|
Reference in New Issue
Block a user