doublebuffer.htm
来自「电脑图学(Computer Graphics)是资料结构、演算法与数学的应用」· HTM 代码 · 共 133 行
HTM
133 行
<!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>双缓冲区绘图</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: 双缓冲区绘图</a></h1>
如果我们要绘制的图形很多时,在动画制作时,如果直接画在前景上,可能会发生图形一个一个显现出来的画面,让整个画面不完整呈现。<br>
<br>
这时候可使用双缓冲区(double-buffer)的方法,要准备两个绘图物件,其中一个是前景区,也就是您所看到的画面,另一个绘图物件您看不到,在
画面准备好之前,所有的图形先绘制在您看不到的画面,当所有的图形都绘制完毕,再将所有的图形绘制到前景,此时前景会整个被后绘图区所覆盖,完成一次画面
的播放,下图为简单的示意图: <br>
<img style="width: 474px; height: 239px;" alt="" src="images/doubleBuffer-1.jpg"><br>
<br>
实作双缓冲区的方法依所使用的API而有所不同,在Java中可以用Image物件来完成,而在使用DirectDraw时,可以使用
Surface来建立,下面这个程式是使用Java来制作,这个程式是至今所有文件内容验收,包括了顶点配置、索引阵列、动画、双缓冲区等等,您可以先观
看结果:<a href="dbuf.html">一个绕Y轴旋转的空心立方块</a>。 <br>
<ul>
<li> DoubleBuffer.java
</li>
</ul>
<pre>package onlyfun.caterpillar.graphics.animation;<br> <br>import javax.swing.JApplet; <br>import java.awt.*; <br> <br>class Point3D { <br> public double x, y, z; <br> <br> public Point3D() { <br> x = y = z = 0; <br> } <br> <br> public Point3D(double x, double y, double z) { <br> this.x = x; <br> this.y = y; <br> this.z = z; <br> } <br>} <br> <br>// 立方体类别 <br>class Cubic { <br> public int NFc; // 平面数量 <br> public int NVt; // 顶点的数量 <br> public int Nvt; // 1个平面的顶点数 <br> public Point3D[] Vt; // 顶点的座标 <br> public int[][] Ord; // 顶点索引 <br> <br> public Cubic(int r) { <br> NFc = 6; <br> NVt = 8; <br> Nvt = 4; <br> Vt = new Point3D[NVt]; <br> Ord = new int[NFc][Nvt]; <br> double sq3 = Math.sqrt(3.0); <br> Vt[0] = new Point3D(r/sq3,r/sq3,r/sq3); <br> Vt[1] = new Point3D(r/sq3,r/sq3,-r/sq3); <br> Vt[2] = new Point3D(-r/sq3,r/sq3,-r/sq3); <br> Vt[3] = new Point3D(-r/sq3,r/sq3,r/sq3); <br> <br> for(int i = 0; i < NVt/2; i++) <br> Vt[NVt/2+i] = new Point3D(<br> -Vt[i].x, -Vt[i].y, -Vt[i].z); <br> <br> int[][] ord={{0,1,2,3},{0,3,5,6},{0,6,7,1}, <br> {4,7,6,5},{4,2,1,7},{4,5,3,2}}; <br> <br> for(int i = 0; i < NFc; i++) <br> for(int j = 0; j < Nvt; j++) <br> Ord[i][j]=ord[i][j]; <br> } <br>} <br> <br>public class DoubleBuffer extends JApplet implements Runnable { <br> private Image OffScreen; <br> private Graphics drawOffScreen; <br> private int orgX, orgY; <br> private Cubic cubic; <br> <br> public void init() { <br> setBackground(Color.black); <br> <br> orgX = (int)(getSize().width / 2); <br> orgY = (int)(getSize().height / 2);<br> <br> OffScreen = createImage(getSize().width,<br> getSize().height); <br> drawOffScreen = OffScreen.getGraphics(); <br> <br> cubic = new Cubic(100); <br> } <br> <br> public void start() { <br> (new Thread(this)).start(); <br> } <br> <br> public void run() { <br> int[] px = new int[4], <br> py = new int[4]; <br> Point3D[] tp = new Point3D[4]; <br> <br> drawOffScreen.setColor(Color.yellow); <br> <br> // 旋转以斜角绘制图形 <br> double sinAx = Math.sin(Math.toRadians(30));<br> double cosAx = Math.cos(Math.toRadians(30));<br> <br> double[] cosAys = new double[360];<br> double[] sinAys = new double[360];<br> <br> for(int i = 0; i < 360; i++) {<br> cosAys[i] = Math.cos(Math.toRadians(i));<br> sinAys[i] = Math.sin(Math.toRadians(i));<br> }<br> <br> int angle = 330;<br> <br> double sinAy = sinAys[angle];<br> double cosAy = cosAys[angle];<br> <br> // 动画回圈 <br> while(true) { <br> drawOffScreen.clearRect(0, 0, <br> getSize().width, getSize().height); <br> for(int i = 0; i < cubic.NFc; i++) { <br> for(int j = 0; j < cubic.Nvt; j++) { <br> // 利用索引array取出正确的顶点 <br> tp[j] = cubic.Vt[cubic.Ord[i][j]]; <br> <br> // 旋转以斜角绘制图形 <br> px[j] = (int) (tp[j].x*cosAy <br> + tp[j].z*sinAy); <br> py[j] = (int) (tp[j].y*cosAx <br> - (-tp[j].x*sinAy <br> + tp[j].z*cosAy) * sinAx); <br> px[j] = px[j] + orgX; <br> py[j] = -py[j] + orgY; <br> } <br><br> // 在缓冲区上缩图 <br> drawOffScreen.drawPolyline(px, py, 4); <br> } <br> <br> // 暂停 20 毫秒 <br> try { <br> Thread.sleep(20); <br> } <br> catch(InterruptedException e) { <br> } <br> <br> repaint(); // 重绘画面 <br> // 绕 y 轴转动 <br> angle = (angle+1) % 360; <br> sinAy = sinAys[angle];<br> cosAy = cosAys[angle];<br> } <br> } <br> <br> // 重新定义update() <br> public void update(Graphics g) { <br> paint(g); <br> } <br> <br> public void paint(Graphics g) { <br> // 将缓冲区画面绘到前景 <br> g.drawImage(OffScreen, 0, 0, this); <br> } <br>}</pre>
<br>
<br>
</body>
</html>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?