pcss 软阴影
PCF
Percentage Closer Filtering:PCF是一种用于阴影反锯齿的方法,本身不是软阴影方法。
算法流程说明:
- Perform multiple (e.g. 7x7) depth
comparisons for each fragment - Then, averages results of comparisons
- e.g. for point P on the floor,
- compare its depth with all pixels
in the red box, e.g. 3x3- get the compared results, e.g.
1, 0, 1,
1, 0, 1,
1, 1, 0,- take avg. to get visibility, e.g. 0.667

pcf使用的过滤size越大,得到的阴影结果越模糊,范围也被扩大。
code:
vec2 poissonDisk[NUM_SAMPLES];
void poissonDiskSamples( const in vec2 randomSeed ) {
float ANGLE_STEP = PI2 * float( NUM_RINGS ) / float( NUM_SAMPLES );
float INV_NUM_SAMPLES = 1.0 / float( NUM_SAMPLES );
float angle = rand_2to1( randomSeed ) * PI2;
float radius = INV_NUM_SAMPLES;
float radiusStep = radius;
for( int i = 0; i < NUM_SAMPLES; i ++ ) {
poissonDisk[i] = vec2( cos( angle ), sin( angle ) ) * pow( radius, 0.75 );
radius += radiusStep;
angle += ANGLE_STEP;
}
}
float PCF(sampler2D shadowMap, vec4 coords,float filterSize) {
if(coords.x <-1.0 || coords.y>1.0 || coords.y<-1.0 || coords.y>1.0){
//不在灯光相机视野中,默认完全照亮
return 1.0;
}
float pixelSize = 1.0/2048.0;
float count = 0.0;
poissonDiskSamples(vec2(coords.x,coords.y));
for(int i=0;i<NUM_SAMPLES;i++){
vec2 uv = poissonDisk[i]*pixelSize*filterSize + coords.xy;
if(uv.x <-1.0 || uv.y>1.0 || uv.y<-1.0 || uv.y>1.0){
//不在灯光相机视野中,默认完全照亮
return 1.0;
}
float dNearest = sampleDepth(shadowMap, uv) * Z_RANGE;
float d = (coords.z+1.0)/2.0*Z_RANGE;//[-1,1]->[0,1.0]
if(!(d > dNearest+Z_EPS)){//pcf 返回可见性指标
count += 1.0;
}
}
float res = count/float(NUM_SAMPLES);
return res;
}
result:

PCF_8X8

PCF_64X64
PCSS
Percentage Closer Soft Shadows
通过观察可知阴影的软硬与阴影距离阴影投掷物的距离有关,距离越近,阴影越实(硬);距离越远,阴影越虚(软)。因此可以在PCF的基础上,动态调整filter size从而实现软阴影效果。
关键在于如何选择filter size,filter size和阴影距离阴影投掷物的距离(d_receiver-d_blocker)和遮挡物距离光源的距离(d_blocker)有关, 如下图所示:

