Image quality with line(); & (TRIANGLE_STRIP);

Hi there! I’m wondering how I can create a higher resolution image in processing. Currently, I am creating very pixelated nets. How can I make crisper nets?


// a class to representing a point on our grid.
// This should/would/could be done better by defining it as faces (of a triangle mesh).
// but would it keep as simple as possible 
class GridPoint {
  float x, y, v;
  public GridPoint(float px, float py, float pv) {
    x = px;  // x-pos of the grid point
    y = py;  // y-pos of the grid point
    v = pv;  // height of the grid point
  }
}

//helper variables
float halfWidth, halfHeight;
boolean mode = false;
// storage of out grid
int rows, cols;
GridPoint[][] grid;
// image used for texture and heightmap
PImage img;

void setup() {
  size(1000, 1000, P3D);
  halfWidth  = width/2.;
  halfHeight = height/2.;
  initGrid(8.);
  // use textureMode IMAGE as the grid is not normalized
  textureMode(IMAGE);
}

void initGrid(float scl) {
  // load the image, used for texture and heightmap.
  // usually more than one picture will be used. One for heightmap, one for normalmap and one with the texture.
  // for simplicity it has the same size than our grid to not make the code more math intensive.
  // to get this work our image is somehow a bit blurred (like noise is), otherwise the mesh isn't smooth enough
  img = loadImage("avatar_cool.png");
  img.loadPixels();
  // initialize our gridpoints
  rows = floor(height/scl);
  cols = floor(width/scl);
  grid= new GridPoint[rows][cols];
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      int sx = floor(x*scl);
      int sy = floor(y*scl);
      // set x and y coordinates (center origin) and the height of the current point.
      // height is the normalized brightness value [0..1] of the pixel color from the image.
      // Subtract 0.5 to align it to center [-0.5..0.5]
      // scaling it by 50, so the range is [50.0*(-0.5)..50.0*(0.5)]
      grid[y][x] = new GridPoint(-halfWidth+sx+scl/2, -halfHeight+sy+scl/2, 500.*(brightness(img.get(sx, sy))/255-0.7));
    }
  }
}

void draw() {
  background(0);
  // set the origin to the center of the screen, and move it 400px far away on z-axis
  translate(halfWidth, halfHeight, 0.05);  // zoom in (lower numbers) zoom out (higher numbers around 200)
  

  // switch between mesh and texured mode
  //if (frameCount % int(TAU*100.) == 0) {
  //  mode = !mode;
  //}

  if (mode) {
    //if textured mode no strokes and a light from viewpoint to object
    noStroke();
    directionalLight(255, 255, 255, 0, 0, -1);
  } else {
    // if mesh mode only show strokes
    noFill();
    stroke(250);
    strokeWeight(1.5);
    smooth(10);
  }

  // apply the rotation after lighting, otherwhile the light gets also rotated, which we not want.
  // tipping 30degree back on X-axis
  //rotateX(radians(30));
  // tipping left/right a bit per frame from -PI/4 - +PI/4 on Y-axis
  //rotateY(sin(frameCount/100.)*QUARTER_PI);

  // build the surface/terrain by triangle strips to display it
  for (int y = 0; y < rows-1; y ++) {
    beginShape (QUAD_STRIP); // or (TRIANGLE_STRIP),(QUAD_STRIP), 
    if (mode) {
      // on textured mode set the texture
      texture(img);
    }
    // common triangle strips
    for (int x = 0; x < cols; x++) {
      GridPoint ca = grid[y][x];
      GridPoint cb = grid[y+1][x];
      vertex(ca.x, ca.y, ca.v, ca.x+halfWidth, ca.y+halfHeight);
      if (mode) {
        // on textured mode we need to set the normal vector, so the light knows how to behave on hittng the surface
        // usually there are better calculation than this cheap hack
        // comment it out to see the difference if normals are messed up
        PVector na = new PVector(ca.x-cb.x, ca.y-cb.y, 0).sub(new PVector(ca.x-cb.x, ca.y-cb.y, 1)).normalize();
        normal(na.x, na.y, na.z);
      }
      vertex(cb.x, cb.y, cb.v, cb.x+halfWidth, cb.y+halfHeight);
      if (mode) {
        // on textured mode we need to set the normal vector, so the light knows how to behave on hittng the surface
        // usually there are better calculation than this cheap hack
        // comment it out to see the difference if normals are messed up
        PVector nb = new PVector(cb.x-ca.x, cb.y-ca.y, 0).sub(new PVector(cb.x-ca.x, cb.y-ca.y, 1)).normalize();
        normal(nb.x, nb.y, nb.z);
      }
    }
    endShape();
  }
}

Also, I am having no luck with smooth();

Hi @asymmetric,

You can’t set smooth where you are putting it …(should be showed on your console output) read reference…

Cheers
— mnse

PS: depending on your graphic card I bet 10 is not even possible … most only supports 4x anti-aliasing some 8x anti-aliasing …

1 Like

Hi @mnse! The smooth(); reference helped improve my image quality. Is there any other way that I can improve my image quality in processing?

The image from above is created with the processing’s P3D renderer. Would the image be higher quality if I made it in OpenGL and used anti-aliased smooth(8);?

Hello @asymmetric,

There is a tutorial about the renderers here:
https://processing.org/tutorials/rendering

I have a very simple pixel viewer here:

Replace the shapes with a line and experiment a little.

You are also limited by the pixel density of your device; you can’t do better than a single pixel and smoothing will just give the appearance of a “smoother” line. Try the pixel viewer to see this.

:)

1 Like