【问题标题】:Tearing and jitter in a simple processing animation简单处理动画中的撕裂和抖动
【发布时间】:2016-04-29 20:11:19
【问题描述】:

我是处理新手。我用弹跳球编写了以下代码,但动画并不流畅。我已经在多台计算机上运行了该应用程序,我偶尔会看到一些球出现抖动或撕裂。 我不认为它与计算时间有关,因为每帧涉及的计算并不多。而且,我已经读过处理已经是双缓冲了。

以下是相关代码:

 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);

   }   

 }

如何消除抖动和撕裂?如何确保以最佳方式使用显卡驱动程序。请注意,我使用带有 MATE 桌面管理器的 Linux Mint 17.3。相同的操作系统在所有经过测试的 PC 和相同的行为上。

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

 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);
   }   

 }

【问题讨论】:

  • 这段代码在 Windows 10 上对我来说运行良好。你能截个图看看你在说什么吗?也许修改您的代码以使用导致该行为的硬编码值,而不是使用 random() 函数。
  • @KevinWorkman 无论球的大小如何,行为都是一致的。每次运行该应用程序时,我都会感到撕裂。我没有在 Windows 上测试它。我无法截屏。使用 VLC 以 ​​60fps 的视频录制无法捕获它。这是一个水平撕裂,球的下部被转移。
  • 如果我们不能重复该行为,这将很难调试。哪个球?随机运动是否完全相关,或者您可以硬编码运动方向吗?你能用一个球创建一个更小的例子吗?这里有很多额外的代码。这一切都与你的问题有关吗?如果没有,你能简化这个例子吗?
  • @KevinWorkman 它随机发生在一些球上。另请参阅:stackoverflow.com/questions/20551224/… 似乎处理了垂直同步问题。该解决方案不适用于处理 3。
  • 这似乎是一个不同的问题。你能发布一个minimal reproducible example 你试图调用的产生错误的代码吗?

标签: processing jitter tearing


【解决方案1】:

事实证明,直接在图形上绘制许多圆圈会导致问题。为每个圆圈在单独的 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);
   }   

 }

【讨论】:

    【解决方案2】:

    我没有发现代码更新和渲染圆圈有任何问题。

    使用 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 上。 尝试处理 3 中的 FX2D 渲染器,看看它与其他两个渲染器的比较。

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

    【讨论】:

    • 我尝试在 Windows 上运行它,值得注意的是,大约每 2-3 秒,球会冻结几分之一秒。我检查了 CPU 利用率,它接近于零。我在 Linux 上尝试了不同的渲染器,但无济于事。
    • 好的,我刚刚在 Windows 上添加了 FX2D 标志,现在它冻结的频率降低了,再次冻结了几分之一秒。
    • 在 Linux 上添加了帧速率线,我得到 59fps-60fps。将帧速率设置为 100 fps,我得到 99 fps-100 fps。因此,它似乎与计算能力无关,计算非常简单。
    • 不错的一个! (+1) (想起this answer 有一个美好的时刻)
    • 好吧,坏消息:当我从 800x600 切换到全屏时,问题又出现了。然后我尝试在一个单独的 PGraphics 对象上绘制屏幕外的所有内容,然后在屏幕上绘制整个图像。徒劳无功。我回到第一方。我删除了我的问题回答标记,因为它不再值得了:-)
    猜你喜欢
    • 2011-01-08
    • 2011-08-13
    • 2011-07-10
    • 1970-01-01
    • 2012-12-09
    • 2011-04-09
    • 2018-10-17
    • 2013-08-30
    • 1970-01-01
    相关资源
    最近更新 更多