Home Forums Games202-高质量实时渲染 作业资料 & 代码勘误

Viewing 21 reply threads
  • Author
    Posts
    • #8322 Score: 11
      YunHsiao
      Participant
      19 pts

      可能是助教同学们时间的确紧张,每次作业框架中都会存在一些问题,多多少少影响完成作业体验。希望在这里和大家一起把问题统一整理一下,以便后来的同学们能把精力更聚焦在算法实现本身而不是调试工程细节问题上。

      按一般公开课的 honor code,任何课程讨论是不适合直接贴代码答案的,所以请尽量把问题描述清楚,且只贴框架本身的问题和代码,不要涉及作业考察内容。

      我会先列一下我在完成作业过程中遇到和解决的框架问题,如果有不准确或是不完整的地方,欢迎讨论补充。

      This post has received 11 votes up.
    • #8323 Score: 0
      YunHsiao
      Participant
      19 pts

      ## 作业 1

      * 框架提供的 unpack 函数算法实现不准确,在不加 bias 时,会导致严重的 banding(地面一半白一半黑而不是典型的 z-fighting 效果),一定程度上影响作业调试。
      准确算法参考[这里](https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/):
      `cpp
      // shaders/shadowShader/shadowFragment.glsl
      vec4 pack (float depth) {
      // 使用rgba 4字节共32位来存储z值,1个字节精度为1/256
      const vec4 bitShift = vec4(1.0, 255.0, 65025.0, 16581375.0);
      const vec4 bitMask = vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0);
      // gl_FragCoord:片元的坐标,fract():返回数值的小数部分
      vec4 rgbaDepth = fract(depth * bitShift); //计算每个点的z值
      rgbaDepth -= rgbaDepth.gbaa * bitMask; // Cut off the value which do not fit in 8 bits
      return rgbaDepth;
      }

      // shaders/phongShader/phongFragment.glsl
      float unpack(vec4 rgbaDepth) {
      const vec4 bitShift = vec4(1.0, 1/255.0, 1/65025.0, 1/16581375.0);
      return dot(rgbaDepth, bitShift);
      }
      `
      * 课程框架的清屏操作代码不完整,实际上是没有真正每帧清屏的。glClearColor 和 glClearDepth 只是指定清屏颜色,实际的执行还得再加一句 glClear。
      `js
      // renderers/WebGLRenderer.js
      gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
      gl.clearDepth(1.0); // Clear everything
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
      `
      清屏操作在处理平面上的一些 artefact 时可以用上。
      * 在课程视频 P3 80:26 时,闫老师的原话是:”……也就意味着如果 light 离你比较远,也就是在 shadowmap 上找一个比较小的范围”。这里应该是口误,light 越远应该查询范围越大。这个细节没有在课程任何其他地方提及,除非自己翻一下 N 厂的原论文实现,考虑到不是每个同学都会这么做,所以这个口误影响比较大。

    • #8324 Score: 1
      YunHsiao
      Participant
      19 pts

      ## 作业 2

      * prt 框架,CMake 生成的 MSVC 项目默认对代码中的中文内容支持有问题(会吞换行符),导致编译报 lambda 没有返回值的错,解决方案是在 prt/CMakeLists.txt 112 行添加:
      `cmake
      target_compile_options(nori PUBLIC /utf-8) # MSVC unicode support
      `
      * WebGL 框架,每帧每个模型都在创建和上传相同的 vertex buffer,因而导致这回作业框架的性能相对很低,而且静置一段时间后页面还会随机崩溃。解决办法是提前 cache 这块内存,每帧只需要绑定,不需要创建和上传。
      `js
      // renderers/MeshRender.js insert to the back of constructor
      if (material.attribs.some((a) => a === ‘aPrecomputeLT’)) {
      this.#precomputeLTBuffer = gl.createBuffer();
      this.#currentEnvmap = -1;
      }

      // replace renderers/MeshRender.js:204-211
      // Bind attribute mat3 – LT
      if (this.#precomputeLTBuffer) {
      gl.bindBuffer(gl.ARRAY_BUFFER, this.#precomputeLTBuffer);

      if (this.#currentEnvmap !== guiParams.envmapId) {
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(precomputeLT[guiParams.envmapId]), gl.STATIC_DRAW);
      this.#currentEnvmap = guiParams.envmapId;
      }

      for (var ii = 0; ii < 3; ++ii) {
      gl.enableVertexAttribArray(this.shader.program.attribs[‘aPrecomputeLT’] + ii);
      gl.vertexAttribPointer(this.shader.program.attribs[‘aPrecomputeLT’] + ii, 3, gl.FLOAT, false, 36, ii * 12);
      }
      }
      `
      * WebGL 框架,不管 shader 里是否实际用到了 mesh 里的 attribute,统一会执行 vertexAttribPoint 等操作,这在比如 shader 里没用使用 aNormalPosition 时,由于反射没取到 location 信息,接下来每帧都会产生 index out of range 报错。不影响运行效果,但可能对作业调试产生干扰。
      * 作业描述中的效果截图都没有考虑伽马校正和积分系数 pi 的问题,所以效果其实是不正确的。可以不参考这个截图。

      This post has received 1 vote up.
    • #8325 Score: 0
      YunHsiao
      Participant
      19 pts

      <h2 id=”-1″>作业 1</h2>

      • <p>框架提供的 unpack 函数算法实现不准确,在不加 bias 时,会导致严重的 banding(地面一半白一半黑而不是典型的 z-fighting 效果),一定程度上影响作业调试。
        准确算法参考这里:</p>

        <code class="lang-cpp"><span class="hljs-comment">// shaders/shadowShader/shadowFragment.glsl</span>
        vec4 pack (<span class="hljs-type">float</span> depth) {
            <span class="hljs-comment">// 使用rgba 4字节共32位来存储z值,1个字节精度为1/256</span>
            const vec4 bitShift = vec4(<span class="hljs-number">1.0</span>, <span class="hljs-number">255.0</span>, <span class="hljs-number">65025.0</span>, <span class="hljs-number">16581375.0</span>);
            const vec4 bitMask = vec4(<span class="hljs-number">1.0</span>/<span class="hljs-number">255.0</span>, <span class="hljs-number">1.0</span>/<span class="hljs-number">255.0</span>, <span class="hljs-number">1.0</span>/<span class="hljs-number">255.0</span>, <span class="hljs-number">0.0</span>);
            <span class="hljs-comment">// gl_FragCoord:片元的坐标,fract():返回数值的小数部分</span>
            vec4 rgbaDepth = fract(depth * bitShift); <span class="hljs-comment">//计算每个点的z值</span>
            rgbaDepth -= rgbaDepth.gbaa * bitMask; <span class="hljs-comment">// Cut off the value which do not fit in 8 bits</span>
            return rgbaDepth;
        }
        
        <span class="hljs-comment">// shaders/phongShader/phongFragment.glsl</span>
        <span class="hljs-type">float</span> unpack(vec4 rgbaDepth) {
            const vec4 bitShift = vec4(<span class="hljs-number">1.0</span>, <span class="hljs-number">1</span>/<span class="hljs-number">255.0</span>, <span class="hljs-number">1</span>/<span class="hljs-number">65025.0</span>, <span class="hljs-number">1</span>/<span class="hljs-number">16581375.0</span>);
            return dot(rgbaDepth, bitShift);
        }
        
      • 课程框架的清屏操作代码不完整,实际上是没有真正每帧清屏的。glClearColor 和 glClearDepth 只是指定清屏颜色,实际的执行还得再加一句 glClear。
        <code class="lang-js"><span class="hljs-comment">// renderers/WebGLRenderer.js</span>
        <span class="hljs-keyword">gl</span>.clearColor(0.0, 0.0, 0.0, 1.0); <span class="hljs-comment">// Clear to black, fully opaque</span>
        <span class="hljs-keyword">gl</span>.clearDepth(1.0); <span class="hljs-comment">// Clear everything</span>
        <span class="hljs-keyword">gl</span>.<span class="hljs-keyword">clear</span>(<span class="hljs-keyword">gl</span>.COLOR_BUFFER_BIT | <span class="hljs-keyword">gl</span>.DEPTH_BUFFER_BIT);
        

        清屏操作在处理平面上的一些 artefact 时可以用上。

      • 在课程视频 P3 80:26 时,闫老师的原话是:"……也就意味着如果 light 离你比较远,也就是在 shadowmap 上找一个比较小的范围"。这里应该是口误,light 越远应该查询范围越大。这个细节没有在课程任何其他地方提及,除非自己翻一下 N 厂的原论文实现,考虑到不是每个同学都会这么做,所以这个口误影响比较大。
    • #8326 Score: 0
      YunHsiao
      Participant
      19 pts

      这论坛限时修改还不能删帖的策略实在是有点蛋疼。。写的时候也不能预览,我不知道发出来排版竟然这么乱啊。。

      格式正常的版本先放这里了:
      https://docs.qq.com/doc/DUG1UZGVDamh1YXVq

    • #8331 Score: 0
      cmc233
      Participant
      6 pts

      作业 2

      还是觉得tools.js的mat4Matrix2mathMatrix函数有问题,glmatrix的mat4是按列优先存储的,但mat4Matrix2mathMatrix读的时候是按行优先存储读的,mat4Matrix2mathMatrix返回的是原矩阵的转置

      打印了一下结果也确实是转置了:

      let v = mat4.create();
      mat4.fromRotation(v, math.pi / 6, [0, 1, 0]);
      let v_ = mat4Matrix2mathMatrix(v);
      console.log(v_);

      0.8660253882408142, 0, -0.5, 0
      0, 1, 0, 0
      0.5, 0, 0.8660253882408142, 0
      0, 0, 0, 1

      但是实际旋转矩阵应该是
      0.8660253882408142, 0, 0.5, 0
      0, 1, 0, 0
      -0.5, 0, 0.8660253882408142, 0
      0, 0, 0, 1

    • #8338 Score: 0
      YunHsiao
      Participant
      19 pts

      我上面发的文档链接编辑权限是公开的,大家有补充可以直接顺手放进去

    • #8349 Score: 0
      Time machine
      Participant

      楼主给力

    • #8350 Score: 0
      Time machine
      Participant

      决定再写一个感想占用一楼:先感谢闫神和那些无私奉献的大佬们,有了他们的知识相诉,个人的知识成长很明显,哪怕是以后用不到这样的技术也可以是一个极有意思的兴趣爱好,东西作出来,效果很棒,心里是愉悦的,就冲这一份愉悦,闫神和那些无私奉献的大佬们值得尊敬。
      课的作业更是漂亮,只是我本人在其实有绝大多数在摸索其中的错误细节,像[吞换行符]小问题上,也是耗费了很长一段时间。只是更多的期望把更多的时间放在完成作业本身的计算上面。
      致敬感谢

    • #8432 Score: 0
      Freakx
      Participant

      感谢lz,想在作业一做个动态光源玩玩结果原框架没有清空shadowMap,直接拷过去那四行清空代码结果还是不对,原来是少了一行clear哈哈哈,太感谢

    • #8597 Score: 0
      YunHsiao
      Participant
      19 pts

      作业 3 完成度明显提高,没有遇到阻碍性问题,助教同学们辛苦。

      提醒一下 cave 场景的相机位置和光照信息和 cube 场景是不一致的,需要手动切换一下,不然直接用 cube 的参数进 cave 正好是墙背后,间接光照下效果是黑屏,不要被搞懵了。

      • #8610 Score: 0
        Migo
        Participant

        你好,我想请教一下作业三的EvalDiffuse究竟是要计算的是什么,我看文档不是很清晰明白

    • #8772 Score: 2
      YunHsiao
      Participant
      19 pts

      作业 4 离线预计算部分代码没有适配 MSVC,需要做以下调整:

      CMake 文件加入以下段落:

      if(MSVC)
      target_compile_definitions(lut-Emu-MC PUBLIC _USE_MATH_DEFINES)
      target_compile_definitions(lut-Eavg-MC PUBLIC _USE_MATH_DEFINES)
      target_compile_definitions(lut-Emu-IS PUBLIC _USE_MATH_DEFINES)
      target_compile_definitions(lut-Eavg-IS PUBLIC _USE_MATH_DEFINES)
      endif()

      C++ 标准并未支持 VLA,需要替换两个 Eavg 实验代码中的

      uint8_t data[resolution * resolution * 3];

      std::vector<uint8_t> buffer(resolution * resolution * 3);
      uint8_t* data = buffer.data();

      This post has received 2 votes up.
      • This reply was modified 2 years, 8 months ago by YunHsiao.
      • This reply was modified 2 years, 8 months ago by YunHsiao.
      • This reply was modified 2 years, 8 months ago by YunHsiao.
    • #8794 Score: 0
      YunHsiao
      Participant
      19 pts

      作业 4 描述 2.2.2 节,最后整理出的采样入射权重公式有误, 应为:(注意分子上是 dot(i, m))

      weight(i) = (i · m) * G(i, o, h) / (o · n) * (m · n)

      • #8822 Score: 0
        Migo
        Participant

        我自己推到也和你的结果是一样的,但是Unreal Engine给出了却是weight(i) = (o · m) * G(i, o, h) / (o · n) * (m · n);

      • #8823 Score: 0
        Migo
        Participant
      • #8824 Score: 0
        Migo
        Participant

        另外,webgl可以运行吗,我什么都还没有做的时候运行,只能看到灯光和cornelBox,没有渲染出那几个Shading ball

        • #8825 Score: 0
          YunHsiao
          Participant
          19 pts

          m 是半角向量,所以其实 dot(o, m) 和 dot(i, m) 是等价的,所以倒是可以互换。

          WebGL 框架默认的 PBR 和 KullaConty shader 里 DistributionGGX 函数没有返回值,这个有报错,修了就画出来了。

          • #8829 Score: 0
            Migo
            Participant

            是的,这样想就明白了,谢谢

    • #8806 Score: 0
      YunHsiao
      Participant
      19 pts

      作业 4 的 GeometrySchlickGGX 项代码中实际使用的是 [Karis SIGGRAPH 13] 版本的 k 值(a * a / 2),并非作业描述中提到的 (a + 1)^2 / 8,估计是为了更接近 Kulla Conty 原作所附的计算结果,两套算法不要搞混。

    • #8826 Score: 0
      YunHsiao
      Participant
      19 pts

      作业 4 WebGL 框架,KullaContyMaterial.js 中 uniform 名字传错了,应为 uEavgLut 而不是 uEavgFLut,这会导致 Eavg 贴图实际用的是 albedo 那张,问题比较隐蔽,但影响比较严重。

      • #8855 Score: 0
        YunHsiao
        Participant
        19 pts

        因为这个 bug,作业描述里最后的效果截图其实也是错的,由于用了 albedo 当作 Eavg 导致 color saturation 更明显了,实际没有那么黄。

    • #8856 Score: 0
      YunHsiao
      Participant
      19 pts

      作业 4,Skybox 对本次作业并没有意义,还影响观察,建议大家关掉调试:

      注释掉 src/engine.js 134 行:

      // loadOBJ(renderer, ‘assets/testObj/’, ‘testObj’, ‘SkyBoxMaterial’, skyBoxTransform);

      src/renderers/WebGLRenderer.js 23 行开始调整一个合适的背景色:

      gl.clearColor(0.1, 0.1, 0.1, 1.0); // Clear to black, fully opaque
      gl.clearDepth(1.0); // Clear everything
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    • #8859 Score: 0
      xuruoji
      Participant

      assignment4.pdf 中的 fadd 计算方法和原文(//https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) 的计算方法不一样,按照原文的计算方法在 uniform uEavgLut 传入正确的情况下结果才像是正确的

    • #8866 Score: 0
      flyingSnow
      Participant
      5 pts

      作业4,pdf里的D项公式错了,代码里的是对的

    • #8927 Score: 0
      小夜子
      Participant

      作业四,assignment4里对G项写的是用半程向量,但实际应该用的是几何法线。

      Attachments:
      You must be logged in to view attached files.
    • #9080 Score: 0
      YunHsiao
      Participant
      19 pts

      作业 5,一个小问题,TemporalAccumulation 函数中 alpha 默认值给了 1,导致在做 Reproject 部分时默认输出的还是 上一步的 filteredColor 而不是 m_accColor,必须要注掉 TemporalAccumulation 函数才能看到 Reproject 的输出。建议调试时先把 alpha 改为 0 就不用关心这个问题了。

      • #9110 Score: 0
        Migo
        Participant

        你好,想请教一下,作业5的TemporalAccumulation

        for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
        // TODO: Temporal clamp
        Float3 color = m_accColor(x, y);
        Float3 mean = Float3(0.f), variance = Float3(0.f);
        meanVarianceCalc(curFilteredColor, x, y, kernelRadius, mean, variance);
        color = Clamp(color, mean-variance*m_colorBoxK, mean+variance*m_colorBoxK);

        // TODO: Exponential moving average
        float alpha = m_valid(x, y) ? m_alpha : 1.0f;
        m_misc(x, y) = Lerp(color, curFilteredColor(x, y), alpha);
        }
        }
        std::swap(m_misc, m_accColor);

        这样做的思路有问题吗?为什么我的出来的最终效果比参考要模糊得多的?

        Attachments:
        You must be logged in to view attached files.
        • #9176 Score: 1
          Ryushinn
          Participant
          2 pts

          如果上一帧的颜色被clamp到mean周围的一个过于小的范围内的话,结果就会偏模糊,因为求mean本身就相当于在filter场景。
          可以试着调高k或者用标准差:mean ± k * sqrt(Variance)

          This post has received 1 vote up.
    • #9097 Score: 0
      YunHsiao
      Participant
      19 pts

      作业 5,再提一个感觉最好放进框架的细节,pink room 和 box 场景因为光照数据不同需要的降噪参数不太一致,对 pink room 需要把 m_sigmaColor 调到 10 左右,其他可以保持一致。

      除此之外未遇到阻碍性问题~

    • #9194 Score: 0
      younne0915
      Participant

      请问你运行Denoise.exe多久出的降噪后的图呢?我的一直在运行,很久都停不了呢。

      • #9195 Score: 0
        YunHsiao
        Participant
        19 pts

        除了不开 a-trous 优化的 pink room,其他情况下应该都很快的,如果算一帧就需要 30 秒以上应该是有问题了。

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