扫描线z-buffer消隐算法思想与数据结构

从冯结青老师上的图形学课件上摘录:

基本思想
开两个一维数组xresolotion分别作为当前扫描线的z缓冲器和帧缓冲器
在处理当前扫描线时
  • 帧缓冲器的初值取背景颜色
  • z缓冲器的初始值取为最小z值
求出该扫描线与场景中各多边形的二维投影之间的交点
一条扫描线与一个多边形有偶数个交点,对每对交点之间的像素计算其深度值,与z缓冲中的值比较,若可见,将该多边形的属性写入帧缓冲器,更新z-buffer中的深度值
当场景中的所有多边形处理完毕时,扫描线帧缓冲器中的内容为画面在此扫描线的消隐结果
数据结构
分类多边形表:根据多边形最大y坐标ymax将多边形放入相应类中
  • a,b,c,d:多边形所在平面方程系数 ax+by+cz+d=0
  • id:多边形编号
  • dy:多边形跨越的扫描线数目
  • color:多边形的颜色
分类边表:根据边的上端点y坐标ymax将边放入到相应类中
  • x:边的上端点的x坐标
  • dx:相邻两条扫描线交点的x坐标差dx(-1/k)
  • dy:边跨越的扫描线数目
  • ID:边所属多边形的编号
中间数据结构
活化多边形表:记录当前扫描线与多边形在oxy平面上投影相交的多边形
  • a,b,c,d:多边形所在平面方程系数 ax+by+cz+d=0
  • id:多边形编号
  • dy:多边形跨越的剩余扫描线数目
  • color:多边形的颜色
活化边表:存放多边形投影边界与扫描线相交的边对
  • xl:左交点的x坐标
  • dxl:左交点边界上两相邻扫描线交点x坐标的差值
  • dyl:左交点剩余跨越扫描线数目
  • xr,dxr,dyr为右交点同上类似
  • zl:左交点处多边形所在平面深度值
  • dzx:沿扫描线向右走一个像素时,多边形所在平面的深度增量。对于平面方程,dzx=-a/c(c≠0);
  • dzy:沿y方向向下移过一根扫描线时,多边形所在平面的深度增量。对于平面方程,dzy=b/c;
  • id:交点对所在的多边形编号
