Algorithm 如何隐藏三维图形的不可见元素?
我正在尝试绘制一个显示波纹的3d图像: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年前
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坐标时,才绘制新像素
但结果却出乎意料: 我做错了什么?或者另一个问题:如何绘制简单的3d图形 谢谢 p.S.程序的最后一部分(说明实际绘图期间Y坐标的反转):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); }
p.p.S.我对算法解决方案有了一个想法,所以添加了一个“算法”标签:也许这个社区的人能帮上忙?我想到了解决方案:从最靠近观察者的点开始绘制,但对于x2和y2坐标的每一个组合,只绘制一次像素,并且只有在像素可见时才绘制它。(永远不要在别人后面画点)…唯一的问题是,我没有画出曲面的每个点,我只画了一个具有10点步长的曲面网格。因此,部分曲面将在网格单元之间可见
另一个想法是计算从曲面的每个绘制点到观察者的距离,并确保只绘制曲面上最靠近观察者的可见点……但如何绘制?我得到了解决方案的想法:从最靠近观察者的点开始绘制,但对于每个组合在x2和y2坐标中,仅在像素可见时绘制像素一次(切勿在其他像素后面绘制点)…唯一的问题是,我没有绘制曲面的每个点,我只绘制一个具有10个点步长的曲面网格。因此,部分曲面将在网格单元之间可见
另一个想法是计算从曲面的每个绘制点到观察者的距离,并确保仅绘制曲面中最靠近观察者的可见点……但是如何绘制?曲面是凹面,这意味着无法使用基于面法线和曲面之间点积的简单方法ra视图方向 你有3个明显的选择 - 使用光线跟踪 当你们得到曲面的解析方程时,这可能是更好的方法
- 使用深度缓冲来掩盖不可见的内容 渲染线框时,需要在两个过程中执行此操作:
- 渲染不可见的填充曲面(仅填充深度缓冲区而不是屏幕)
- 渲染线框 深度缓冲区条件也必须包含相等的值,以便
z=depth[y][x]
但是,您需要使用面渲染(三角形或四边形…),我假设这是软件渲染,因此如果您不熟悉此类内容,请参见:
x、y、z
坐标直接对应于摄影机空间坐标,则可以通过对for循环和迭代方向进行排序(在等轴测视图中很常见),以从后到前的顺序渲染栅格。这不需要深度缓冲,但是您需要渲染填充的四边形以获得正确的输出(边框设置为打印颜色,内部填充背景色)
//---------------------------------------------------------------------------
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