Home Forums Games202-高质量实时渲染 [作业1]关于PCSS边界明显的Tip

Viewing 4 reply threads
  • Author
    Posts
    • #8085 Score: 3
      JH
      Participant
      3 pts

      在完成PCSS的过程中,我的结果一直存在边界明显且部分区域过亮的问题(见图1),在群里好像也看到过类似的问题。其可能的原因是在求解PCF的filter size的时候,使用了normalized depth(范围[0,1])而不是linearized depth(view/eye space depth,范围[zNear, zFar])。修正后结果明显有所改善(见图2)。希望这个能对大家debug有所帮助:)

      This post has received 3 votes up.
      Attachments:
      You must be logged in to view attached files.
    • #8088 Score: 0
      JH
      Participant
      3 pts

      linear depth计算:https://learnopengl.com/Advanced-OpenGL/Depth-testing

      • This reply was modified 2 years, 11 months ago by JH.
    • #8091 Score: 0
      夜影
      Participant

      感谢大佬 我说怎么之前一直不对 传进来的点是经过投影变换的 而shadowmap上的点是正交投影出来的 肯定怎么算怎么错

    • #8206 Score: 0
      happyfire
      Participant
      4 pts

      请问能说清楚一些吗?最好能上代码。
      PCF里面比较的是shadowmap中的深度和当前片段在LightSpace中的深度。这两个深度都是正交投影计算出来的吧,而且使用的都是LightMVP矩阵。
      区别只是shadowmap中的深度是从gl_FragCoord.z读取出来的,这个值是range到了0~1(默认)。而用来和shadowmap比较的深度计算是vPositionFromLight = uLightMVP * vec4(aVertexPosition, 1.0);
      这个就是clip space的,当然对于正交投影,w=1,因此就是NDC的。因此范围是[-1,1],因此只要转换到[0,1]就可以和shadow map解压出来的深度比较了。
      如果我分析的没问题的话,这里面找不到需要变换到线性深度(eye space z,范围[n,f])的地方呀?而且用的都是一样的矩阵,即便不是正交投影,是透视投影,应该也没问题吧?

      另外最终出的效果和采样数,filterSize都有关系,你确定其他参数都没变?

      • #8207 Score: 0
        happyfire
        Participant
        4 pts

        Sorry,看成PCF了,不过意思一样的。(这个帖子不能编辑吗?没找到EDIT..)
        findBlocker和PCF里面都是用的一样的z,可能你修改了findBlocker,不过这个函数真的是改一点东西影响都很大,所以你改了z应该就是会有不同的效果。但是我觉得应该和linear depth没关系的,请批评指正!

        • #8209 Score: 0
          JH
          Participant
          3 pts

          不好意思我可能有点没说清楚…我的意思是修改PCSS中step2 penumbra size的计算,而所有关于shadow map中深度的比较都是用的[0,1]范围的深度这个没错。
          这个是我原来的代码

          float filterSize = (coords.z / avgBlockerDepth - 1.0) * LIGHT_WIDTH_UV;
          float ret = PCF(shadowMap, coords, filterSize);

          其中coord.z和avgBlockerDepth都是[0,1]的值。
          这个是我更新后的代码

          float vsReceiverDepth = linearizeDepth(coords.z);
           float vsBlockerDepth = linearizeDepth(avgBlockerDepth);
           float filterSize = (vsReceiverDepth / vsBlockerDepth - 1.0) * LIGHT_WIDTH_UV;
           float ret = PCF(shadowMap, coords, filterSize);

          简单来说就是把这里normalized的depth转换到linear depth再求解filterSize。我非常同意你说的有可能改一点就会让结果差很多,比如你可以加一个scalar来进行调参,不过这样并不能保证是physically correct的。我的理解是求解filterSize的本质是相似三角形,不过当所有距离都进行来非线性变换(从linear depth变成[0,1])之后相似三角形的比例关系并不能保证一定满足,所以这里利用linear depth求解是比较合理的。实践上来看我自己的测试也得到了更好的效果,同时我也参考了一些别人的实现,包括Nvidia的实现(http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf),感觉大多都是使用linear depth来计算的。
          这些就是我大致的理解和推测,如果有问题的话欢迎继续讨论:)

          • #8259 Score: 0
            happyfire
            Participant
            4 pts

            了解了,你应该是用了透视投影,然后你的zReceiver和zBlocker都不是线性的,所以你需要转到线性吧。这没问题。
            我是跟着课程走的,计算penumbra就是用的一个简单的相似三角形,当然用的是正交投影,所以zReceiver和zBlocker都是线性的,因此这么计算:
            float penumbra = (zReceiver – zBlocker) * LIGHT_WIDTH / zBlocker;
            应该没有物理上不正确吧

    • #8213 Score: 0
      shengjie
      Participant

      如果你用的是正交投影矩阵,深度就是线性的,虽然数值范围需要从[-1,1]变换到[0,1]。看你的描述,你是用了perspective projection?
      findBlock的搜索范围确实应该设大一点。但step2-3 z的绝对值不重要,只要z是线性的,求相似三角形比值只和z的相对值有关。
      我认为其他的坑点在
      1.8个uint表示float的数值精度问题
      2.地板自遮挡
      需要好好调参一下eps

      • #8214 Score: 0
        JH
        Participant
        3 pts

        我觉得你说有道理,而且directional light也应该是用正交投影,所以不需要去做linearization。我这里的操作应该只能针对使用透视投影的光源。感谢指正!

Viewing 4 reply threads
  • You must be logged in to reply to this topic.