Home Forums GAMES在线课程(现代计算机图形学入门)讨论区 关于作业2两个三角形重叠部分的Z-Buffer问题

Viewing 8 reply threads
  • Author
    Posts
    • #7332 Score: 0
      luuuuyang
      Participant
      2 pts

      在两个三角形的重叠部分上,浅蓝色三角形上的一些像素点绘制在了浅绿色三角形上面,为什么会出现z值较大的像素点覆盖z值较小的像素点这种情况?

      Attachments:
      You must be logged in to view attached files.
    • #7337 Score: 0
      苏丛
      Participant
      2 pts

      这两张图看起来都没问题

      • #7339 Score: 0
        luuuuyang
        Participant
        2 pts

        再添加一张来自作业1的get_projection_matrix函数的截图

        • This reply was modified 4 years ago by luuuuyang.
        Attachments:
        You must be logged in to view attached files.
    • #7342 Score: 2
      luuuuyang
      Participant
      2 pts

      问题已解答
      是由于两个三角形的深度信息也就是z值不正确导致的。
      参考其他帖子了解到在提供的框架中,在将z值从负值反转的正值的过程中少了一个负号,加上就能计算出正确的z值,可以参考下图注释及注释下一行

      This post has received 2 votes up.
      • This reply was modified 4 years ago by luuuuyang.
      Attachments:
      You must be logged in to view attached files.
    • #7648 Score: 0
      wjwABCDEFG
      Participant

      请问楼主,为什么你不会出现中心对称问题(作业1和作业3也存在),如何解决?

      • #7649 Score: 0
        wjwABCDEFG
        Participant

        已解决

        • #9505 Score: 0
          chenghaochn
          Participant

          怎么解决的?

          • #9621 Score: 0
            Astesia
            Participant

            我也想问,我的三角形都是中心对称的

            • #11655 Score: 0
              wjwABCDEFG
              Participant

              可以在作业1的get_projection_matrix函数中先进行一次正负转换zNear = -abs(zNear); zFar = -abs(zFar);同时在计算top时保持正数float t = tan((eye_fov / 2) / 180 * MY_PI) * abs(zNear);因为这里的zNear指的是距离

    • #11317 Score: 0
      见龙
      Participant

      谢谢楼主,已解决

    • #12033 Score: 0
      unkvcc
      Participant
      2 pts

      感谢解答。我的理解是之前做MVP变换时采用了-z的值,那么做视图变换时也应该采用顶点的-z
      `
      // 单位立方体的边长
      float f1 = (50 – 0.1) / 2.0;
      // 单位立方体的中心点的z值 反转后的 正值
      float f2 = (50 + 0.1) / 2.0;
      ……
      // 变换前的点(0,0) 变换后应该在(width/2,height/2) 的位置
      //Viewport transformation
      for (auto & vert : v)
      {
      vert.x() = 0.5*width*(vert.x()+1.0);
      vert.y() = 0.5*height*(vert.y()+1.0);
      // 因为之前为了方便计算z值,将z值设置成正值
      // 而我们做MVP变换时,采用的是z值的负值
      // 所以这里再做视口变换,应改回负值
      vert.z() = -vert.z() * f1 + f2;
      // vert.z() = vert.z() * f1 + f2;
      }
      `

    • #12095 Score: 0
      shs1992shs
      Participant

      我的理解是mvp变换后z坐标就在[-1,1]之内,那么经过放大f1倍后(vert.z()*f1),如果z值是负的,就是还是负的。第二个三角形原始的z为-5,小于第一个三角形原始z值-2,mvp变换后还是符合这种情况。
      那么加上f2之后,就是所有点都平移到了z轴正方向,此时所有的z坐标都是正值,那么此时第二个三角形的z值假设由最初的-5变为1,第一个三角形的z值此时必然比1要大,可能为8,还是符合靠近相机的z值大于远离相机的z值,这会覆盖后面的z值。那么判断深度值,坚持以这个关系进行比较,即若当前的z值大于z缓冲,那么就以当前的三角形的颜色绘制,并更新z缓冲,这样理解起来是非常直观的。
      此处出现问题,主要是代码框架的depth_buf初始化的问题,初始化值是正无穷大, 那么从第一个三角形开始比较,其z值小于初始 z缓冲(无穷大),认为在目前深度后面,不用更新,那么最终就什么都没有绘制,为黑屏。
      如果直接把判断关系改为作业提示中的z值越大表示离视点越远,即若当前z值小于z缓冲,则以当前颜色绘制并更新,那么此时第一个三角形满足情况,顺利绘制并更新z缓冲。但是第二个三角形中的部分z值小于和第一个三角形重叠部分的z值,即小于z缓冲值,那么满足判断关系,进行绘制覆盖并更新,从而颠倒了两个三角形的绘制顺序。所以最简单的修改,就是把初始化的z缓冲设为负无穷大,这样就是z值越小,离相机越远。参考下面的代码。
      如果坚持以作业提示中的方法,初始化的z缓冲还是正无穷大,那就需要修改原代码框架里的视口变换的z坐标变换了,即把 vert.z() * f1进行放大时,前面加一负号,完成z值镜像反转。此时原来离视点最远的z值由负变正,数值上变为最大,那么判断关系就符合作业要求了,z值越小离视点越近,若当前z值小于z缓冲,则绘制覆盖并更新,顺序就正确了。这个方法我认为理解起来不是那么直观,因为前面的mvp推导过程都是坚持z值为负值的,突然一下转为正值,很容易让人混淆,理解起来困难。
      两种方法都试一下之后,相信就会加深理解了。

      修改后的代码如下:

      int pixel_index = get_index(x, y);
      float depth = depth_buf[pixel_index];
      if (depth < z_interpolated)  {
          set_pixel(Vector3f(x, y, z_interpolated), t.getColor());
          depth_buf[pixel_index] = z_interpolated; // update depth
      }
      void rst::rasterizer::clear(rst::Buffers buff)
      {
          if ((buff & rst::Buffers::Color) == rst::Buffers::Color)
          {
              std::fill(frame_buf.begin(), frame_buf.end(), Eigen::Vector3f{0, 0, 0});
          }
          if ((buff & rst::Buffers::Depth) == rst::Buffers::Depth)
          {
              //std::fill(depth_buf.begin(), depth_buf.end(), std::numeric_limits<float>::infinity()); //原框架初始深度值为∞
              std::fill(depth_buf.begin(), depth_buf.end(), -std::numeric_limits<float>::infinity());//初始深度值改为-∞,z轴最远处。
          }
      }

      修改视口变换的代码:

      // Viewport transformation
      for (auto &vert : v)
      {
          vert.x() = 0.5 * width * (vert.x() + 1.0);
          vert.y() = 0.5 * height * (vert.y() + 1.0);
          vert.z() = -vert.z() * f1 + f2; // 负号是为了实现镜像反转(reflection )
          // vert.z() = vert.z() * f1 + f2;
      }
    • #15806 Score: 0
      w小宇
      Participant

      为什么我按楼主的方法还是没有解决啊,有没有大佬帮帮忙

    • #16111 Score: 0
      Ashechol
      Participant
      1 pt

      果然是框架的问题啊,我就说怎么z在视口变换前大小正常的,视口后就反过来了

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