Graphics quality compared to OpenFrameworks

I am working on a sketch that is basically a very simple particle system, but the trails are drawn as lines. I wrote one version of the code in processing and one in openFrameworks. The code is nearly identical, but the output isn’t. While I expected some differences, the processing version does not render smooth lines, whenever the particles are moving quickly, there are some clearly visible stripes/artifacts/gaps in the lines. Also, the aliasing is quite noticeable (I enabled smooth(16)).

Is there anything I can do to improve the output of the processing sketch? I’d prefer to work in an environement without xcode and with shorter compile-time, but if the difference in quality is that noticeable, I can’t justify not choosing openFrameworks.

Images:

2 Likes

Welcome to the community. Is it possible to see the source code that you are using in Processing? It would also be nice to see screen shots of the two outputs so that we can compare them.

Sure. In the original post is a link to an imgur album with screenshots. This is the source code:

PVector[] pos;
PVector[] vel;
PVector[] prevPos;
float[] mass;
int number;

void setup() {
  size(800, 600);
  surface.setResizable(true);
  background(0);
  stroke(255, 255, 255, 5);
  strokeWeight(1);
  smooth(16);
  number = 500;
  pos = new PVector[number];
  vel = new PVector[number];
  prevPos = new PVector[number];
  mass = new float[number];
  
  for (int i = 0; i < number; i++) {
    pos[i] = PVector.random2D().mult(5.0);
    vel[i] = PVector.random2D();
    prevPos[i] = pos[i];
    mass[i] = random(0.3);
  }
}

void draw() {
  PVector mouse = new PVector(mouseX, mouseY);
  for (int i = 0; i < number; i++) {
    PVector acc = PVector.sub(mouse, pos[i]);
    acc.mult(0.01);
    acc.mult(mass[i]);
    vel[i].add(acc);
    pos[i].add(vel[i]);
    
    line(prevPos[i].x, prevPos[i].y, pos[i].x, pos[i].y);
    
    vel[i].mult(0.97);
    prevPos[i] = pos[i];
  }
}

Sorry, I didn’t scroll down. I can see that there is a clear difference and I would be surprised if we can’t match it, but will defer to others with more experience for their comments.

Obviously OF and Java2D (Processing) render lines differently so it would seem we have to tweak the code between to get similar results.

I got this in Processing by increasing the lines opacity with stroke(255, 255, 255, 14); which seems an improvement, at least to me :grin:

2 Likes

Yes, that does improve the overall look, but sadly the lines still seem to be a series of spaced points rather than continuous lines. Is there anything I can to about that?

I think it is very much such it and see. I tried changing the initial velocity with

vel[i] = PVector.random2D().mult(3);

and doubled the frame rate by adding the following statement at the end of the setup() function

frameRate(120);

and got this which i think is a slight improvement

1 Like

Hello @woodwindblues,

Take a look at my comments and modifications in the code you provided:

// Code from:
// https://discourse.processing.org/t/graphics-quality-compared-to-openframeworks/34308/3
// Some modifications made

PVector[] pos;
PVector[] vel;
PVector[] prevPos;
float[] mass;
int number;

void setup() {
  size(800, 600);
  surface.setResizable(true);
  background(255);
  stroke(255);
  strokeWeight(2);
  //smooth(16);
  number = 500;
  pos = new PVector[number];
  vel = new PVector[number];
  prevPos = new PVector[number];
  mass = new float[number];
  
  for (int i = 0; i < number; i++) {
    pos[i] = PVector.random2D().mult(5.0);
    vel[i] = PVector.random2D();
    prevPos[i] = pos[i];
    mass[i] = random(0.3);
  }
}

void draw() 
  {
  PVector mouse = new PVector(mouseX, mouseY);
  for (int i = 0; i < number; i++) 
    {
    //PVector mouse = new PVector(mouseX, mouseY);
    PVector acc = PVector.sub(mouse, pos[i]);
    acc.mult(0.01);
    acc.mult(mass[i]);
    vel[i].add(acc);
    pos[i].add(vel[i]);
    
   // Check to see if vector updated:
    if (prevPos[i].x != pos[i].x)
    println(prevPos[i].x, prevPos[i].y, pos[i].x, pos[i].y);
    
    stroke(255, 0, 0, 5);
    line(prevPos[i].x, prevPos[i].y, pos[i].x, pos[i].y);
    
    vel[i].mult(0.97);
    //Try it with and without copy()
    prevPos[i] = pos[i].copy();
    //prevPos[i] = pos[i];
    }
  }

Take a look at where I used copy();

References:

:)

2 Likes

Well spotted @glv I have slightly modified your code to avoid creating new objects in the draw method. The copy is now made in setup and the pos[] contents is copied to prevPos[] in draw.

PVector[] pos;
PVector[] vel;
PVector[] prevPos;
float[] mass;
int number;

void setup() {
  size(800, 600);
  surface.setResizable(true);
  background(0);
  stroke(255, 255, 255, 5);
  strokeWeight(1);
  smooth(16);
  number = 500;
  pos = new PVector[number];
  vel = new PVector[number];
  prevPos = new PVector[number];
  mass = new float[number];

  for (int i = 0; i < number; i++) {
    pos[i] = PVector.random2D().mult(5.0);
    vel[i] = PVector.random2D();
    prevPos[i] = pos[i].copy();
    mass[i] = random(0.3);
  }
}

void draw() {
  PVector mouse = new PVector(mouseX, mouseY);
  for (int i = 0; i < number; i++) {
    PVector acc = PVector.sub(mouse, pos[i]);
    acc.mult(0.01);
    acc.mult(mass[i]);
    vel[i].add(acc);
    pos[i].add(vel[i]);

    line(prevPos[i].x, prevPos[i].y, pos[i].x, pos[i].y);

    vel[i].mult(0.97);
    prevPos[i].set(pos[i]);
  }
}
1 Like

Thank you, now it looks almost as good as the OF version. I checked the references you linked, but I still don’t quite unterstand, why the original code is slower.

Does

prevPos[i] = pos[i]

point prevPos to the vector in pos instead of copying it and that makes it slower?

Hello,

The example I provided illustrated that you were not copying the PVector and I was addressing that issue only.

The Nature of Code references discusses this in the 1.9 Static vs. Non-Static Functions section.

The “slower” is a different issue.

:)

Both prevPos[i] and pos[i] are references to a PVector object. When you execute the code above you copy the reference not the object. It means that both prevPos[i] and pos[i] refer to the same PVector object.

The statement
prevPos[i] = pos[i].copy();

creates a new PVector object with its own reference which is stored in prevPos[i]. So now both prevPos[i] and pos[i] refer to different objects.

2 Likes