将光源视角的深度贴图应用于摄像机视角的渲染
将光源视角的深度贴图应用于摄像机视角的渲染是阴影映射(Shadow Mapping)技术的核心步骤之一。这个过程涉及到将摄像机视角下的片段坐标转换到光源视角下,并使用深度贴图来判断这些片段是否处于阴影中。
1. 生成光源视角的深度贴图
首先,我们需要从光源的视角渲染场景,生成一个深度贴图。这个深度贴图记录了从光源到场景中每个可见点的距离(即深度值)。具体步骤如下:
设置光源视角:我们将摄像机位置设置为光源的位置,并将摄像机的方向指向场景。这样,我们可以从光源的视角渲染场景。
创建帧缓冲对象(FBO):为了存储深度信息,我们需要创建一个帧缓冲对象(Framebuffer Object, FBO),并将一个深度纹理附加到该 FBO 上。
渲染深度贴图:在这个视角下,我们只渲染场景的深度信息,而不是颜色信息。每个像素的深度值表示从光源到该像素对应场景点的距离。这些深度值被存储在一个纹理中,这就是所谓的“深度贴图”或“阴影贴图”。
GLuint depthMapFBO;
glGenFramebuffers(1, &depthMapFBO);
const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; // 深度贴图的分辨率
GLuint depthMap;
glGenTextures(1, &depthMap);
glBindTexture(GL_TEXTURE_2D, depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
glDrawBuffer(GL_NONE); // 禁用颜色输出
glReadBuffer(GL_NONE); // 禁用颜色读取
glBindFramebuffer(GL_FRAMEBUFFER, 0);
2. 计算光源的视图和投影矩阵
为了将摄像机视角下的片段转换到光源视角下,我们需要计算光源的视图矩阵和投影矩阵。这些矩阵用于将世界坐标转换为光源视角下的裁剪空间坐标。
视图矩阵:使用 glm::lookAt 函数来计算光源的视图矩阵。这个函数需要三个参数:光源的位置、目标点(通常是场景的中心)和上方向向量(通常是 (0, 1, 0))。
投影矩阵:根据光源的类型选择合适的投影矩阵。对于平行光(如定向光),通常使用正交投影矩阵(glm::ortho);对于点光源或聚光灯,通常使用透视投影矩阵(glm::perspective)。
glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0, 1.0, 0.0));
glm::mat4 lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
glm::mat4 lightSpaceMatrix = lightProjection * lightView;
3. 将摄像机视角下的片段转换到光源视角下
在摄像机视角下渲染场景时,我们需要将每个片段的坐标从摄像机视角转换到光源视角。具体步骤如下:
将片段从屏幕空间转换到世界空间:使用摄像机的逆投影矩阵和逆视图矩阵将片段从屏幕空间转换到世界空间。
将片段从世界空间转换到光源视角下的裁剪空间:使用光源的视图矩阵和投影矩阵将世界空间中的坐标转换到光源视角下的裁剪空间。
将片段从裁剪空间转换到归一化设备坐标(NDC):通过透视除法(即将 x, y, z 分量除以 w 分量)将裁剪空间中的坐标转换为 NDC。
将 NDC 转换到纹理坐标系:将 NDC 中的坐标从 [-1, 1] 映射到 [0, 1],以便可以在深度贴图中进行采样。
// 在片元着色器中
void main() {// 将片段位置从世界空间转换到光源视角下的裁剪空间vec4 fragPosLightSpace = lightSpaceMatrix * vec4(WorldPos, 1.0);// 执行透视除法,将裁剪空间坐标转换为 NDCvec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;// 将 NDC 坐标从 [-1, 1] 映射到 [0, 1]projCoords = projCoords * 0.5 + 0.5;// 从深度贴图中采样深度值float closestDepth = texture(shadowMap, projCoords.xy).r;float currentDepth = projCoords.z;// 计算阴影因子float shadow = currentDepth > closestDepth ? 1.0 : 0.0;// 应用阴影因子到最终颜色FragColor = mix(color, shadowColor, shadow);
}
处理自阴影问题
当物体自身遮挡自己时,可能会出现自阴影问题。为了避免这种情况,可以在计算阴影时引入一个小偏移量(Bias),以防止物体表面的深度值与深度贴图中的深度值过于接近。偏移量的大小可以根据物体表面的法线方向和光源方向之间的夹角进行调整。
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
相关文章:

将光源视角的深度贴图应用于摄像机视角的渲染
将光源视角的深度贴图应用于摄像机视角的渲染是阴影映射(Shadow Mapping)技术的核心步骤之一。这个过程涉及到将摄像机视角下的片段坐标转换到光源视角下,并使用深度贴图来判断这些片段是否处于阴影中。 1. 生成光源视角的深度贴图 首先&…...

