实时阴影渲染(二):软阴影

软阴影是通过对阴影图进行多次采样实现的

因为多个片段经常会对应同一个阴影纹理像素,单次采样会产生严重的锯齿问题

另外软阴影还可以产生比较柔和的边界,看起来比较自然

锯齿产生的原因

仔细思考阴影锯齿产生的原因,可以想到多个片段对应同一个阴影像素时,其在该阴影像素中对应的的位置是不同的

如下示意图,黑色的大方格表示单个阴影纹理像素,虚线分割的部分表示对应到该阴影像素的9个片段

显然对于AB来说其阴影值和C应该是不同的,算法中应该把这个因素考虑进去

可以想到,当纹理坐标没有对应到正中心时,通过与相邻像素的线性插值也许可以很好的解决我们遇到的锯齿问题

2×2线性插值

如上图,实线分割的四个区域表示阴影纹理中的四个像素,ABCD为其中心点

当一个片段映射到ABCD虚线包含的区域时,这四个像素都应该参与阴影计算,然后通过线性插值得出最终结果

假设纹理大小为float2 size(w, h),像素大小texelSize=float2(1/w, 1/h),当前纹理坐标uv

则以下代码可计算四个点纹理坐标uva/uvb/uvc/uvd,插值系数factor(x, y)【 水平方向插值系数为x, 垂直方向插值为y】:

factor= frac(uv*size-0.5);uva = (floor(uv*size-0.5) + 0.5) * texelSize;

uvb = uva + float(1, 0) * texelSize;
uvc = uva + float(0, 1) * texelSize;
uvd = uva + float(1, 1) * texelSize;

a、b、c、d分别为A、B、C、D阴影值

//a=depthShadow(sm,uva, z,...); b=depthShadow(uvb,...)
ab =  lerp(a, b, factor.x);cd =  lerp(c, d, factor.x);shdow = lerp(ab, cd, factor.y); //最终阴影值

这样即便单个阴影像素点也可以产生平滑的阴影,并具有典型的线性插值特征:

更大的采样范围

2x2线性插值虽然可以产生平滑过渡的阴影,但没有完全解决锯齿纹理,效果并不理想

这是因为使用的阴影图本身就是栅格化的

处理这个问题的办法是采用更大的采样范围比如3x3\4x4\5x5

其处理思路都是一样的,比如以5x5为例:

首先计算各行的阴影值: row[i]= b+c+d+lerp(a, e, factor.x) , 其中a b c d e为同一行的五个点阴影结果

总阴影值 = ( row1+row2+row3 + lerp(row0, row4, factor.y) ) / 16

5X5采样得到可以产生非常柔和的阴影

不过需要25次纹理采样,性能相比3×3的9次或 4x4的16次要差些

时间: 2024-12-22 07:06:48

实时阴影渲染(二):软阴影的相关文章

UWP Button添加圆角阴影(二)

原文:UWP Button添加圆角阴影(二) 阴影 对于阴影呢,WindowsCommunityToolkit中已经有封装好的DropShadowPanel啦,只要引用Microsoft.Toolkit.Uwp.UI.Controls这个Nuget包就可以使用啦. 直接把阴影套在咱们的圆角Button外面呢,会出现圆角的Button映出直角的阴影的丑陋状况.对于这种情况肯定是有处理方式的. 看DropShadowPanel的源码,对Content的特殊类型做了处理.下面我详细的说下. Compo

实时阴影渲染(一):PSSM平行分割阴影图

PSSM(Parallel Split Shadow Map)平行分割阴影图,是一种根据距离远近采用多个深度纹理渲染阴影的方法 适合用于室外大场景中的平行光比如太阳形成的阴影 本系列需要读者了解基本的深度阴影渲染方面的知识 1 视锥划分 如下图,以采用三个划分为例: 这里将视锥体平行划分为3个区域,代号分别为1.2.3 这三个区域在渲染阴影的时候分别采用不同的阴影图sm1. sm2.sm3 这样将1.2.3对应的距离数据打包为一个float3变量splits.xyz,传入片段shader,然后通

基于CSM和PCF的软阴影实现

断断续续花了两个多礼拜才把这个问题完全搞定,比开始预想的时间多多了,一开始也没想到会碰到这么多的状况,不过好在是都解决了. 阴影技术是三维渲染里面的一个非常重要的课题,实现方式多种多样,最基本的是从光源方向渲一张ShadowMap,简单易行,但是效果很差,锯齿像牛一样大.想要获得更精细的阴影,唯一的办法就是加大SM的分辨率. 事实上我们对远处的阴影要求并没有近处那么高,粗糙点无所谓,反正离得远也看不见,于是在此之上,出现了Cascaded ShadowMap,简称CSM,它的做法是把相机的可视范

.NET实时2D渲染入门·动态时钟

.NET实时2D渲染入门·动态时钟 从小以来"坦克大战"."魂斗罗"等游戏总令我魂牵梦绕.这些游戏的基础就是2D实时渲染,以前没意识,直到后来找到了Direct2D.我的2D实时渲染入门,是从这个动态时钟开始的. 本文将使用我写的"准游戏引擎"FlysEngine完成.它是对Direct2D和.NET库SharpDX浅层次的封装,隐藏了一些细节,简化了一些调用.同时还保留了Direct2D的原汁原味. 本文的最终效果如下: 绘制动态时钟 要绘制动

一个实用的实时毛发渲染及着色方法

一个实用的实时毛发渲染及着色方法 Thorsten scheuermann ATI Resarch,Inc. 翻译:潘曦 (译文里的(pancy:XXX)为译者注) 介绍: 我们提出了一个使用多边形模型的实时毛发渲染算法,并且将其应用于今年SIGGRAPH动画节上的一个实时动画<ruby:The Double Cross>上面.该毛发渲染算法是基于Kajiya-Kay 毛发渲染模型的算法,但是在其之上添加了一个实时的接近现实高光的镜面反射效果(pancy:原始算法可能没有考虑到头发的高光只计算

CSS3实现曲线阴影和翘边阴影

预备知识 DIV+CSS基础 圆角:border-radius 2D变幻:transform:skew && rotate 伪类::before 和 :after 代码 HTML结构代码很简单,CSS内含注释,图片小伙伴们自己替换哈! HTML <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>CSS3

CSs阴影框,Div阴影

<!DOCTYPE HTML><html><head><meta charset="UTF-8"><title>CSs阴影框,Div阴影</title><style type="text/css">*{ margin:0; padding:0; border:0; }body{ padding:4em; font-family:Tahoma, Geneva, sans-serif }

嵌入式Linux基础知识0(什么是真正的实时操作系统--硬实时 软实时)

需求说明:IPC项目需要Linux系统,知识储备 来自:http://blog.csdn.net/zhourui1982/article/details/5282361 阅读精华整理: 1.根据实际应用,可以选择采用硬实时操作系统或软实时操作系统,硬实时当然比软实时好,但是,如果你的公司正在准备开发一款商用软件,那请你注意了,业界公认比较好的VxWorks(WindRiver开发),会花光你本来就很少的银子,而软实时的操作系统,如某些实时Linux,一般是开源免费的,我们公司本来的产品就是基于V

localStorage实现购物车数量单价和总价实时同步(二)

利用localStorage实时显示购物车小计和总价页面显示: 和昨天的原理相同,本地存储同时实时循环计算总价之和,注意循环时候的先清空再计算 Success is getting what you want, happiness is wanting what you get.成功是得其所想,幸福是想其所得! <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&q