其中W_penumbra就是面光源形成的软阴影范围,也就是pcf使用的filter size。
通过三角相似关系,可以得到下面的数量关系:
\]
其中W_light为光源宽度,在代码中可以取常量;d_receiver是物体深度,可以在shader中uLightMVP*aPosition计算得到;
d_blocker是遮挡物深度可以从pass1中记录的最近物体深度读取,读取一定范围内的遮挡物的平均深度,这个范围需要取多大?
1.Can be set constant (e.g. 5x5), but can be better with heuristics
2.理论上的blocker search region:
依赖于光源面积大小和观察点距离光源的距离,即图中红虚线构成四棱锥范围。有一个问题是从面光源的不同点看场景会有不同的shadw map,如果只用一个shadw map进行采样,本身这里是精确分析,最后的结果又变成了近似。
最后得到PCSS的算法流程:
The complete algorithm of PCSS
- Step 1: Blocker search
(getting the average blocker depth in a certain region) - Step 2: Penumbra estimation
(use the average blocker depth to determine filter size) - Step 3: Percentage Closer Filtering
code:
vec2 findBlocker( sampler2D shadowMap, vec2 uv, float zReceiver ) {
if(uv.x <-1.0 || uv.y>1.0 || uv.y<-1.0 || uv.y>1.0){
//不在灯光相机视野中,默认没有遮挡物
return vec2(0.0,0.0);
}
//uniformDiskSamples(uv);
float pixelSize = 1.0/2048.0;
float db = 0.0;
float ds = 0.0;
//启发式的得到搜索范围,单位:像素
float searchSize = 0.0;
searchSize = LIGHT_WIDTH*(zReceiver-NEAR_PLANE)/zReceiver;
searchSize = searchSize/200.0/pixelSize;
searchSize *= 1.5;
//固定
//searchSize = 64.0;// 64.0;
float count = 0.0;
poissonDiskSamples(vec2(uv.x*9999.0+8888.0,uv.y*7777.0+12345.0));
for(int i = 0; i < NUM_SAMPLES; i++){
vec2 uv2 = poissonDisk[i]*pixelSize*searchSize + uv;
if(uv2.x <-1.0 || uv2.y>1.0 || uv2.y<-1.0 || uv2.y>1.0){
//不在灯光相机视野中,默认没有遮挡物
return vec2(0.0,0.0);
}
float d = sampleDepth(shadowMap, uv2);
d = d*Z_RANGE;
if(d < zReceiver-5.0 ){
db += d;
count += 1.0;
}
}
db = db / count;
ds = zReceiver - db;
//db = db / float(NUM_SAMPLES);
//ds = ds / float(NUM_SAMPLES);
return vec2(db,ds);
}
float PCF(sampler2D shadowMap, vec4 coords,float filterSize) {
if(coords.x <-1.0 || coords.y>1.0 || coords.y<-1.0 || coords.y>1.0){
//不在灯光相机视野中,默认完全照亮
return 1.0;
}
float pixelSize = 1.0/2048.0;
float count = 0.0;
poissonDiskSamples(vec2(coords.x,coords.y));
for(int i=0;i<NUM_SAMPLES;i++){
vec2 uv = poissonDisk[i]*pixelSize*filterSize + coords.xy;
if(uv.x <-1.0 || uv.y>1.0 || uv.y<-1.0 || uv.y>1.0){
//不在灯光相机视野中,默认完全照亮
return 1.0;
}
float dNearest = sampleDepth(shadowMap, uv) * Z_RANGE;
float d = (coords.z+1.0)/2.0*Z_RANGE;//[-1,1]->[0,1.0]
if(!(d > dNearest+10.0)){//pcf 返回可见性指标
count += 1.0;
}
}
float res = count/float(NUM_SAMPLES);
return res;
}
float PCSS(sampler2D shadowMap, vec4 coords){
float d_r = (coords.z+1.0)/2.0*Z_RANGE;// d_receiver
float pixelSize = 1.0/2048.0;
float d_b = 0.0;//d_blocker
float d_s = 0.0;//average d_reciver - d_blocker
float filterSize = 16.0;
// STEP 1: avgblocker depth
vec2 vB = findBlocker(shadowMap,coords.xy,d_r);
d_b = vB.x;
d_s = vB.y;
//return d_b/Z_RANGE;
//return d_s/Z_RANGE;
if(d_s<=EPS){
//不受遮挡,可见性为1
return 1.0;
}
// STEP 2: penumbra size
//float wp = pow(d_s / d_b,2.0) * LIGHT_WIDTH; // d_s / d_b* LIGHT_WIDTH;//
float wp = d_s / d_b* LIGHT_WIDTH;
//float wp = (dr/db-1.0) * L_WIDTH;
float penumbraPixelSize = wp/200.0/pixelSize;//200是正交相机里设定的窗口范围
//return penumbraPixelSize/100.0;
// STEP 3: filtering
//filterSize = penumbraPixelSize+8.0;
filterSize = penumbraPixelSize;
float res = PCF(shadowMap, coords, filterSize);
return res;
}
result:

PCF 64X64

