撕裂和抖动在一个简单的处理动画



我刚开始处理。我用弹跳球编写了以下代码,但动画并不流畅。我在各种电脑上运行过这个应用程序,偶尔会看到一些球的抖动或撕裂。我不认为这与计算时间有关,因为每帧的计算并不多。此外,我已经读到的处理已经是双重缓冲。

以下是相关代码:

 final int MAX_BALLS = 50;
 final int DISPLAY_WIDTH = 800;
 final int DISPLAY_HEIGHT = 600;
 final float MIN_SPEED = 1;
 final float MAX_SPEED = 5;
 final float MIN_SIZE = 30;
 final float MAX_SIZE = 50;
 Ball[] balls = new Ball[MAX_BALLS];
 void setup() {
   size(800, 600);
   stroke(255);
   background(0, 0, 0);
   for (int i=0; i<balls.length; i++) {
     balls[i] = new Ball(random(MIN_SIZE, MAX_SIZE), random(0, DISPLAY_WIDTH), random(0, DISPLAY_HEIGHT), random(MIN_SPEED, MAX_SPEED), random(MIN_SPEED, MAX_SPEED), 0, DISPLAY_WIDTH, 0, DISPLAY_HEIGHT);
   }
 } 
 void draw() {
   clear();
   for (int i = 0; i<balls.length; i++)
     balls[i].draw();
 }
 class Ball {
   private float size;
   private float x;
   private float y;
   private float vx;
   private float vy;
   private float minx;
   private float maxx;
   private float miny;
   private float maxy;
   private float r;
   private float g;
   private float b;
   public Ball(float size,float x, float y, float vx, float vy, float minx, float maxx, float miny, float maxy) {
     this.size = size;
     this.x = x;
     this.y = y;
     this.vx = vx;
     this.vy = vy;
     this.minx = minx;
     this.maxx = maxx;
     this.miny = miny;
     this.maxy = maxy;
     r = (int) random(30, 255);
     g = (int) random(30, 255);
     b = (int) random(30, 255);
   }
   void draw() {
     x = x + vx;
     if (x + size/2 > maxx) {
       vx = -vx;
       x = 2 * maxx - (x + size);
     } else if (x - size/2 < minx) {
       vx = -vx;
       x = 2 * minx - (x - size);
     }
     y = y + vy;
     if (y + size/2 > maxy) {
       vy = -vy;
       y = 2 * maxy - (y + size);
     } else if (y -size/2 < miny) {
       vy = -vy;
       y = 2 * miny - (y - size);
     }
     stroke(r,g,b);
     fill(r,g,b);
     ellipse(x, y, size, size);
   }   
 }

如何消除抖动和撕裂?如何确保图形卡驱动程序得到最佳使用。注意,我使用Linux Mint 17.3和MATE桌面管理器。在所有测试的电脑上都有相同的O.S.和相同的行为。

[编辑日期:2016年1月5日]在生成屏幕外的圆圈,甚至使用屏幕大小的离线图像后,我仍然会有一些撕裂。这是更新后的代码:

 final int MAX_BALLS = 50;
 final float MIN_SPEED = 1;
 final float MAX_SPEED = 5;
 final float MIN_SIZE = 30;
 final float MAX_SIZE = 50;
 Ball[] balls = new Ball[MAX_BALLS];
 PGraphics img;
 void setup() {
   frameRate(60);
   fullScreen();
   img = createGraphics(width, height);
   img.stroke(255);
   img.smooth();
   for (int i=0; i<balls.length; i++) {
     balls[i] = new Ball(random(MIN_SIZE, MAX_SIZE), random(0, width), random(0, height), random(MIN_SPEED, MAX_SPEED), random(MIN_SPEED, MAX_SPEED), 0, width, 0, height);
   }
 } 
 void draw() {
   img.beginDraw();
   img.background(0,0,0);
   img.clear();
   clear();
   for (int i = 0; i<balls.length; i++)
     balls[i].draw();
   img.text((int)frameRate+"fps",10,15);
   img.endDraw();
   image(img, 0, 0); // Put the whole image at once on the screen
 }
 class Ball {
   private float size;
   private float x;
   private float y;
   private float vx;
   private float vy;
   private float minx;
   private float maxx;
   private float miny;
   private float maxy;
   private PGraphics circle;
   private final int MARGIN = 10; // Margin to avoid circle to be drawn slightly outside the square
   public Ball(float size,float x, float y, float vx, float vy, float minx, float maxx, float miny, float maxy) {
     this.size = size;
     this.x = x;
     this.y = y;
     this.vx = vx;
     this.vy = vy;
     this.minx = minx;
     this.maxx = maxx;
     this.miny = miny;
     this.maxy = maxy;
     int r = (int) random(30, 255);
     int g = (int) random(30, 255);
     int b = (int) random(30, 255);
     circle = createGraphics((int) this.size + 2*MARGIN, (int) this.size + 2*MARGIN);
     circle.beginDraw();
     circle.background(0, 0);
     circle.fill(r, g, b);
     circle.ellipse(MARGIN + this.size/2, MARGIN + this.size/2, this.size, this.size);
     circle.endDraw();         
   }
   void draw() {
     x = x + vx;
     if (x + size/2 > maxx) {
       vx = -vx;
       x = 2 * maxx - (x + size);
     } else if (x - size/2 < minx) {
       vx = -vx;
       x = 2 * minx - (x - size);
     }
     y = y + vy;
     if (y + size/2 > maxy) {
       vy = -vy;
       y = 2 * maxy - (y + size);
     } else if (y -size/2 < miny) {
       vy = -vy;
       y = 2 * miny - (y - size);
     }
     img.image(circle, x - this.size/2 - MARGIN, y - this.size/2 - MARGIN);
   }   
 }

