mirror of
https://github.com/mouse0w0/lwjglbook-CN-Translation.git
synced 2025-08-23 04:35:29 +08:00
Fix problems
This commit is contained in:
@@ -33,7 +33,7 @@
|
|||||||
* 首先,我们将场景从光照空间渲染为阴影图,以获得最小距离。
|
* 首先,我们将场景从光照空间渲染为阴影图,以获得最小距离。
|
||||||
* 其次,我们从摄像机的视角渲染场景。并使用深度图计算对象是否位于阴影中。
|
* 其次,我们从摄像机的视角渲染场景。并使用深度图计算对象是否位于阴影中。
|
||||||
|
|
||||||
为了渲染深度图,我们需要说说深度缓冲区(Depth-buffer)。当我们渲染一个场景时,所有深度信息都储存在一个名为“深度缓冲区”(又称“Z缓冲区(Z-buffer)”)的缓冲区中。深度信息是渲染的每个片元的$$z$$值。如果你从第一章回忆我们在渲染场景时,将正在渲染的场景从世界坐标转换为屏幕坐标。我们所绘制的坐标空间,对于$$x$$和$$y$$轴来说,坐标的范围为$$0$$到$$1$$。如果一个物体比其他对象原,我们必须通过透视投影矩阵计算它如何影响其$$x$$和$$y$$坐标。这不是根据$$z$$值自动计算的,它必须由我们来做。实际储存在$$z$$坐标中的是它在片元的深度,仅此而已。
|
为了渲染深度图,我们需要说说深度缓冲区(Depth-buffer)。当我们渲染一个场景时,所有深度信息都储存在一个名为“深度缓冲区”(又称“Z缓冲区(Z-buffer)”)的缓冲区中。深度信息是渲染的每个片元的$z$值。如果你从第一章回忆我们在渲染场景时,将正在渲染的场景从世界坐标转换为屏幕坐标。我们所绘制的坐标空间,对于$x$和$y$轴来说,坐标的范围为$0$到$1$。如果一个物体比其他对象原,我们必须通过透视投影矩阵计算它如何影响其$x$和$y$坐标。这不是根据$z$值自动计算的,它必须由我们来做。实际储存在$z$坐标中的是它在片元的深度,仅此而已。
|
||||||
|
|
||||||
此外,在源代码中,我们启用了深度测试。在`Window`类中,我们添加如下行:
|
此外,在源代码中,我们启用了深度测试。在`Window`类中,我们添加如下行:
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
```
|
```
|
||||||
|
|
||||||
通过添加这行,我们可以防止无法看到的片元被绘制出来,因为他们位于其他对象之后。在绘制片元之前,它的$$z$$值将与Z缓冲区中的$$z$$值进行比较。如果它的$$z$$值(它的距离)大于缓冲区的$$z$$值,则会被丢弃。请记住,这是在屏幕空间中完成的,因此,给定一对屏幕空间中范围为$$[0, 1]$$的$$x$$和$$y$$坐标,我们比较其片元的$$z$$值。同样,$$z$$值也在此范围内。
|
通过添加这行,我们可以防止无法看到的片元被绘制出来,因为他们位于其他对象之后。在绘制片元之前,它的$z$值将与Z缓冲区中的$z$值进行比较。如果它的$z$值(它的距离)大于缓冲区的$z$值,则会被丢弃。请记住,这是在屏幕空间中完成的,因此,给定一对屏幕空间中范围为$[0, 1]$的$x$和$y$坐标,我们比较其片元的$z$值。同样,$z$值也在此范围内。
|
||||||
|
|
||||||
深度缓冲区的存在是我们在执行任何渲染操作之前需要清除屏幕的原因。我们不仅需要清除颜色,还要清除深度信息:
|
深度缓冲区的存在是我们在执行任何渲染操作之前需要清除屏幕的原因。我们不仅需要清除颜色,还要清除深度信息:
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ public Texture(int width, int height, int pixelFormat) throws Exception {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
我们将纹理环绕方式设置为`GL_CLAMP_TO_EDGE`,因为我们不希望在超出$$[0, 1]$$范围时重复纹理。
|
我们将纹理环绕方式设置为`GL_CLAMP_TO_EDGE`,因为我们不希望在超出$[0, 1]$范围时重复纹理。
|
||||||
|
|
||||||
所以,现在我们可以创建空的纹理,我们需要能够在其中渲染一个场景。为了做到它,我们需要使用帧缓冲区对象(Frame Buffers Objects,或称FBOs)。帧缓冲区是可以作为渲染终点的缓冲区集合。当我们渲染到屏幕上时,我们使用的是OpenGL的默认缓冲区。OpenGL允许我们使用FBO渲染到用户定义的缓冲区。我们将通过创建一个名为`ShadowMap`的新类,来隔离为阴影映射创建FBO过程的其余代码。如下就是那个类的定义。
|
所以,现在我们可以创建空的纹理,我们需要能够在其中渲染一个场景。为了做到它,我们需要使用帧缓冲区对象(Frame Buffers Objects,或称FBOs)。帧缓冲区是可以作为渲染终点的缓冲区集合。当我们渲染到屏幕上时,我们使用的是OpenGL的默认缓冲区。OpenGL允许我们使用FBO渲染到用户定义的缓冲区。我们将通过创建一个名为`ShadowMap`的新类,来隔离为阴影映射创建FBO过程的其余代码。如下就是那个类的定义。
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ void main()
|
|||||||
|
|
||||||
然后我们需要将这些坐标转换到屏幕空间,也就是说,需要投影它们。这是计算平行光与点光源的阴影图时的区别之一。对于地昂扬,我们将使用透视投影(Perspective Projection)矩阵,就像我们正常渲染场景一样。相反,平行光以相同方式影响所有对象,而与距离无关。平行光源位于无穷远的点上,没有位置,只有方向。正交投影(Orthographic Projection)不会使远处的物体变小,因此,正交投影最适合平行光。
|
然后我们需要将这些坐标转换到屏幕空间,也就是说,需要投影它们。这是计算平行光与点光源的阴影图时的区别之一。对于地昂扬,我们将使用透视投影(Perspective Projection)矩阵,就像我们正常渲染场景一样。相反,平行光以相同方式影响所有对象,而与距离无关。平行光源位于无穷远的点上,没有位置,只有方向。正交投影(Orthographic Projection)不会使远处的物体变小,因此,正交投影最适合平行光。
|
||||||
|
|
||||||
片元着色器更简单。它只输出$$z$$坐标作为深度值。
|
片元着色器更简单。它只输出$z$坐标作为深度值。
|
||||||
|
|
||||||
```glsl
|
```glsl
|
||||||
#version 330
|
#version 330
|
||||||
@@ -335,7 +335,7 @@ float calcShadow(vec4 position)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
该函数接收使用正交投影矩阵投影的光照观察空间的坐标。如果坐标在阴影中,则返回$$0$$,如果不在阴影中,则返回$$1$$。首先,将坐标转换为纹理坐标。屏幕坐标在$$[-1, 1]$$范围内,但纹理坐标在$$[0, 1]$$范围内。我们通过坐标从纹理中获取深度值,并将其与片元坐标的$$z$$值比较。如果$$z$$值低于储存在纹理中的值,则表示片元不再阴影中。
|
该函数接收使用正交投影矩阵投影的光照观察空间的坐标。如果坐标在阴影中,则返回$0$,如果不在阴影中,则返回$1$。首先,将坐标转换为纹理坐标。屏幕坐标在$[-1, 1]$范围内,但纹理坐标在$[0, 1]$范围内。我们通过坐标从纹理中获取深度值,并将其与片元坐标的$z$值比较。如果$z$值低于储存在纹理中的值,则表示片元不再阴影中。
|
||||||
|
|
||||||
在片元着色器中,`calcShadow`函数的返回值,用于调节点光源、聚光源和平行光对光照颜色的共享。环境光不受阴影的影响。
|
在片元着色器中,`calcShadow`函数的返回值,用于调节点光源、聚光源和平行光对光照颜色的共享。环境光不受阴影的影响。
|
||||||
|
|
||||||
@@ -373,11 +373,11 @@ if ( projCoords.z - bias < texture(shadowMap, projCoords.xy).r )
|
|||||||
|
|
||||||
> 译者注:使用偏移来消除阴影失真又会造成悬浮(Peter Panning)问题,另请参阅[LearnOpenGL阴影映射](https://learnopengl-cn.github.io/05%20Advanced%20Lighting/03%20Shadows/01%20Shadow%20Mapping/)一文。
|
> 译者注:使用偏移来消除阴影失真又会造成悬浮(Peter Panning)问题,另请参阅[LearnOpenGL阴影映射](https://learnopengl-cn.github.io/05%20Advanced%20Lighting/03%20Shadows/01%20Shadow%20Mapping/)一文。
|
||||||
|
|
||||||
现在我们要解决的是去阴影边缘问题,这也是由纹理分辨率引起的。对于每个片元,我们将使用片元的坐标值和周围的值对深度图进行采样。然后我们将计算平均值并将该值指定为阴影值。在此情况下,它的值不会是$$0$$和$$1$$但可以在两者间取值,以获得更平滑的边缘。
|
现在我们要解决的是去阴影边缘问题,这也是由纹理分辨率引起的。对于每个片元,我们将使用片元的坐标值和周围的值对深度图进行采样。然后我们将计算平均值并将该值指定为阴影值。在此情况下,它的值不会是$0$和$1$但可以在两者间取值,以获得更平滑的边缘。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
在纹理坐标中,周围值必须与当前片元位置保持一个像素距离。所以我们需要计算纹理坐标中一个像素的增量,它等于$$1 / 纹理大小$$。
|
在纹理坐标中,周围值必须与当前片元位置保持一个像素距离。所以我们需要计算纹理坐标中一个像素的增量,它等于$1 / 纹理大小$。
|
||||||
|
|
||||||
在片元着色器中,我们只需要修改阴影银子的计算来得到一个平均值。
|
在片元着色器中,我们只需要修改阴影银子的计算来得到一个平均值。
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user