Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何隐藏三维图形的不可见元素?_Algorithm_Graphics_3d_Drawing_Wireframe - Fatal编程技术网

Algorithm 如何隐藏三维图形的不可见元素?

Algorithm 如何隐藏三维图形的不可见元素?,algorithm,graphics,3d,drawing,wireframe,Algorithm,Graphics,3d,Drawing,Wireframe,我正在尝试绘制一个显示波纹的3d图像: function myFunc(x, y) { let zRipple = Math.pow(2, -0.005 * (Math.abs(x) + Math.abs(y))) * Math.cos(((x * x + y * y) * 2 * pi) / 180 / width) * height; return zRipple; } 这里的宽度和高度是定义绘图区域的常量,在我的测试中等于200 我的方法是基于我30年前

我正在尝试绘制一个显示波纹的3d图像:

function myFunc(x, y) {
  let zRipple =
    Math.pow(2, -0.005 * (Math.abs(x) + Math.abs(y))) *
    Math.cos(((x * x + y * y) * 2 * pi) / 180 / width) *
    height;

  return zRipple;
}
这里的宽度和高度是定义绘图区域的常量,在我的测试中等于200

我的方法是基于我30年前读过的一篇文章中的回忆,现在我试图回忆起来

其想法是:

  • 将整个绘图板拆分为10像素网格

  • 对于网格的每个“单元”,沿Y轴和X轴(步长=10,ds=0.0)绘制一条到最近单元的线

    for (let x3 = width; x3 >= - width; x3 -= step) {
      for (let y3 = -height; y3 <= height; y3 += step) {
        for (let s = 0; s < step; s += ds) {
          let x = x3 + s;
            if (x < width) {
              let z3 = myFunc(x, y3);
              drawPixel3d(x, y3, z3);
            }
          }
    
          for (let s = 0; s < step; s += ds) {
            let y = y3 + s;
            if (y < height) {
              let z3 = myFunc(x3, y);
              drawPixel3d(x3, y, z3);
            }
          }
        }
      }
    }
    
    如下图所示,我得到了一个不错的图形,但有一个问题:我画了所有的点,而不仅仅是那些,可见的点

    问题:如何检查是否需要显示任何像素

    根据我在那篇文章中所记得的,我们应该遵循以下方法:

    • 从场景的前部开始绘制(我相信我是这样做的,如果圆点带有坐标(宽度,-高度),则最靠近查看器或屏幕)
    • 对于每个像素列-记住“Z”坐标,仅当新像素的Z坐标大于上次记录的Z坐标时,才绘制新像素
    为了实现这一点,我修改了我的“drawPixel3d”方法:

    function drawPixel3d(x3, y3, z3) {
      let x2 = (x3 + y3) * Math.sin((60 * pi) / 180);
      let y2 = z3 - ((x3 - y3) * Math.sin((30 * pi) / 180)) / 4;
    
      let n = Math.round(x2);
      let visible = false;
      if (zs[n] === undefined) {
        zs[n] = z3;
        visible = true;
      } else {
        if (z3 > zs[n]) {
          visible = z3 > zs[n];
          zs[n] = z3;
        }
      }
    
      if (visible) drawPixel(x2, y2);
    }
    
    但结果却出乎意料:

    我做错了什么?或者另一个问题:如何绘制简单的3d图形

    谢谢

    p.S.程序的最后一部分(说明实际绘图期间Y坐标的反转):


    p.p.S.我对算法解决方案有了一个想法,所以添加了一个“算法”标签:也许这个社区的人能帮上忙?

    我想到了解决方案:从最靠近观察者的点开始绘制,但对于x2和y2坐标的每一个组合,只绘制一次像素,并且只有在像素可见时才绘制它。(永远不要在别人后面画点)…唯一的问题是,我没有画出曲面的每个点,我只画了一个具有10点步长的曲面网格。因此,部分曲面将在网格单元之间可见


    另一个想法是计算从曲面的每个绘制点到观察者的距离,并确保只绘制曲面上最靠近观察者的可见点……但如何绘制?

    我得到了解决方案的想法:从最靠近观察者的点开始绘制,但对于每个组合在x2和y2坐标中,仅在像素可见时绘制像素一次(切勿在其他像素后面绘制点)…唯一的问题是,我没有绘制曲面的每个点,我只绘制一个具有10个点步长的曲面网格。因此,部分曲面将在网格单元之间可见


    另一个想法是计算从曲面的每个绘制点到观察者的距离,并确保仅绘制曲面中最靠近观察者的可见点……但是如何绘制?

    曲面是凹面,这意味着无法使用基于面法线和曲面之间点积的简单方法ra视图方向

    你有3个明显的选择

  • 使用光线跟踪

    当你们得到曲面的解析方程时,这可能是更好的方法

  • 使用深度缓冲来掩盖不可见的内容

    渲染线框时,需要在两个过程中执行此操作:

  • 渲染不可见的填充曲面(仅填充深度缓冲区而不是屏幕)
  • 渲染线框
  • 深度缓冲区条件也必须包含相等的值,以便
    z=depth[y][x]

    但是,您需要使用面渲染(三角形或四边形…),我假设这是软件渲染,因此如果您不熟悉此类内容,请参见:

  • 利用拓扑使用深度排序

    如果没有视图变换,因此
    x、y、z
    坐标直接对应于摄影机空间坐标,则可以通过对for循环和迭代方向进行排序(在等轴测视图中很常见),以从后到前的顺序渲染栅格。这不需要深度缓冲,但是您需要渲染填充的四边形以获得正确的输出(边框设置为打印颜色,内部填充背景色)

  • 我确实选择了#2方法。当我将最后一个链接移植到3D时,我得到了以下(C++代码):

    //---------------------------------------------------------------------------
    const int col_transparent=-1;//透明颜色
    类别gfx_干管
    {
    公众:
    Graphics::TBitmap*bmp;//用于win32渲染的VCL位图
    int**scr、**zed、xs、ys;//屏幕、深度缓冲区和分辨率
    struct pbuf//凸多边形光栅化行缓冲区
    {
    int x,z;//渲染期间要插值的值
    pbuf(){}
    pbuf(pbuf&a){*this=a;}
    ~pbuf(){}
    pbuf*运算符=(常量pbuf*a){*this=*a;返回this;}
    //pbuf*运算符=(常量pbuf&a){…复制…返回此;}
    }*pl,*pr;//左、右缓冲区
    gfx_main();
    gfx_main(gfx_main&a){*this=a;}
    ~gfx_main();
    gfx_main*运算符=(const gfx_main*a){*this=*a;返回this;}
    //gfx_main*运算符=(const gfx_main&a){…复制…返回此;}
    void resize(int _xs=-1,int _ys=-1);
    void clear(int z,int col);//清除缓冲区
    无效像素(int x,int y,int z,int col);//渲染三维点
    虚线(int x0,int y0,int z0,int x1,int y1,int z1,int col);//渲染三维线
    空心三角形(int x0,int y0,int z0,int x1,int y1,int z1,int x2,int y2,int z2,int col);//渲染三维三角形
    void _三角形_线(intx0,inty0,intz0,intx1,inty1,intz1);//这只是一个子程序
    };
    //----------------------------------------
    
    function drawPixel3d(x3, y3, z3) {
      let x2 = (x3 + y3) * Math.sin((60 * pi) / 180);
      let y2 = z3 - ((x3 - y3) * Math.sin((30 * pi) / 180)) / 4;
    
      let n = Math.round(x2);
      let visible = false;
      if (zs[n] === undefined) {
        zs[n] = z3;
        visible = true;
      } else {
        if (z3 > zs[n]) {
          visible = z3 > zs[n];
          zs[n] = z3;
        }
      }
    
      if (visible) drawPixel(x2, y2);
    }
    
    function drawPixel(x: number, y: number) {
      ctx.fillRect(cX + x, cY - y, 1, 1); // TS-way to draw pixel on canvas is to draw a rectangle
    }   // cX and cY are coordinates of the center of the drawing canvas