PCSS
pcss 软阴影的更多相关文章
- DirectX11 With Windows SDK--38 级联阴影映射(CSM)
前言 在31章我们曾经实现过阴影映射,但是受到阴影贴图精度的限制,只能在场景中相当有限的范围内投射阴影.本章我们将以微软提供的例子和博客作为切入点,学习如何解决阴影中出现的Atrifacts: 边缘闪 ...
- DirectX11 With Windows SDK--39 阴影技术(VSM、ESM)
前言 上一章我们介绍了级联阴影贴图.刚开始的时候我尝试了给CSM直接加上PCSS,但不管怎么调难以达到说得过去的效果.然后文章越翻越觉得阴影就是一个巨大的坑,考虑到时间关系,本章只实现了方差阴影贴图( ...
- WebGL光照阴影映射
原文地址:WebGL光照阴影映射 经过前面的学习,webgl的基本功能都已经掌握了,我们不仅掌握了着色器的编写,图形的绘制,矩阵的变换,添加光照,还通过对webgl的基础api封装,编写出了便 ...
- 转:体积阴影(Shadow Volumes)生成算法
下面以最快的速度简单谈谈阴影生成技术,目前普遍采用的一般有三种:Planar Shadow.Shadow Mapping和Shadow Volume,前者类似投影,计算最简单,缺点只能绘制抛射在平面上 ...
- Unity QualitySettings.shadows 阴影
QualitySettings.shadows 阴影 public static ShadowQuality shadows; Description 描述: 要使用的实时阴影类型. 这就决定了应该使 ...
- Unity3D中使用Projector生成阴影
在Unity3D中使用Projector实现动态阴影 无意中看见一篇博客叙述使用Projector实现动态阴影可以在移动平台拥有非常好的性能,遂按照其想法实现了一遍,发现其中竟有许多细节,写下这篇博客 ...
- Shadow Map阴影贴图技术之探 【转】
这两天勉勉强强把一个shadowmap的demo做出来了.参考资料多,苦头可不少.Shadow Map技术是目前与Shadow Volume技术并行的传统阴影渲染技术,而且在游戏领域可谓占很大优势.本 ...
- Unite 2018 | 《崩坏3》:在Unity中实现高品质的卡通渲染(上)
http://forum.china.unity3d.com/thread-32271-1-1.html 我们已经发布了Unite 2018 江毅冰的<发条乐师>.Hit-Point的&l ...
- 基于Unity 5的次世代卡通渲染技术 -- Unite 2017 米哈游总监贺甲分享实录
在5月12日Unite2017开发者大会上,米哈游技术总监兼美术指导贺甲进行了主题为次世代卡通渲染的演讲.一下为详细分享内容: 大家好,首先自我介绍一下,我叫贺甲,在米哈游担任技术总监和美术指导工作, ...
- 3D游戏中的画质与效率适配
哪里来的需求? 众所周知,由于不同的设备配置不同.导致其CPU和GPU处理能力有高有低.同样的游戏想要在所有设备上运行流畅且画面精美,是不可能的.这就需要我们针对不同的设备能力进行画质调节,以保证 ...
随机推荐
- 探索Amazon S3:存储解决方案的基石(Amazon S3使用记录)
探索Amazon S3:存储解决方案的基石 本文为上一篇minio使用的衍生版 相关链接:1.https://www.cnblogs.com/ComfortableM/p/18286363 2.h ...
- pycham配置GitHub环境【一文了解window上GitHub的基本操作】
基础用户设置[包含用户登录.密钥生成] 网络配置 外观->系统设置->https代理->检查连接 我这里测试网址是GitHub,连接成功即可后续操作[不成功别找我,我也不知道] gi ...
- 算法·理论:KMP 学习笔记
\(\text{KMP}\) 笔记! 上次比赛,出题人出了一个 \(\text{KMP}\) 模板,我敲了个 \(\text{SAM}\) 跑了,但是学长给的好题中又有很多 \(\text{KMP}\ ...
- 强化学习运行环境,atari 2600 游戏模拟器,atari-py库 —— 无法运行游戏,pacman,surround,报错: Segmentation fault (core dumped)
atari2600运行环境: https://github.com/openai/atari-py 安装环境,以及导入 rom文件这里不进行介绍(前文已介绍): 测试游戏环境rom文件能否正常加载如内 ...
- 读博期间的宿舍 && 行李打包 —— 大连开发区校区
=============================================
- 在使用pytorch官方给出的torchvision中的预训练模型参数时为保证收敛性要求使用原始的数据预处理方式
本文主要内容如题: 在使用pytorch官方给出的torchvision中的预训练模型参数时为保证收敛性要求使用原始的数据预处理方式 具体的pytorch官方讨论: https://github.co ...
- java多线程之-CAS无锁
1.背景 加锁确实能解决线程并发的的问题,但是会造成线程阻塞等待等问题 那么有没有一种方法,既可以线程安全,又不会造成线程阻塞呢? 答案是肯定的......请看如下案例 注意:重要的文字说明,写在了代 ...
- Grafana的仪表盘URL参数设置
转载请注明出处: 在调试grafana时,需要对grafana进行share的url图表进行一些自定义设置,总结下常用的参数 参考网站:https://grafana.com/docs/grafana ...
- C# 读取DBF文件到Datatable
此种方式不依赖与任何驱动,第三方插件. 核心代码TDbfTable如下: using System; using System.Collections.Generic; using System.Te ...
- Adobe Photoshop cc2022 Mac中文破解版下载安装
PS2024 for Mac,我这个版本是Mac版25.2,大小4.03G,支持intel/M1/M2/M3芯片,最低系统需求:13.4以上,不限速下载地址还是放在最后. 然后安装总共有三个步骤,尤其 ...