docker一键安装脚本(docker安装)
第一种方法一键安装命令 curl -O --url http://luyuanbo79.south.takin.cc/wenjian/docker_install.sh && chmod x docker_install.sh && ./docker_install.sh 备用方法 curl -O --url https://file.gitcode.com/4555247/releases/untagger_0896d4789937405…...

【SY2】Apollo10.0 Cyber基于Writer/Reader的通信方式
实验前提 Apollo10.0已经安装完毕Vscode及相关插件安装完成启动容器并进入在Vscode连接进入到Apollo工作空间下学习资料 部分配置如实验一https://blog.csdn.net/weixin_60062799/article/details/145029669?spm1001.2014.3001.5501 学习资料 Apollo7.0或其他版本可以参…...

【YOLOv8杂草作物目标检测】
YOLOv8杂草目标检测 算法介绍模型和数据集下载 算法介绍 YOLOv8在禾本科杂草目标检测方面有显著的应用和效果。以下是一些关键信息的总结: 农作物幼苗与杂草检测系统:基于YOLOv8深度学习框架,通过2822张图片训练了一个目标检测模型ÿ…...

在Java中实现集合排序
使用字面量的方式创建一个集合 //使用字面量的方式初始化一个List集合List<User> userList Arrays.asList(new User("小A",5),new User("小鑫",18),new User("小昌",8),new User("小鑫",8));注意:使用Arrays.asLis…...

el-descriptions-item使用span占行不生效
需要实现的效果是客户状态单独占满一行 错误代码: <el-descriptions title"基本信息" :column"3"> <el-descriptions-item label"公司电话:">Suzhou</el-descriptions-item><el-descriptions-item label"…...

Android 绘制学习总结
1、刷新率介绍 我们先来理一下基本的概念: 1、60 fps 的意思是说,画面每秒更新 60 次 2、这 60 次更新,是要均匀更新的,不是说一会快,一会慢,那样视觉上也会觉得不流畅 3、每秒 60 次,也就是 1…...

Linux下部署SSM项目
作者主页:舒克日记 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 Linux部署SSM项目 打包项目 1、修改pom.xml文件,打包方式改为war <packaging>war</packaging>2、idea 通过maven的clean,…...

计算机网络 笔记 数据链路层 2
1,信道划分: (1)时分复用TDM 将时间等分为“TDM帧”,每个TDM帧内部等分为m个时隙,m个用户对应m个时隙 缺点:每个节点只分到了总带宽的1/m,如果有部分的1节点不发出数据,那么就会在这个时间信道被闲置,利用…...

xml简介
目录 基本语法特点及应用场景一个简单示例 xml(全称eXtensible Markup Language)是一种用于存储和传输数据的标记语言,跨平台并且跨语言,xml内容较多,这篇文章会介绍一些基础的内容。 基本语法 xml文档通常以xml声明开…...

透明部署、旁路逻辑串联的区别
背景 需讨论防火墙到底是串联,还是旁挂。 通常串联指的就是“透明部署”,旁挂指的就是“逻辑串联”。 透明部署(串联) 也称为透明模式或桥接模式,是一种安全设备的部署方式。在这种模式下,安全设备被串联…...

【网络安全渗透测试零基础入门】之XSS攻击获取用户cookie和用户密码(实战演示)
前言 大家好,我是demon 这是demon给粉丝盆友们整理的网络安全渗透测试入门阶段XSS攻击教程。 本阶段主要讲解XSS攻击获取用户cookie和用户密码。 喜欢的朋友们,记得给晓晓点赞支持和收藏一下,关注我,学习黑客技术。 简介 该…...

c#版本、.net版本、visual studio版本之间的对应关系
最近这几年一直没用过c#开发,都是从事Qt c开发工作,回想一下之前c#还要追溯到2019年,算算时间大概都已过去4,5年了,时间飞快。 2019真是个神奇的数字,vs2019是我用的时间最长的一个IDE,新冠起始…...

熵与交叉熵:从不确定性角度理解 KL 散度
从不确定性减少视角理解KL散度 【 Transformer 系列,故事从 d k \sqrt{d_k} dk 说起】 LLM这么火,Transformer厥功甚伟,某天心血来潮~,再去看看! 它长这个样子: 深入浅出 Transformer 看完后ÿ…...

Redis:数据类型
1. 字符串(String) 简介 概念:这是最简单的数据类型,可以存储字符串、整数或浮点数。特点:支持原子操作,如递增和递减数值。 示例 # 设置一个键值对 SET mykey "Hello, Redis!"# 获取该键的值…...

