Shadow Map ———— PCSS(percentage-closer Soft Shadow)
来源:互联网 发布:淘宝怎么改评价 编辑:程序博客网 时间:2024/06/01 10:18
Shadow Map ———— PCSS(percentage-closer Soft Shadow)
1、PCSS解决了什么问题
传统的PCF每一次采样过滤耗费很大(每次都要遍历附近的几个点,虽然用了泊松分布,但还是不可避免),PCSS算法基本解决了该问题(通过动态计算采样范围,使用FindBlocker剔除非阴影点)
传统的PCF半影不够逼真…PCSS算法通过计算准确的半影范围解决了
4、PCSS的有关你资料:
http://www.cg.tuwien.ac.at/research/publications/2013/SCHWAERZLER-2013-FPCSS/SCHWAERZLER-2013-FPCSS-draft.pdf
http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf
http://developer.download.nvidia.com/SDK/10.5/direct3d/Source/PercentageCloserSoftShadows/doc/PercentageCloserSoftShadows.pdf
http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
https://developer.nvidia.com/gameworks-directx-samples(本文参照的DEMO,soft shadow)
PCSS算法解释:
第一步渲染shadowmap
Z_VSOut LightRender_VS ( Geometry_VSIn IN )
{
Z_VSOut OUT;
float4 WorldPos = mul(IN.Pos, g_world);
OUT.HPosition = mul(WorldPos, g_lightViewProj);
return OUT;
}
第二步、ZPrePass,减少多余的绘制
Geometry_VSOut EyeRender_VS (Geometry_VSIn IN)
{
Geometry_VSOut OUT;
float4 WorldPos = mul(IN.Pos, g_world);
OUT.HPosition = mul(WorldPos, g_viewProj);
OUT.WorldPos = WorldPos;
OUT.Normal = IN.Normal;
OUT.LightPos = mul(WorldPos, g_lightViewProjClip2Tex);
return OUT;
}
DepthStencilState ZTestLess_DS
{
DepthEnable = TRUE;
DepthFunc = LESS;
DepthWriteMask = ALL;
};
第三步:渲染场景
Geometry_VSOut EyeRender_VS (Geometry_VSIn IN)
{
Geometry_VSOut OUT;
float4 WorldPos = mul(IN.Pos, g_world); //将顶点转到光源摄像机的世界矩阵
OUT.HPosition = mul(WorldPos, g_viewProj);
OUT.WorldPos = WorldPos;
OUT.Normal = IN.Normal;
OUT.LightPos = mul(WorldPos, g_lightViewProjClip2Tex); //将顶点转到对应的shadowmap:
//将顶点转到光源摄像机的WVP后,此时顶点:(-1,1),为了转到shadowmap纹理坐标(0,1),还需要乘以一个Clip2Tex矩阵
return OUT;
}
float4 EyeRender_PS (uniform int shadowTechnique, Geometry_VSOut IN) : SV_Target
{
float2 uv = IN.LightPos.xy / IN.LightPos.w; //该顶点对应的shadowmap像素
float z = IN.LightPos.z / IN.LightPos.w; //深度的计算,在PS而不在VS是为了不然插值导致误差
float2 dz_duv = DepthGradient(uv, z); //为了解决Depth Bias问题(待会儿再说)
float4 color = Shade(IN.WorldPos, IN.Normal); //计算颜色,根据法线,光照,纹理等一堆东西计算,简单的光照模型
if (IsBlack(color.rgb)) return color; //如果颜色本身就是黑色…呵呵,直接做阴影
// Eye-space z from the light’s point of view
float zEye = mul(IN.WorldPos, g_lightView).z; //顶点的z转换到光源的View位置(相对于光源的位置),z*WV(还没有进行投影)
float shadow = 1.0f;
switch (shadowTechnique)
{
case 1:
shadow = PCSS_Shadow(uv, z, dz_duv, zEye); //PCSS….
break;
case 2:
shadow = PCF_Shadow(uv, z, dz_duv, zEye); //这是PCF忽略
break;
}
return color * shadow;
}
float PCSS_Shadow(float2 uv, float z, float2 dz_duv, float zEye)
{
// ————————
// STEP 1: blocker search
// ————————
float accumBlockerDepth = 0;
float numBlockers = 0;
//根据顶点到光源的距离,动态计算需要采样的范围(相似三角形如图)
//float2 SearchRegionRadiusUV(float zWorld)
//{
//return g_lightRadiusUV * (zWorld - g_lightZNear) / zWorld;
//}
float2 searchRegionRadiusUV = SearchRegionRadiusUV(zEye);
//寻找最合适的遮挡物,这个感觉对PCF没有太多用途…
//把目标点变换到Light space之后,找到周围点中的遮挡该目标点的点,记录其与光源的距离。
//在搜索了一定的遮挡点之后,我们会根据这些遮挡点计算出一个平均遮挡距离。如果目标点不在阴影中,平均遮挡距离为0,PCSS算法直接返回1.0。
FindBlocker(accumBlockerDepth, numBlockers, g_shadowMap, uv, z, dz_duv, searchRegionRadiusUV);
// Early out if not in the penumbra
if (numBlockers == 0) //完全没有遮挡物
return 1.0;
else if (numBlockers == BLOCKER_SEARCH_COUNT) //完全被遮挡
return 0.0;
// ————————
// STEP 2: penumbra size
// ————————
//取遮挡点的平均值:为何要选取多个遮挡点:
float avgBlockerDepth = accumBlockerDepth / numBlockers;
//现在的avgBlockerDepth在0~1之间,我们要将它映射到Znear~Zfar
float avgBlockerDepthWorld = ZClipToZEye(avgBlockerDepth);
//计算半影大小:
//float2 PenumbraRadiusUV(float zReceiver, float zBlocker)
//{
//return g_lightRadiusUV * (zReceiver - zBlocker) / zBlocker;
//}
float2 penumbraRadiusUV = PenumbraRadiusUV(zEye, avgBlockerDepthWorld);
//Clamp filter width to be >= MinRadius for antialiasing
//float2 ProjectToLightUV(float2 sizeUV, float zWorld)
//{
//return sizeUV * g_lightZNear / zWorld;
//}
float2 filterRadiusUV = ProjectToLightUV(penumbraRadiusUV, zEye);
// ————————
// STEP 3: filtering
// ————————
return PCF_Filter(uv, z, dz_duv, filterRadiusUV);
}
//进行PCF采样,一堆加起来
float PCF_Filter(float2 uv, float z0, float2 dz_duv, float2 filterRadiusUV)
{
float sum = 0;
ifdef USE_POISSON //使用泊松分布?
for (int i = 0; i < PCF_POISSON_COUNT; ++i)
{
float2 offset = PCF_POISSON[i] * filterRadiusUV; //将半径乘以泊松分布的值就是偏移值
float z = BiasedZ(z0, dz_duv, offset); //处理Bias问题
//SampleCmpLevelZero:小于Z的才会采样 https://msdn.microsoft.com/zh-cn/library/windows/apps/dn263156.aspx
//
//SamplerComparisonState PCF_Sampler
//{
//ComparisonFunc = LESS; 这里决定了SampleCmpLevelZero的比较方法:则比较测试通过时固有函数会返回零;这表示像素位于阴影中。
//Filter = COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
//AddressU = Border;
//AddressV = Border;
//BorderColor = float4(MAX_LINEAR_DEPTH, 0, 0, 0);
//};
sum += g_shadowMap.SampleCmpLevelZero(PCF_Sampler, uv + offset, z);
}
else
float2 stepUV = filterRadiusUV / PCF_FILTER_STEP_COUNT;
for (float x = -PCF_FILTER_STEP_COUNT; x <= PCF_FILTER_STEP_COUNT; ++x)
{
for (float y = -PCF_FILTER_STEP_COUNT; y <= PCF_FILTER_STEP_COUNT; ++y)
{
float2 offset = float2(x, y) * stepUV;
float z = BiasedZ(z0, dz_duv, offset);
sum += g_shadowMap.SampleCmpLevelZero(PCF_Sampler, uv + offset, z);
}
}
endif
return sum / PCF_COUNT; //取得平均值
}
4、关于Depth bias问题(http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/Isidoro-ShadowMapping.pdf)
//float2 uv = IN.LightPos.xy / IN.LightPos.w; //该顶点对应的shadowmap像素
//float z = IN.LightPos.z / IN.LightPos.w; //深度的计算,在PS而不在VS是为了不然插值导致误差
//计算改uv所处地方的z的变化情况(偏导数)
//ddx,ddy是系统的api用于算Screen Space的偏导数…
//这里就是利用传说中的雅可比矩阵将偏导数算出来~
float2 DepthGradient(float2 uv, float z)
{
float2 dz_duv = 0;
float3 duvdist_dx = ddfloat3(uv,z));
float3 duvdist_dy = ddy(float3(uv,z));
dz_duv.x = duvdist_dy.y * duvdist_dx.z;
dz_duv.x -= duvdist_dx.y * duvdist_dy.z;
dz_duv.y = duvdist_dx.x * duvdist_dy.z;
dz_duv.y -= duvdist_dy.x * duvdist_dx.z;
float det = (duvdist_dx.x * duvdist_dy.y) - (duvdist_dx.y * duvdist_dy.x);
dz_duv /= det;
return dz_duv;
}
//利用z的偏导数动态计算准确的bias
float BiasedZ(float z0, float2 dz_duv, float2 offset)
{
return z0 + dot(dz_duv, offset);
}
- Shadow Map ———— PCSS(percentage-closer Soft Shadow)
- Shadow Map ———— PCF(percentage-closer filtering)
- 随笔——Shadow
- 关于box—shadow
- 标签—box-shadow
- 配置文件——/etc/shadow
- Shadow Map & Shadow Volume
- Shadow Map & Shadow Volume
- Shadow Map & Shadow Volume
- shadow map
- shadow map
- CSS3的文字阴影—text-shadow
- CSS3的文字阴影—text-shadow
- CSS3的文字阴影—text-shadow
- CSS3的文字阴影—text-shadow
- CSS3的文字阴影—text-shadow
- CSS3的文字阴影—text-shadow
- CSS3的文字阴影—Text-Shadow
- disney BRDF代码解释
- TangentSpace的法线转换到ViewSpace
- SHADOWMAP
- Shadow Map ———— PCF(percentage-closer filtering)
- liunx误删文件回复方式
- Shadow Map ———— PCSS(percentage-closer Soft Shadow)
- 如何在CodeBlocks中添加头文件graphics.h
- liunx删除了之后没有释放空间
- 推荐系统大师项亮都来了,就问你约不约?
- 从inotify机制说到FileObserver实现原理
- 网络编程学习笔记一:Socket编程
- 如何在Java中构造多维动态数组以及多维动态数组的使用
- HDU 3974 Assign the task(并查集)
- Spring集成Shiro HelloWorld之初步实现登陆及验证