A question on pixels and incrementing


#1

Hello all, new to the world of Processing and have a quick question which I am hoping will have just as quick of an answer.

So…
Working with PVector objects, trying to get a understanding of motion within the Processing environment.
Now, let’s make the simplest of motion examples with a ball that starts in the centre-top of the screen at rest and falls and travels to the right at a 5:1 ratio, gaining speed until reaching its predefined maximum fall speed and stays at that speed, it also wraps around the screen when in reaches the edges…

Ball b;

void setup(){
    size(400,400);
    b = new Ball();
}

void draw(){
    background(255);
    b.update();
    b.checkEdges();
    b.display();
}

class Ball{
    PVector loc;
    PVector vel;
    PVector acc;
    float maxSpeed;

    Ball(){
        loc = new PVector(width/2, 5);
        vel = new PVector(0,0);
        acc = new PVector(0.001, 0.005);
        maxSpeed = 15;
    }

    void update(){
        vel.add(acc);
        vel.limit(maxSpeed);
        loc.add(vel);
    }

    void checkEdges(){
        if(loc.x > width){
            loc.x = 0;
        }else if(loc.x < 0){
            loc.x = width;
        }

        if(loc.y > height){
            loc.y = 0;
        }else if(loc.y < 0){
            loc.y = height;
        }
    }

    void display(){
        fill(175);
        ellipse(loc.x, loc.y, 10, 10);
    }
}

Now, I understand what’s going on in the code here completely, and I understand the way vectors work… What I am slightly confused about though is the fact that the vectors we are using here are holding values to be used as co-ordinates based on an array of pixels and we are incrementing by fractions of a pixel. So, the values in loc.x and loc.y are floating point numbers with up to 5 point precision (from the values I’ve seen using a println() statement), and those values are being used as the centre of the ellipse being drawn each frame.
How can you have a fraction of a pixel? Or is the value truncated, or rounded, or floored, or modified in any other way (cast to an int?) before being used as a pixel location, and because the values are incrementing many times per second (based on frame rate) the intermediate values (the real numbers between the integers) are basically ignored?


#2
size(200,200);
background(0);
noStroke();
fill(255);
ellipse(20,20,20,20);
ellipse(20,50.5,20,20);
ellipse(20.4,80.4,20,20);
ellipse(20,110,20.4,20.4);

If you run this and take a screen shot and look at it magnified a bit, you’ll see that fractions of a pixel do make a difference - a very, very small difference. Basically, when you just normally draw a shape, you’re not getting an exact shape - its edges are being smoothed out a bit so it doesn’t look pixelated.

Now try this:

size(200,200);
background(0);
noStroke();
noSmooth();
fill(255);
ellipse(20,20,20,20);
ellipse(20,50.5,20,20);
ellipse(20.4,80.4,20,20);
ellipse(20,110,20.4,20.4);

Now the difference is more obvious… but it looks awful. But you still aren’t getting an “exact” shape - it’s pixelated now!


#3

Interesting. Thank you.

So we are actually working with fractions of pixels?

I can understand when the values are just a single point of precision, as you have, but 5 points of precision? And I can also understand when the values are being used in calculations, where those fractional parts make a difference on the end result. But it seems strange to me when they are being used as x,y co-ords in a pixel space and the values are changing in such small increments.

So, the values are definitely not being modified in any way when being passed into the ellipse function (or any other shape) as the co-ords to be drawn at?


#4

Yes, but don’t think in terms of pixels. If you have one ellipse at (0,0) and one at (0,0.1), the second ellipse is lower that the first. You might not be able to see it at all when you’re working with a 1 distance = 1 pixel zoom level, but you certainly can see it if you look closer.

void setup() {
  size(400, 400);
  noStroke();
}

void draw() {
  background(0);
  if ( mousePressed ) {
    scale(100);
  }
  fill(255, 0, 0);
  ellipse(2, 2.1, 2, 2);
  fill(255);
  ellipse(2, 2, 2, 2);
}

Also, notice that even at 100X zoom, these ellipses are still round! They may only have a size of 2, but that won’t always mean they appear two pixels wide!


#5

Ok.
This makes perfect sense now that you have introduced me to scale()
Thank you very much for your assistance in clearing this matter up.


#6

An interesting (if somewhat unusual) genre of Processing sketch is to calculate and display things on a unit square (1.0 x 1.0). However, the behaviors of extreme scaling can sometimes be surprising, if I recall correctly – especially when things like stroke caps or joins get involved.