周笔记(9/52)

来源:互联网 发布:java编程思想 新手 编辑:程序博客网 时间:2024/05/21 08:03

Shadow Mapping

要点

  1. 整体而言,先从光源的视角渲染一个深度贴图,然后在第二个pass里,用这个深度贴图作为对比,来决定渲染阴影的地方。
    • 这个以光源为视角的view matrix来选择合适的proj matrix
      • 正交投影(orthographic projection):可用于平行光
      • 透视投影:可用于点光源
    • 这个中间的深度贴图的 Format 设置为 R24G8_TYPELESS,因为会先后绑定为D24S8(渲染深度图)和R24X8(在PS中作为source)。
    • 在处理多个RenderTarget的时候,总是可以通过申请多个RenderTarget,然后通过绑定新的来解除旧的
    • 只需设置depthstencil target,无需设置 render target。这会有优化。
    • 手动对视锥之外的物体进行剔除
  2. 投影纹理坐标:如何为每个像素指定一个纹理坐标,从而使他看上去就像是被投影在一个物体上一样?
    • 先把点p投影到光线的投影窗口,转换到NDC空间
    • 然后把投影后的坐标从NDC空间转换到纹理空间,从而变换为纹理坐标
  3. 偏置(biasing)和走样(aliasing)
    • 阴影斑(shadow acne)
      • 由于shadowmap只是光源视角的离散的深度采样,无法精确满足摄像机视角的所有像素的深度比较。会导致非阴影位置出现阶梯条纹。
      • 根据法线角度可知深度图和渲染时的最大误差,设置误差上限,可以减轻这种走样。 (peter-panning)但是误差上限如果太大,阴影就会明显偏移根部。但是在法线和光源几乎垂直的时候,误差上限需要比较大。现在图形卡对这件事有了专门的支持——根据坡度缩放偏置(slope-scaled-bias)的光栅阶段的属性:
      • D3D11_RASTERIZER_DESC
        • DepthBias:一个固定的偏移
        • DepthBiasClamp:最大偏移钳位值
        • SlopScaledDepthBias:根据光源透视下的斜率,控制深度偏移
        • 注:如果深度缓存是UNORM格式或者没有深度缓存,那么偏移值为:(float)DepthBias * r + SlopeScaledDepthBias * MaxDepthSlope,其中r为深度缓存的格式的误差限。
          问题:上边的MaxDepthSlope在哪里定义的?
    • PCF滤波(percentage closer filtering)
      • shadow map 的采样,并非是双线性插值,对四个点的深度值进行平均显然不对,同样,mipmap也会产生错误的结果。应当对结果进行插值,而非深度值——亦即PCF滤波:对分辨率下的相邻四个点进行采样并计算阴影,然后将结果进行插值。
      • DX11新增:SampleCmpLevelZero
        • 只读取第一级mipmap,且自动做一个4-tap的双线性插值的PCF
        • Filter = COMPARISON_MIN_MAG_LINEAR_MIP_POINT
        • Format = R32_FLOAT_X8X24_TYPELESS/R32_FLOAT/R24_UNORM_X8_TYPELESS/R16_UNORM
      • 使用多个PCF可以将4-tap提升到更大,但太大的话会重新造成阴影漂移
      • 采样是比较贵的,可以通过只在阴影边缘采样来提高效率。
      • 不需要一定是方形的滤波
      • 注意对于前边介绍的曲面细分阶段,生成shadowmap的时候,在light的视角所做的细分要和摄像机视角时的一样。不过如果不是偏移很大的话也可以省略。精确度换速度。
    • PCF滤波在采样增多时的问题
      • 采样的边长增大时,因为采样点未必是在同一直线上,所以会引起错误的结果——导致本来在阴影里的点,结果判定只有部分在阴影里,亦即阴影漂移
      • 通过计算x和y方向的导数(斜率),从而计算在 z+delta_z 处的深度值,来解决上述漂移问题
0 0
原创粉丝点击