zbuffermethod.htm
来自「电脑图学(Computer Graphics)是资料结构、演算法与数学的应用」· HTM 代码 · 共 161 行
HTM
161 行
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>Z Buffer法</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="ComputerGraphics.htm">Computer Graphics: Z Buffer法</a></h1>
<a href="MaxMinMethod.htm">最大最小法</a> 仅适用于曲面函式可以用显函式y = f(x, z)来表示时,如果曲面函式非显函式形式,则无法使用最大最小法来处理深度问题。<br>
<br>
Z Buffer有些类似画家演算法,都是以近景遮盖远景的方法来处理深度问题,所不同的是Z
Buffer使用的是裁剪(culling)的方法,并以像素为处理的对象,Z
Buffer将绘图画布内所有的座标当作一个深度缓冲区阵列zbuf[]的索引,每一个zbuf[]的元素记录一个像素绘制时的Z深度资讯,可以使用它来
处理隐函式的图形绘制。<br>
<br>
假设画布大小为600X400(X,
Y),则zbuf[]的大小必须设定为600*400=240000(X*Y),一开始时所有zbuf[]元素的值设定为一个极小值,也就是所有的像素都
表示空间中一个极深的位置,开始绘制之后,必须在zbuf[]中记录每一个像素的z值。<br>
<br>
zbuf[]是个一维阵列,所以我们必须计算座标的索引值,如果以列为主的话,则(x, y)对应的zbuf[]元素值为:zbuf[x + y * 画布高度];当然您也可以使用二维阵列zbuf[][]来直接对应。<br>
<br>
如果后来要绘制的点之z值大于zbuf[]中记录的值,表示此点在之前所绘点的前面,于是绘制此点来覆盖之前所绘的点,并更新zbuf[]
中的z值为目前点的z值;如果后来要绘制的点之z值小于zbuf[]中记录的值,表示此点在之前所绘点的后面,于是不用绘制此点,当然也不用更新zbuf
[]中的z值。<br>
<br>
Z Buffer的深度处理方式无论从哪一个点开始绘制,都不会影响处理的结果;Z buffer的缺点就是使用大量的记忆体作为缓冲区,而由于它是以像素为处理的单位,所以需耗用相当大量的运算资源。<br>
<br>
下面这个程式并不是一个很好的示范,因为我们并不是每个像素都考虑到,但可以让您了解Z Buffer的演算法,如果要考虑所有的像素,这个程式要画的好,最好加上阴影的效果,绘制的图形之参数式如下,其中 a 表示圆的粗细: <br>
<div style="margin-left: 40px;"><span style="font-family: Courier New,Courier,monospace; font-weight: bold;">x = (1+a*cosθ) * sinφ </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">y = a * sinθ </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">z = (1+a*cosθ)*cosφ </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">0 < a < 1, 0 <= θ <= 2π, 0 <= φ <= 2π </span><br>
</div>
<br>
<span class="postbody"></span><br>
<ul>
<li> ZBufferMethod.java
</li>
</ul>
<pre>package onlyfun.caterpillar;<br> <br>import java.awt.Color;<br>import java.awt.Graphics;<br>import javax.swing.JApplet;<br> <br>public class ZBufferMethodDemo extends JApplet {<br> private int orgX;<br> private int orgY;<br> private double[] zbuf; <br> <br> public void init() {<br> super.init();<br> setBackground(Color.black);<br> orgX = (int)getSize().width /2;<br> orgY = (int) (getSize().height / 2);<br> zbuf = <br> new double[getSize().width * getSize().height];<br> }<br> <br> public void paint(Graphics g) {<br> g.setColor(Color.yellow);<br> <br> // 从斜角绘制<br> // 绕 x 轴转 30 度<br> double angleX = Math.toRadians(30);<br> <br> double a = 0.3;<br> double k = 200.0;<br> <br> for(int l = 0; l < zbuf.length; l++) <br> zbuf[l] = -10000.0; <br> <br> // 由于是单色,调整一下 j 与 i 可以看的明显一些<br> for(double j = 0; j < 360; j+=0.2) { <br> for(double i = 0; i < 360; i+=0.1) { <br> double x = (1 + a*Math.cos(Math.toRadians(i))) * <br> Math.sin(Math.toRadians(j)); <br> double y = a * Math.sin(Math.toRadians(i)); <br> double z = (1 + a*Math.cos(Math.toRadians(i))) * <br> Math.cos(Math.toRadians(j)); <br><br> // 立体旋转,从斜角绘制,调整绘图中心至视窗中心<br> double pointX = orgX + k * x;<br> double pointY = orgY - k * <br> (y*Math.cos(angleX) - z*Math.sin(angleX));<br> <br> // Z buffer处理<br> int index = (int) (pointX + <br> pointY * getSize().width);<br> if(z > zbuf[index]) {<br> g.drawLine((int)pointX, (int)pointY, <br> (int)pointX, (int)pointY);<br> zbuf[index] = z;<br> }<br> } <br> }<br> }<br>}<br></pre>
<br>
<br>
<img style="width: 607px; height: 468px;" alt="" src="images/zBufferMethod-1.jpg"><br>
<br>
<br>
</body>
</html>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?