• 实时阴影渲染(三):软阴影深度校正


    上一篇介绍的软阴影技术已经可以生成很好的软阴影

    再结合第一篇介绍的PSSM就可以实现不错的阴影效果

    但在实际应用中的会遇到一个很重要的问题:阴影渲染中的自阴影问题

    这种问题的产生的原因和锯齿原因类似:

    视空间中的像素和灯光空间像素不一致

    比如视空间中的一块区域(多个像素)在渲染阴影时对应同一个像素,因而仅产生一个深度值(中心深度)

    对于灯光空间中倾斜的三角面来说,这些值是应该不同的

    一般对这种问题的解决办法是通过一个小的深度偏移量,或者再通过背面渲染缓解这种问题

     而采用多个采样的深度软阴影技术,这种问题会更加显著,这样仅采用一个小小的偏移就不够了

    但如果深度偏移太大又会导致本该出现阴影的地方没有阴影

    下图以水平3像素的软阴影采样为例说明这种问题:

    如上图,假设场景中仅存在ABC所在的平面,ABC为相邻的三个阴影像素,

    采用水平3采样计算c点阴影时,会得到强度为0.333的阴影,因为 depth(a)>depth(c)+depthBias

    这样渲染那出来的结果是:整个平面都在强度为0.333阴影中;而实际上整个平面都不应该有阴影

     除非我们将depthBias设的足够大,但AB平面越倾斜、采样数越多所需要的depthBias的值就越大

    这样通过增大depthBias的值是不能解决问题的

    思考一下,如果我们能知道ac点的深度差dz = depth(c)-depth(a)的值,就可以通过计算比较出:

      depth(a) - dz  <   depth(c)+depthBias;

      depth(c)  <     depth(c)+depthBias;

      depth(b) + dz <   depth(c)+depthBias;

    从而得出整个平面都不在阴影中的结果

    计算深度差dz

    在GPU设计体系中,片段程序执行时并不知道其它片段的信息

    但好在GPU的实现中提供了ddx ddy两个例外的指令,通过这两条指令可以得出相邻片段间的偏导,也就是相邻片段之间的数据差值

    因为实际采样一般为3*3,5*5,我们需要计算水平和垂直两个方向上的深度差zx、zy

    假设在当前片段所在三角面对应一个阴影纹理像素的深度差为float2(zx, zy), 阴影纹理宽高为float2(w,h)

    通过求解二元一次方程组:

      ddx(uv) * float2(zx, zy) * float2(w,h)= ddx(z)

      ddy(uv) * float2(zx, zy) *float2(w,h)= ddy(z)

     就可以得到zx、zy

    注:uv  为当前片段的深度纹理uv坐标, z 为当前片段深度值 ,这些都是已知

    2017-9-22修改: +方程求解说明

    之前的方程写的意思不明确,想表达的是:

        ddx(u)*zx*w + ddx(v)*zy*h = ddx(z)   即 x方向z变化量【ddx(z)】 = x方向u变化量【ddx(u)】 * 单位u变化对应的z变化量【zx】 +  x向v变化量【ddx(v)】 * 单位v变化对应的z变化量【zy】

        ddy(u)*zx*w + ddy(v)*zy*h = ddy(z)   同上

    求解我就不写了,相当于求解 方程组:

    a* zx + b * zy = c

    d* zx + e * zy = f 即利用a b c d e f六个已知量,计算两个未知量zxzy,但写出来挺长,还不如自己推导便于理解

     方程ddx(u)*zx*w + ddx(v)*zy*h = ddx(z) 成立的意思是:

    当前片段x方向变化对应纹理坐标uv两个变化,而阴影纹理u、v的变化分别产生各自的z变化值,累加就是ddx(z)

  • 相关阅读:
    阅读笔记
    学习小记
    networkx学习笔记
    ORM查询简化
    redis等缓存
    redis相关缓存知识
    Centos7网络配置
    redis安装详细
    redis安装详细
    mobaxterm使用手册
  • 原文地址:https://www.cnblogs.com/wiki3d/p/shadow3.html
Copyright © 2020-2023  润新知