事实证明,直接在图形上绘制许多圆是导致问题的原因。在单独的PGraphics上为每个圆预渲染圆可以解决问题。以下是修订后的代码:

 final int MAX_BALLS = 50;
 final int DISPLAY_WIDTH = 800;
 final int DISPLAY_HEIGHT = 600;
 final float MIN_SPEED = 1;
 final float MAX_SPEED = 5;
 final float MIN_SIZE = 30;
 final float MAX_SIZE = 50;
 Ball[] balls = new Ball[MAX_BALLS];
 void setup() {
   frameRate(60);
   size(800, 600, FX2D);
   stroke(255);
   background(0, 0, 0);
   smooth();
   for (int i=0; i<balls.length; i++) {
     balls[i] = new Ball(random(MIN_SIZE, MAX_SIZE), random(0, DISPLAY_WIDTH), random(0, DISPLAY_HEIGHT), random(MIN_SPEED, MAX_SPEED), random(MIN_SPEED, MAX_SPEED), 0, DISPLAY_WIDTH, 0, DISPLAY_HEIGHT);
   }
 } 
 void draw() {
   clear();
   for (int i = 0; i<balls.length; i++)
     balls[i].draw();
     text((int)frameRate+"fps",10,15);
 }
 class Ball {
   private float size;
   private float x;
   private float y;
   private float vx;
   private float vy;
   private float minx;
   private float maxx;
   private float miny;
   private float maxy;
   private PGraphics circle;
   private final int MARGIN = 10; // Margin to avoid circle to be drawn slightly outside the square
   public Ball(float size,float x, float y, float vx, float vy, float minx, float maxx, float miny, float maxy) {
     this.size = size;
     this.x = x;
     this.y = y;
     this.vx = vx;
     this.vy = vy;
     this.minx = minx;
     this.maxx = maxx;
     this.miny = miny;
     this.maxy = maxy;
     int r = (int) random(30, 255);
     int g = (int) random(30, 255);
     int b = (int) random(30, 255);
     circle = createGraphics((int) this.size + 2*MARGIN, (int) this.size + 2*MARGIN);
     circle.beginDraw();
     circle.background(0, 0);
     circle.fill(r, g, b);
     circle.ellipse(MARGIN + this.size/2, MARGIN + this.size/2, this.size, this.size);
     circle.endDraw();         
   }
   void draw() {
     x = x + vx;
     if (x + size/2 > maxx) {
       vx = -vx;
       x = 2 * maxx - (x + size);
     } else if (x - size/2 < minx) {
       vx = -vx;
       x = 2 * minx - (x - size);
     }
     y = y + vy;
     if (y + size/2 > maxy) {
       vy = -vy;
       y = 2 * maxy - (y + size);
     } else if (y -size/2 < miny) {
       vy = -vy;
       y = 2 * miny - (y - size);
     }
     image(circle, x - this.size/2 - MARGIN, y - this.size/2 - MARGIN);
   }   
 }

我认为代码更新和渲染圆没有任何问题。

使用Processing 2,我已经可以看到不同渲染器的性能差异。

我在draw()的末尾添加了这个,以大致了解帧速率:

text((int)frameRate+"fps",10,15);

它的设置我试过

size(800, 600,JAVA2D);
frameRate(60);

size(800, 600,P2D);
frameRate(60);

注意到JAVA2D的帧速率非常接近60fps,而P2D的则降至约40-45fps

不过这是在OSX上,而不是在Linux Mint上。尝试Processing 3中的FX2D渲染器,看看它与其他两个渲染器的比较情况。

此外,如果Linux Mint计算机上有GPU,驱动程序安装正确,并且您有时间,您可以尝试将代码移植到GLSL,并使用PShader在Processing中渲染它。

最新更新