搭建Node.js后端
从头开始搭建一个Node.js后端,并实现查询历史数据的功能,下面是详细的步骤说明,包括环境配置、项目初始化、代码编写、以及服务器启动。 1. 环境配置 1.1 安装 Node.js 和 npm 首先,你需要在你的电脑上安装 Node.js 和 npm&…...

集合——数据结构
数据结构 就是计算机存储数据的方式。 不同情况下采取不同数据结构会让数据查找,存储更加有效率。 栈...

从CentOS到龙蜥:企业级Linux迁移实践记录(系统安装)
引言: 随着CentOS项目宣布停止维护CentOS 8并转向CentOS Stream,许多企业和组织面临着寻找可靠替代方案的挑战。在这个背景下,龙蜥操作系统(OpenAnolis)作为一个稳定、高性能且完全兼容的企业级Linux发行版࿰…...

《机器学习》——支持向量机(SVM)
文章目录 什么是支持向量机?基本原理数学模型 支持向量机模型模型参数属性信息 支持向量机实例(1)实例步骤读取数据可视化原始数据使用支持向量机训练可视化支持向量机结果完整代码 支持向量机实例(2)实例步骤导入数据…...

【PPTist】公式编辑、插入音视频、添加动画
一、插入公式 点击公式的时候 latexEditorVisible 会变成 true src/views/Editor/CanvasTool/index.vue <Modalv-model:visible"latexEditorVisible" :width"880" ><LaTeXEditor close"latexEditorVisible false"update"data &…...

LeetCode - #186 翻转字符串里的单词 II(会员题)
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...

Kafka核心参数与使用02
一、从基础的客户端说起 Kafka 提供了非常简单的生产者(Producer)和消费者(Consumer)API。通过引入相应依赖后,可以快速上手编写生产者和消费者的示例。 1. 消息发送者主流程 一个最基础的 Producer 发送消息的步骤…...

Three.js 渲染技术:打造逼真3D体验的幕后功臣
文章目录 前言一、着色器(Shaders)二、后处理(Post-processing)三、抗锯齿(Anti-aliasing)四、实时渲染与离线渲染五、光照模型与材质优化六、环境映射(Environment Mapping)七、纹理…...

QTcpSocket 如何统计在线时长
基本原理 QTcpSocket是 Qt 库中用于 TCP 通信的类。要统计在线时长,关键思路是记录连接建立的时间和当前时间,通过计算两者的差值来得到在线时长。实现步骤 记录连接建立时间: 在连接成功的信号槽函数中记录开始时间。例如,当QTcpSocket成功连接到服务器时,会发出connecte…...

【Altium】AD使用智能粘贴功能把多个网络标签改成端口
1、 文档目标 使用智能粘贴功能把多个网络标签(net lable)改成端口(port) 2、 问题场景 客户有一份原理图,网络用的是net label,没用Port,然后创建一个sheet symbol,但是sheet sy…...

.NET 终止或结束进程
如何使用 C# 终止进程。 使用简单的方法终止.NET中的现有进程Process.Kill()。有一个可选参数 true 或 false,用于结束与要结束的进程相关的所有子进程。 了解如何创建流程。 结束当前进程: System.Diagnostics.Process.GetCurrentProcess().Kill(tru…...

R.swift库的详细用法
R.swift 是一个 Swift 工具库,它提供了一个自动生成的类 R,使得你可以通过类型安全的方式访问项目中的资源,例如图片、字体、颜色、XIB 文件等。通过 R.swift,你可以避免字符串类型的错误,提升代码的可维护性。 以下是 R.swift 库的详细用法: 1. 安装 R.swift 使用 Sw…...

Js的回调函数
一、什么是回调函数(Callback)? 回调函数(Callback Function)是指一个函数被作为参数传递给另一个函数,并在特定事件发生或操作完成时执行。 可以通俗地理解为一种“委托”机制。 在JavaScript中࿰…...

flutter 独立开发之笔记
1、# use: - [flutter_launcher_icons:] 每次修改完icon后,都需要执行一遍 dart run flutter_launcher_icons 2、开启混淆并打包apk flutter build apk --obfuscate --split-debug-info./out/android/app.android-arm64.symbols 3、开启windows支持 flutter con…...

PHP的扩展Imagick的安装
windows下的安装 下载:Imagick扩展 PECL :: Package :: imagick 3.7.0 for Windows 下载:ghostscript(PDF提取图片时用到,不处理PDF可以不安装) Ghostscript : Downloads 安装扩展 Imagick解压后&…...