零基础学习OpenGL(十三)--阴影(二) 点光源阴影

本文介绍了如何在OpenGL中创建点光源动态阴影,重点讲述了使用立方体贴图和几何着色器来生成深度立方体贴图,以实现从各个方向生成阴影。通过渲染场景6次并利用光空间变换矩阵,实现了在光照像素着色器中对立方体贴图的采样,从而计算出点光源阴影。
摘要由CSDN通过智能技术生成

       上节我们学了如何使用阴影映射技术创建动态阴影,但它只适合定向光,因为阴影只是在单一定向光源下生成的。本节我们的焦点是在各种方向生成动态阴影。这个技术可以适用于点光源,生成所有方向上的阴影。

        点光阴影,过去的名字是万向阴影贴图(omnidirectional shadow maps)技术。算法和定向阴影映射差不多:我们从光的透视图生成一个深度贴图,基于当前fragment位置来对深度贴图采样,然后用储存的深度值和每个fragment进行对比,看看它是否在阴影中。定向阴影映射和万向阴影映射的主要不同在于深度贴图的使用上。

       对于深度贴图,定向光只要用2D的贴图就可以,但是点光源,需要从这个点的所有渲染场景,普通2D深度贴图不能工作,但是用立方体贴图可以储存6个面的环境数据,它可以将整个场景渲染到立方体贴图的每个面上,把它们当作点光源四周的深度值来采样。生成后的深度立方体贴图被传递到光照像素着色器,它会用一个方向向量来采样立方体贴图,从而得到当前的fragment的深度(从光的透视图)。

       为创建一个光周围的深度值的立方体贴图,我们必须渲染场景6次:每次一个面。显然渲染场景6次需要6个不同的视图矩阵,每次把一个不同的立方体贴图面附加到帧缓冲对象上。

for(int i = 0; i < 6; i++)

{

    GLuint face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, face, depthCubemap, 0);

    BindViewMatrix(lightViewMatrices[i]);

    RenderScene();

}

       这会很耗费性能因为一个深度贴图下需要进行很多渲染调用。这个教程中我们将转而使用另外的一个小技巧来做这件事,几何着色器允许我们使用一次渲染过程来建立深度立方体贴图。

创建一个立方体贴图:

    GLuint depthCubemap;

    glGenTextures(1, &depthCubemap);

生成立方体贴图的每个面,将它们作为2D深度值纹理图像:

    const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;

    glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap);

    for (GLuint i = 0; i < 6; ++i)

        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

设置合适的纹

OpenGL中实现多光源阴影贴图通常涉及以下几个步骤: 1. **设置光照模型**: 首先,你需要选择适合阴影渲染的光照模型,例如Phong照明模型。在这个模型中,光源对物体表面的照射有明暗两个部分。 2. **创建光源和投影矩阵**: 对于每个光源,计算它的方向或位置(如果为点光源),然后生成对应的光照方向向量和投影矩阵。这一步通常使用GLU库中的gluLookAt函数来帮助计算视口矩阵和投影矩阵。 3. **启用深度测试和写入深度缓冲**: 设置OpenGL的深度测试功能,确保每个像素都会被正确地投射到阴影贴图上。启用GL_DEPTH_TEST和GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT。 4. **阴影映射**: - **阴影贴图**: 创建一个纹理来存储阴影信息。大小通常是屏幕分辨率的两倍(通常称为“影子分辨率”)。 - **近似阴影** (Shadow Mapping): 投影每个光源到这个纹理上,使用场景中物体的背面作为相机的位置。如果像素在物体后面,则认为是阴影区域,否则不是。 - **深度偏移** (Depth Bias): 为了避免由于浮点精度导致的边界模糊,可能需要添加一个小的深度值偏移。 5. **绘制场景**: - **逐顶点着色器(Vertex Shader)**: 将每个顶点变换到屏幕空间,并同时将其转换到所有光源的阴影映射空间,以便获取阴影值。 - **逐片段着色器(Fragment Shader)**: 如果当前片段落在阴影区域内,则颜色为黑色,否则根据光照计算结果。 6. **合并多个光源的阴影**: 如果有多光源,你可以在片段着色器里累加各个光源的阴影影响。一种常见的做法是使用各向异性过滤器(Anisotropic Filtering)来平滑不同光源的影响边界。 7. **最终渲染**: 在所有光源处理完毕后,禁用深度测试,再次启用写入颜色缓冲,按照正常的方式绘制带有阴影效果的场景。 ```cpp // 示例片段着色器代码片段 #version 330 core in vec3 vertexPosition; in vec3 vertexNormal; uniform sampler2D shadowMap[numberOfLights]; // 存储每个光源的阴影贴图 uniform float lightIntensity[numberOfLights]; uniform mat4 viewMatrix, projectionMatrix; void main() { // 获取当前片段在阴影贴图上的深度 float depth = texture(shadowMap[lightIndex], gl_FragCoord.xy).r; // 使用混合因子(如blending)融合当前片段与阴影的结果 float shadowFactor = smoothstep(clipValue, 1.0f, depth / clipValue); // 光照计算和颜色合成 vec3 shadedColor = vec3(0.0) + shadowFactor * lightIntensity[lightIndex] * vec3(normalize(vertexNormal)); gl_FragColor = vec4(shadedColor, 1.0f); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值