news 2026/4/28 14:49:53

GPU PRO 4 - 4.1 Real-Time Deep Shadow Maps 笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GPU PRO 4 - 4.1 Real-Time Deep Shadow Maps 笔记

本笔记仅为个人的理解,如果有误欢迎指出

Real-Time Deep Shadow Maps 实时深度阴影贴图

在离线渲染中渲染半透明物体的时候会使用到一种深度阴影贴图的东西辅助渲染,例如头发以及烟雾的阴影渲染,本篇文章提供了一种在实时渲染中生成并应用深度阴影贴图的方法,依赖DX11 的API。

一张阴影贴图是光源点为视角,观察不透明物体时生成的深度图,但这张贴图一般是不会考虑半透明物体的,深度阴影贴图中则是专门考量半透明物体对阴影影响,具体影响数值由下面这个公式得出

公式意义很简单,d表示深度,意思是到这个深度前每个透明物体都根据透明度(α)累乘(1-α),

类似这样(1-α1)(1-α2)(1-α3)(1-α4)

得到深度阴影贴图后,在渲染半透明物体时把对应的值都考虑到最终结果计算即可

shading /= FILTER_AREA; return float4(finalColor * clamp(shading, 0.1f, 1.0f), 1.0f);

书籍中的代码的shading便是计算出来的

简单的说,深度阴影贴图是一个专门保存半透明物体对阴影影响的贴图,虽然说是贴图但在源代码中并没有贴图生成,所有数据都保存在RWStructuredBuffer上,这也是为什么要依靠DX11的原因。

文章中分了5个部分:

1,创建链表

2,处理片元

3,链接邻居

4,延迟阴影渲染

5,空间滤波

1,创建链表:

从光源角度渲染场景,在渲染半透明物体的时候将每个片元的深度信息以及透明度信息保存在链表下。

示意图:

相关代码:

RWStructuredBuffer<StartElementBufEntry> StartElementBuf; RWStructuredBuffer<LinkedListEntryDepthAlphaNext> LinkedListBufDAN; void ps_main(PS_IN input) { int counter = LinkedListBufDAN.IncrementCounter(); LinkedListBufDAN[counter].depth = input.pos.z + 0.00002f; LinkedListBufDAN[counter].alpha = Alpha; int originalVal; InterlockedExchange(StartElementBuf[((uint)input.pos.y) * Dimension + (uint)input.pos.x].start, counter, originalVal); LinkedListBufDAN[counter].next = originalVal; }

代码很简单,就是一个常见的创建链表的过程,在创建链表的时候会生成一个起点表,用来表示每个像素的起点。

但这里有个问题,半透明物体渲染的顺序一般是远的物体先渲染然后再渲染近的,代码上逻辑没有问题,最后生成出来的StartElementBuf起点应该是最靠近光源点的,但是示意图中的HeadBuffer就反直觉了,比如HeadBuffer 中 1像素的位置,对应的Next是 6,6对应的Next 是 -1,但是按照代码来看每个LinkedListBufDAN的元素next应该小于索引号或者是-1才对。

这里面可能的原因是c++代码中并没有对渲染半透明物体进行排序,因此引出了后面【处理片元】和【链接邻居】这两个步骤,对链表中的数据进行了排序调整,所以示意图中的数据是排序后的样子。

2,处理片元:

在这里就对上一个步骤中生成的链表根据深度进行插入排序,并且计算了每个深度对应的保存,为了加速计算,如果累乘之后变化值很小的话就会停止计算。

对应代码:

// reduction float shadingBefore = 1.0f; for(int i = 0; i < numElems; i++) { float shadingCurrent = shadingBefore * (1.0f - list[i].alpha); if(shadingBefore - shadingCurrent > 0.001f) { shadingBefore = shadingCurrent; list[i].alpha = shadingCurrent; } else { numElems = i; nextPoints[i - 1] = -1; break; } }

3,链接邻居:

在这里每个片元的链表都会链接周围深度上接近的链表,这个主要是为了后面抗锯齿做的处理,为了节省内存,文章中只连接了右和上的邻居链表

4,延迟阴影:

这里主要是应用DSM在半透明渲染上,渲染半透明物体的时候根据当前深度查找链表获取计算到的,并应用到最终颜色的渲染上

相关代码:

void depthSearch(inout LinkedListEntryWithPrev entry, inout LinkedListEntryNeighbors entryNeighbors, float z, out float outShading) { LinkedListEntryWithPrev tempEntry; int newNum = -1; // -1 means not changed if(entry.depth < z) for(int i = 0; i < NUM_BUF_ELEMENTS; i++) { if(entry.next == -1) { outShading = entry.shading; break; } tempEntry = LinkedListBufWPRO[entry.next]; if(tempEntry.depth >= z) { outShading = entry.shading; break; } newNum = entry.next; entry = tempEntry; } else for(int i = 0; i < NUM_BUF_ELEMENTS; i++) { if(entry.prev == -1) { outShading = 1.0f; break; } newNum = entry.prev; entry = LinkedListBufWPRO[entry.prev]; if(entry.depth < z) { outShading = entry.shading; break; } } if(newNum != -1) // finally lookup the neighbors if we changed entry entryNeighbors = NeighborsBufRO[newNum]; } ........... shading /= FILTER_AREA; return float4(finalColor * clamp(shading, 0.1f, 1.0f), 1.0f);

在这里outShading则是在处理片元步骤中计算的值,最终运用到finalColor上

5,空间滤波:

基于空间的抗锯齿技术,由于在第三步中链接了邻居片元的链表,所以文章中用了类似PCF的方式通过邻居链表遍历每个片元右边以及上边的邻居,获取他们的值,总和平均计算出最终的。思路其实是和PCF一样的,获取周边像素并平均,在这里则是通过邻居链表来获取周边像素来平均

文章中还提及了可以用ESM来处理抗锯齿,图则是效果,左边是没有通过空间滤波,直接使用当前深度的,中间用的PCF抗锯齿,右边则是ESM来抗锯齿

参考链接:

[GPU Pro4] 阴影篇

【屏幕空间深度阴影贴图】

书籍源码

图形学基础 - 着色 - 透明度混合-OIT

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 1:35:53

从数据监测到训练优化:视觉训练 APP 的硬件联动逻辑

视觉训练APP与硬件的联动&#xff0c;核心是构建“数据监测-分析处理-训练优化”的闭环逻辑。硬件作为数据采集终端&#xff0c;APP承担中枢调控功能&#xff0c;二者依托物联网技术深度协同&#xff0c;让护眼训练从经验化走向精准化&#xff0c;实现效能最大化。数据采集是联…

作者头像 李华
网站建设 2026/4/17 8:08:35

终极指南:如何安全使用R3nzSkin实现英雄联盟换肤体验

终极指南&#xff1a;如何安全使用R3nzSkin实现英雄联盟换肤体验 【免费下载链接】R3nzSkin Skin changer for League of Legends (LOL) 项目地址: https://gitcode.com/gh_mirrors/r3n/R3nzSkin R3nzSkin换肤工具是一款专为《英雄联盟》玩家设计的开源皮肤修改工具&…

作者头像 李华
网站建设 2026/4/17 9:24:36

MATLAB箱线图绘制全攻略:从数据导入到高级美化(附常见问题解决)

MATLAB箱线图绘制全攻略&#xff1a;从数据导入到高级美化&#xff08;附常见问题解决&#xff09; 箱线图作为数据可视化的重要工具&#xff0c;能直观展示数据的分布特征和异常值。对于MATLAB用户而言&#xff0c;掌握箱线图的完整绘制流程不仅能提升数据分析效率&#xff0c…

作者头像 李华
网站建设 2026/4/15 3:39:59

免费快速备份QQ空间历史说说的完整解决方案

免费快速备份QQ空间历史说说的完整解决方案 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾担心QQ空间里那些记录青春岁月的说说会随着时间流逝而消失&#xff1f;GetQzonehist…

作者头像 李华
网站建设 2026/4/17 7:22:03

Dify+OpenAI+XInference三件套配置指南:从模型部署到API调用全流程

DifyOpenAIXInference三件套配置指南&#xff1a;从模型部署到API调用全流程 在AI应用开发领域&#xff0c;如何高效整合多个模型服务并构建稳定可靠的工作流&#xff0c;一直是开发者面临的挑战。本文将深入探讨基于Dify平台&#xff0c;结合OpenAI的通用语言模型与XInference…

作者头像 李华
网站建设 2026/4/17 13:33:49

数据发散与数据倾斜:从原理到实战的避坑指南

1. 数据发散与数据倾斜&#xff1a;初学者的第一道门槛 刚入行数据开发那会儿&#xff0c;我最怕的就是跑着跑着任务突然卡死&#xff0c;或者莫名其妙生成了几百GB的中间数据。后来才知道&#xff0c;这八成是遇到了数据发散或数据倾斜的问题。这两个概念听起来像双胞胎&#…

作者头像 李华