算法描述
首先建立分类的多边形表和边表
扫描顺序从上到下:在处理最上面一条扫描线前,活化的多边形表和边表是空的
在处理每条扫描线前,作如下工作:
把帧缓冲器的相应行置成底色
把z缓冲器的各个单元置成最小值(表示离视点最远)
检查分类的多边形表,如果有新的多边形涉及该扫描线,则把它放入活化的多边形表中
如果有新的多边形加入到活化多边形表中,则把该多边形在oxy平面上的投影和扫描线相交的边加入到活化边表中
如果有些边在这条扫描线处结束了,而其所在的多边形仍在活化多边形表中,则可以从分类多边形表中找到该多边形在oxy平面上的投影与扫描线相交的新边或边对,修改或加到活化边表中,边对在活化边表中的次序是不重要的
增量式的深度更新:从形成的活化边表中取出一个边对
当前扫描线y,当前位置x(xl<=x<=xr),深度值zx(左交点zx=zl)
每向右前进一个像素:zx=zx+dzx;
比较zx与当前z缓冲器中的Z值
如果zx>z,那么z=zx,将对应像素颜色置为该多边形的颜色
对活化边表中每一个 边对按如上方法处理
活化边表中元素的修改:修改后的活化边表是下一条扫描线的边表
对于每一条边对可计算;
dyl=dyl-1      dyr=dyr-1
若dyl或dyr小于0,相应的边就要从一个边对中去掉,从活化边表中找到合适的边来代替
边和下一条扫描线交点的x值:
xl=xl+dxl xr=xr+dxr
多边形所在平面对应下一条扫描线在x=xl处的深度为
zl=zl+dzldxl+dzy       Q:(dzl  or dzx ?)
活化多边形表中的元素修改
每一个多边形的dy:dy=dy-1
当dy<0时,该多边形要从多边形活化表中删除

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,z-buffer算法是一种基于深度值比较的消隐算法,我们需要先生成一个深度缓存,然后在渲染每个像素时,比较其深度值和缓存中的深度值,选择深度值较小的像素进行渲染。 下面是一个简单的实现示例,使用canvas绘制三角形,并实现z-buffer算法消隐: HTML代码: ``` <!DOCTYPE html> <html> <head> <title>Z-Buffer Algorithm</title> </head> <body> <canvas id="canvas" width="400" height="400"></canvas> </body> <script src="zbuffer.js"></script> </html> ``` JS代码(zbuffer.js): ``` // 定义三角形顶点信息 var vertices = [ [-0.5, -0.5, 0.5], [0.5, -0.5, 0.5], [0, 0.5, 0.5], ]; // 定义顶点颜色信息 var colors = [ [255, 0, 0], [0, 255, 0], [0, 0, 255], ]; // 定义深度缓存 var depthBuffer = []; // 初始化深度缓存 function initDepthBuffer() { for (var i = 0; i < 400; i++) { depthBuffer[i] = []; for (var j = 0; j < 400; j++) { depthBuffer[i][j] = -Infinity; } } } // 计算三角形面积 function calcTriangleArea(v1, v2, v3) { var a = Math.sqrt(Math.pow(v1[0] - v2[0], 2) + Math.pow(v1[1] - v2[1], 2) + Math.pow(v1[2] - v2[2], 2)); var b = Math.sqrt(Math.pow(v1[0] - v3[0], 2) + Math.pow(v1[1] - v3[1], 2) + Math.pow(v1[2] - v3[2], 2)); var c = Math.sqrt(Math.pow(v2[0] - v3[0], 2) + Math.pow(v2[1] - v3[1], 2) + Math.pow(v2[2] - v3[2], 2)); var p = (a + b + c) / 2; return Math.sqrt(p * (p - a) * (p - b) * (p - c)); } // 绘制三角形 function drawTriangle(ctx, v1, v2, v3, c1, c2, c3) { // 计算三角形面积 var area = calcTriangleArea(v1, v2, v3); // 将三角形顶点按y坐标从小到大排序 var tmp; if (v1[1] > v2[1]) { tmp = v1; v1 = v2; v2 = tmp; tmp = c1; c1 = c2; c2 = tmp; } if (v1[1] > v3[1]) { tmp = v1; v1 = v3; v3 = tmp; tmp = c1; c1 = c3; c3 = tmp; } if (v2[1] > v3[1]) { tmp = v2; v2 = v3; v3 = tmp; tmp = c2; c2 = c3; c3 = tmp; } // 计算三角形投影到屏幕上的坐标 var sx1 = (v1[0] + 1) * 200; var sy1 = (v1[1] + 1) * 200; var sx2 = (v2[0] + 1) * 200; var sy2 = (v2[1] + 1) * 200; var sx3 = (v3[0] + 1) * 200; var sy3 = (v3[1] + 1) * 200; // 分别计算每行的左右端点 var x1, x2, y; var z1, z2, z3; var c11, c21, c31; var c12, c22, c32; for (y = Math.ceil(sy1); y <= sy2; y++) { // 计算左右端点的x坐标和深度值 x1 = sx1 + (y - sy1) / (sy2 - sy1) * (sx2 - sx1); z1 = v1[2] + (y - sy1) / (sy2 - sy1) * (v2[2] - v1[2]); c11 = c1[0] + (y - sy1) / (sy2 - sy1) * (c2[0] - c1[0]); c21 = c1[1] + (y - sy1) / (sy2 - sy1) * (c2[1] - c1[1]); c31 = c1[2] + (y - sy1) / (sy2 - sy1) * (c2[2] - c1[2]); x2 = sx1 + (y - sy1) / (sy3 - sy1) * (sx3 - sx1); z2 = v1[2] + (y - sy1) / (sy3 - sy1) * (v3[2] - v1[2]); c12 = c1[0] + (y - sy1) / (sy3 - sy1) * (c3[0] - c1[0]); c22 = c1[1] + (y - sy1) / (sy3 - sy1) * (c3[1] - c1[1]); c32 = c1[2] + (y - sy1) / (sy3 - sy1) * (c3[2] - c1[2]); // 交换左右端点,保证x1 <= x2 if (x1 > x2) { tmp = x1; x1 = x2; x2 = tmp; tmp = z1; z1 = z2; z2 = tmp; tmp = c11; c11 = c12; c12 = tmp; tmp = c21; c21 = c22; c22 = tmp; tmp = c31; c31 = c32; c32 = tmp; } // 在该行上进行扫描线填充 for (var x = Math.ceil(x1); x <= x2; x++) { // 计算当前像素的深度值 var z = z1 + (x - x1) / (x2 - x1) * (z2 - z1); // 判断是否需要更新深度缓存和像素颜色 if (z > depthBuffer[x][y]) { depthBuffer[x][y] = z; var r = c11 + (x - x1) / (x2 - x1) * (c21 - c11); var g = c12 + (x - x1) / (x2 - x1) * (c22 - c12); var b = c31 + (x - x1) / (x2 - x1) * (c32 - c31); ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")"; ctx.fillRect(x, y, 1, 1); } } } for (y = Math.ceil(sy2); y <= sy3; y++) { // 计算左右端点的x坐标和深度值 x1 = sx2 + (y - sy2) / (sy3 - sy2) * (sx3 - sx2); z1 = v2[2] + (y - sy2) / (sy3 - sy2) * (v3[2] - v2[2]); c11 = c2[0] + (y - sy2) / (sy3 - sy2) * (c3[0] - c2[0]); c21 = c2[1] + (y - sy2) / (sy3 - sy2) * (c3[1] - c2[1]); c31 = c2[2] + (y - sy2) / (sy3 - sy2) * (c3[2] - c2[2]); x2 = sx1 + (y - sy1) / (sy3 - sy1) * (sx3 - sx1); z2 = v1[2] + (y - sy1) / (sy3 - sy1) * (v3[2] - v1[2]); c12 = c1[0] + (y - sy1) / (sy3 - sy1) * (c3[0] - c1[0]); c22 = c1[1] + (y - sy1) / (sy3 - sy1) * (c3[1] - c1[1]); c32 = c1[2] + (y - sy1) / (sy3 - sy1) * (c3[2] - c1[2]); // 交换左右端点,保证x1 <= x2 if (x1 > x2) { tmp = x1; x1 = x2; x2 = tmp; tmp = z1; z1 = z2; z2 = tmp; tmp = c11; c11 = c12; c12 = tmp; tmp = c21; c21 = c22; c22 = tmp; tmp = c31; c31 = c32; c32 = tmp; } // 在该行上进行扫描线填充 for (var x = Math.ceil(x1); x <= x2; x++) { // 计算当前像素的深度值 var z = z1 + (x - x1) / (x2 - x1) * (z2 - z1); // 判断是否需要更新深度缓存和像素颜色 if (z > depthBuffer[x][y]) { depthBuffer[x][y] = z; var r = c11 + (x - x1) / (x2 - x1) * (c21 - c11); var g = c12 + (x - x1) / (x2 - x1) * (c22 - c12); var b = c31 + (x - x1) / (x2 - x1) * (c32 - c31); ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")"; ctx.fillRect(x, y, 1, 1); } } } } // 初始化深度缓存 initDepthBuffer(); // 获取canvas元素和绘制上下文 var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); // 绘制三角形 drawTriangle(ctx, vertices[0], vertices[1], vertices[2], colors[0], colors[1], colors[2]); ``` 上述代码实现了一个简单的z-buffer算法消隐,我们先定义了一个三角形的顶点和颜色信息,然后初始化了一个深度缓存。在绘制三角形时,我们先计算三角形的面积,并将三角形顶点按y坐标从小到大排序,然后计算三角形投影到屏幕上的坐标。接着,我们分别计算每行的左右端点,并在该行上进行扫描线填充。在每个像素上,我们比较其深度值和深度缓存中的深度值,如果当前像素的深度值小于深度缓存中的深度值,则更新深度缓存和像素颜色。最后,我们实现了一个简单的三角形渲染,并使用z-buffer算法消隐了隐藏面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值