首页 > 其他分享 >Shadow Map(阴影贴图)跟Soft Shadows(软阴影)

Shadow Map(阴影贴图)跟Soft Shadows(软阴影)

时间:2024-06-06 18:44:26浏览次数:17  
标签:贴图 Map 深度图 光源 float 像素 阴影

Shadow mapping(阴影贴图)是一种常用的实时阴影生成技术,广泛应用于计算机图形学、游戏引擎和其他实时渲染系统中。它用于创建场景中物体的阴影,从而增加画面的真实感和深度感。

阴影贴图的基本原理

阴影贴图技术的基本思想是使用一个深度图(depth map)来记录光源视角下场景中每个像素到光源的距离。然后,在渲染场景时,通过比较像素到光源的距离与深度图中的值来确定该像素是否在阴影中。

阴影贴图的步骤

  1. 从光源视角渲染深度图:

    • 首先,从光源的视角渲染整个场景,并将每个像素到光源的距离存储在深度图中。这一步称为深度图生成(depth map generation)。
  2. 从相机视角渲染场景:

    • 其次,从相机的视角渲染场景。对于每个像素,计算该像素到光源的距离,并将其与深度图中的对应值进行比较。
    • 如果该像素到光源的距离大于深度图中的值,则该像素在阴影中;否则,该像素不在阴影中。

阴影贴图的实现细节

以下是一些实现阴影贴图的关键细节:

  1. 深度图生成:

    • 使用光源的视角进行正交或透视投影。
    • 渲染场景并记录每个像素到光源的深度。
  2. 深度比较:

    • 在相机视角下渲染时,将每个像素的世界坐标转换到光源的视角。
    • 通过光源的投影矩阵计算该像素在深度图中的坐标。
    • 比较该像素到光源的距离与深度图中的值,确定是否在阴影中。
  3. 处理伪影:

    • 阴影走样(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)是指阴影的边缘是平滑的,而不是硬边的。这种阴影更接近于现实生活中的阴影,因为在现实世界中,光源通常不是点光源,而是具有一定面积的面光源或体积光源,导致阴影边缘出现渐变。

软阴影的生成

生成软阴影的方法有很多,包括:

  1. 面积光源采样(Area Light Sampling): 通过对光源的多个点进行采样,生成阴影的柔和边缘。
  2. 阴影贴图的模糊(Shadow Map Blurring): 对阴影贴图进行模糊处理,使得阴影边缘变得柔和。
  3. PCF(Percentage-Closer Filtering): 对多个邻近深度值进行平均处理,可以平滑阴影边缘。

阴影贴图与软阴影

阴影贴图(Shadow Mapping)是生成阴影的基础技术,通过记录从光源视角下场景中每个像素到光源的距离,来判断像素是否在阴影中。通过添加一些额外的处理,阴影贴图技术也可以用来生成软阴影。

使用阴影贴图生成软阴影的方法

以下是几种常见的方法,用于在阴影贴图的基础上生成软阴影:

使用阴影贴图生成软阴影的方法

以下是几种常见的方法,用于在阴影贴图的基础上生成软阴影:

  1. 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;
  2. 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);
    }
  3. 面积光源采样(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

相关文章

  • 从零开始的.NET项目(一)仓储模式与配置AutoMapper
    目标框架:.net6.0操作系统:macos编译器:Rider内容:创建第一个Controller,使用仓储(Respository)模式实现,并使用AutoMapper进行数据对象关系映射非常简单的实现,Automapper也只介绍了最基础也最常用的其他用法后续再补,目的就是稳准狠......
  • 高德面试:为什么Map不能插入null?
    在Java中,Map是属于java.util包下的一个接口(interface),所以说“为什么Map不能插入null?”这个问题本身问的不严谨。Map部分类关系图如下:所以,这里面试官其实想问的是:为什么ConcurrentHashMap不能插入null?1.HashMap和ConcurrentHashMap的区别HashMap和ConcurrentHash......
  • Day1 学习笔记及成果---MapReduce实现手机流量统计分析
    Day1学习笔记及成果—MapReduce实现手机流量统计分析题目统计每个手机号上行流量和、下行流量和、总流量和(上行流量和+下行流量和),并且:将统计结果按照手机号的前缀进行区分,并输出到不同的输出文件中去。13*==>…15*==>…other==>…其中,access.log数据文件部分......
  • Day2 学习笔记及成果---基于MapReduce项目实现中所遇到的问题及解决方法
    Day2学习笔记及成果—基于MapReduce项目实现中所遇到的问题及解决方法问题一:主机和虚拟机互相能ping通,主机能ping通外网,虚拟机不能ping通外网。解决方案:可能的错误原因是网关设置有问题,虚拟机的网关应该和自己的网关一直,自己的网关可在编辑-虚拟网络设置中查看。首先执......
  • Linux系统之Nmap工具结果可视化教程
    Linux系统之Nmap工具结果可视化教程一、Nmap介绍1.1Nmap简介1.2Nmap特点1.3nmap-did-what介绍二、本地环境介绍2.1本地环境规划2.2本次实践介绍四、安装python环境4.1安装python4.2检查python版本4.3创建部署目录五、使用Nmap命令5.1......
  • 【图解】HashMap1.7 头插法造成死循环
    1.概述HashMap1.7当中,扩容的时候,采用的是头插法转移结点,在多线程并发的情况下会造成链表死循环的问题。HashMap1.8中改为了尾插法,解决扩容时线程并发产生的死循环问题。2.图解假设有两个线程,线程1和线程2,两个线程进行hashMap的put操作,触发了扩容。下面是扩容的时候结点转移的......
  • 使用Kimi+Markmap总结网页内容生成思维导图
    AI可以帮助我们更高效地阅读文章进行提炼总结,像上图这张思维导图,就是使用Kimi进行内容提炼,再使用markmap生成思维导图,下面讲解下详细实现步骤:一、工具准备Kimi,将文章或一篇网页投给他,让他进行核心观点的提炼并生成我们想要的特定格式markmap一个可以将markdown文本转换成思维......
  • Java集合-Map家族
    集合-Map家族1各实现类的特点HashMap:存key+value,key去重,无序,线程不安全LinkedHashMap:存key+value,key去重,有序,线程不安全Hashtable:弃用,存key+value,key去重,无序,线程安全,方法加锁-效率低ConcurrentHashMap:存key+value,key去重,无序,线程安全,局部加锁、CAS-效率高TreeMap:存key+......
  • View->Canvas使用RectF方式绘制Bitmap,RectF大小和Bitmap大小不同导致绘制效果不同
    图片XML文件<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent......
  • View->Bitmap缩放到自定义ViewGroup的任意区域(RectF方式绘制Bitmap)
    XML文件<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent&quo......