Shadow mapping(阴影贴图)是一种常用的实时阴影生成技术,广泛应用于计算机图形学、游戏引擎和其他实时渲染系统中。它用于创建场景中物体的阴影,从而增加画面的真实感和深度感。
阴影贴图的基本原理
阴影贴图技术的基本思想是使用一个深度图(depth map)来记录光源视角下场景中每个像素到光源的距离。然后,在渲染场景时,通过比较像素到光源的距离与深度图中的值来确定该像素是否在阴影中。
阴影贴图的步骤
-
从光源视角渲染深度图:
- 首先,从光源的视角渲染整个场景,并将每个像素到光源的距离存储在深度图中。这一步称为深度图生成(depth map generation)。
-
从相机视角渲染场景:
- 其次,从相机的视角渲染场景。对于每个像素,计算该像素到光源的距离,并将其与深度图中的对应值进行比较。
- 如果该像素到光源的距离大于深度图中的值,则该像素在阴影中;否则,该像素不在阴影中。
阴影贴图的实现细节
以下是一些实现阴影贴图的关键细节:
-
深度图生成:
- 使用光源的视角进行正交或透视投影。
- 渲染场景并记录每个像素到光源的深度。
-
深度比较:
- 在相机视角下渲染时,将每个像素的世界坐标转换到光源的视角。
- 通过光源的投影矩阵计算该像素在深度图中的坐标。
- 比较该像素到光源的距离与深度图中的值,确定是否在阴影中。
-
处理伪影:
- 阴影走样(Shadow Acne): 由于深度精度限制,可能会出现锯齿状阴影。通常通过偏移深度值(biasing)来减轻。
- 彼得平滑(PCF,Percentage-Closer Filtering): 通过对多个邻近深度值进行平均处理,可以平滑阴影边缘。
- 阴影伪影(Shadow Map Aliasing): 分辨率不足的深度图可能导致锯齿状阴影边缘。通过提高深度图分辨率或使用级联阴影贴图(Cascaded Shadow Maps)来减轻。
代码示例
以下是一个基本的伪代码示例,展示了如何使用 OpenGL 实现阴影贴图:
// 1. 从光源视角生成深度图 glViewport(0, 0, shadowWidth, shadowHeight); glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glClear(GL_DEPTH_BUFFER_BIT); glm::mat4 lightProjection, lightView; glm::mat4 lightSpaceMatrix; // 设置光源的投影矩阵和视图矩阵 lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane); lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0, 1.0, 0.0)); lightSpaceMatrix = lightProjection * lightView; // 渲染场景到深度图 shader.setMat4("lightSpaceMatrix", lightSpaceMatrix); renderScene(shader); glBindFramebuffer(GL_FRAMEBUFFER, 0); // 2. 从相机视角渲染场景,并使用深度图进行阴影检测 glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glm::mat4 view = camera.GetViewMatrix(); glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); shader.setMat4("projection", projection); shader.setMat4("view", view); // 传递光源的空间矩阵和深度图到着色器 shader.setMat4("lightSpaceMatrix", lightSpaceMatrix); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, depthMap); shader.setInt("shadowMap", 1); renderScene(shader);
总结
阴影贴图是一种强大且灵活的实时阴影生成技术,通过记录和比较深度值,能够在三维场景中生成动态阴影。虽然实现细节可能比较复杂,但通过合理处理深度比较和伪影问题,可以实现高质量的阴影效果。
软阴影(Soft Shadows)是指阴影的边缘是平滑的,而不是硬边的。这种阴影更接近于现实生活中的阴影,因为在现实世界中,光源通常不是点光源,而是具有一定面积的面光源或体积光源,导致阴影边缘出现渐变。
软阴影的生成
生成软阴影的方法有很多,包括:
- 面积光源采样(Area Light Sampling): 通过对光源的多个点进行采样,生成阴影的柔和边缘。
- 阴影贴图的模糊(Shadow Map Blurring): 对阴影贴图进行模糊处理,使得阴影边缘变得柔和。
- PCF(Percentage-Closer Filtering): 对多个邻近深度值进行平均处理,可以平滑阴影边缘。
阴影贴图与软阴影
阴影贴图(Shadow Mapping)是生成阴影的基础技术,通过记录从光源视角下场景中每个像素到光源的距离,来判断像素是否在阴影中。通过添加一些额外的处理,阴影贴图技术也可以用来生成软阴影。
使用阴影贴图生成软阴影的方法
以下是几种常见的方法,用于在阴影贴图的基础上生成软阴影:
使用阴影贴图生成软阴影的方法
以下是几种常见的方法,用于在阴影贴图的基础上生成软阴影:
-
PCF(Percentage-Closer Filtering):
- 在计算阴影时,对当前像素周围的多个深度值进行采样,然后对这些深度值进行平均处理,以生成平滑的阴影边缘。
float shadow = 0.0; vec2 texelSize = 1.0 / textureSize(shadowMap, 0); for(int x = -1; x <= 1; ++x) { for(int y = -1; y <= 1; ++y) { float pcfDepth = texture(shadowMap, fragPosLightSpace.xy + vec2(x, y) * texelSize).r; shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0; } } shadow /= 9.0;
-
VSM(Variance Shadow Maps):
- 使用方差阴影贴图技术,通过存储深度和深度的平方,使用方差来估计深度的分布,从而实现软阴影。
float ChebyshevUpperBound(float Moments[2], float t) { // One-tailed inequality valid if t > Moments[0] float p = t - Moments[0]; float variance = Moments[1] - (Moments[0] * Moments[0]); variance = max(variance, 0.00002); float d = p * p / variance; return variance / (variance + d); }
-
面积光源采样(Area Light Sampling):
- 对光源进行多个采样,模拟面积光源的效果,从而生成软阴影。这个方法比较昂贵,因为需要进行多次采样。
float shadow = 0.0; int samples = 16; vec3 random = vec3(rand(), rand(), rand()); for(int i = 0; i < samples; ++i) { vec3 offset = gridSamplingDisk(i, samples, random); float closestDepth = texture(shadowMap, fragPosLightSpace.xy + offset.xy).r; shadow += currentDepth - bias > closestDepth ? 1.0 : 0.0; } shadow /= float(samples);
总结
软阴影是指具有平滑边缘的阴影,能够提供更逼真的渲染效果。阴影贴图是生成阴影的一种基础技术,通过一些扩展和处理,可以在阴影贴图的基础上生成软阴影。常见的方法包括PCF、VSM和面积光源采样等。通过这些技术,可以实现不同程度和质量的软阴影效果,以满足不同的渲染需求。
标签:贴图,Map,深度图,光源,float,像素,阴影 From: https://www.cnblogs.com/jeason1997/p/18235791