Line thickness in P3D

Hello everyone!

Been a little while, and I enjoy exploring what Processing 3 has brought us. Have a rather simple question though transitioning from the old OpenGL way of thinking to the new P3D rendering – one being line thickness in 3D. The classic way OpenGL rendered lines was without an actual thickness in the 3D sense of the word; a line going away from you would have a constant thickness and not get thinner as it was farther away (which I admit, in most cases would be desirable). Now the line thickness does scale according to distance from the camera by default.

My question is whether the classic behaviour is still possible to enable, without having to do funky post processing/screenX kind of tricks?

1 Like

just for completeness sake I want to mention (what you already know) that there is a 2D version and a 3D version of the line command. The latter has 6 parameters: x1,y1,z1 , x2,y2,z2. See reference line(): https://www.processing.org/reference/line_.html. Unfortunately, line() is not mentioned in the 3D Primitives section of the reference (same with point()).

There is a fancy 3D line function that is easy to handle. (I think 1 or 2 things are not correct but it looks cool)

see: https://github.com/Kango/Processing-snippets/blob/master/ThreeDLine/ThreeDLine.pde

Thanks for you reply! Upon re-reading my post I realised my ‘simple question’ wasn’t actually worded all that clearly. What I am after is indeed when using the 3D version of the line, and creating say a line that starts very far away and ends up at the camera, for that line not to appear thicker when it is close, but instead be always exactly the 1px thick as set by lineThickness(), no matter how far away from the camera it is.

The context in this case would be a 3D grid that I’m drawing, that I want to have behave with the lines always being ‘hairlines’, like they are in C4D etc.

1 Like

I wasn’t reading your post properly, just read “line thickness in 3D” and - click! - I was writing. Sorry.

I don’t know whether that’s possible. Maybe using a 2D line with previously stored screenX and screenY or with a transparent PImage… very complicate…

I know right! The “odd” thing is that point() does still behave like it use to; zooming out or into a scene does not change the size of a point. It simply is whatever you set the strokeWidth to be.

Or use set perspective orthogonal or so?

Can’t remember

I’m not sure if that is possible with P3D.

I do know that if you have the 3D coordinates for a line (float[6]) then you can retrieve the 2D coordinates using screenX / screenY.

float[] screenLine(float[] ln) {
  return screenLine(ln[0], ln[1], ln[2], ln[3], ln[4], ln[5]);
}
float[] screenLine(float x1, float y1, float z1, float x2, float y2, float z2) {
  float[] result = new float[]{
    screenX(x1, y1, z1), 
    screenY(x1, y1, z1), 
    screenX(x2, y2, z2), 
    screenY(x2, y2, z2)
  };
  return result;
}

So, you could enter a 3D scene with translations and rotations, express a bunch of 3D lines, and, rather than drawing them, save them to a float[][] array. Then after you exit (popMatrix), you can loop over your line data and render as 2D lines.

Here is a simple example with one line to inspect what is going on when you draw a 3D line inside a transform, then draw it again in 2D (flat) outside the transform.

/**
 * Flat 2D Line from 3D Line
 * 2019-07-31 Processing 3.4
 * note that screenX/Y can return bad values if the 3D points
 * are outside the view. You can view this bug by increasing
 * the line dim=500.
 */

PVector rot;
float dim = 50;

void setup() {
  size(400, 400, P3D);
  rot = new PVector(-1, 0, 0);
  frameRate(30);
}

void draw() {
  background(192);

  pushMatrix();

  // center and pulse in-out
  translate(width/2.0, height/2.0,sin((frameCount/120.0)%4000)*200);
  // increment rotation and apply
  rot.add(0.01, 0.02, 0.03);
  rotateX(rot.x);
  rotateY(rot.y);
  rotateZ(rot.z);

  pushStyle();
  // draw 3D line
  stroke(0);
  strokeWeight(1);
  sphere(30);
  float[] ln = new float[]{-dim, -dim, -dim, dim, dim, dim};
  line(ln[0], ln[1], ln[2], ln[3], ln[4], ln[5]);
  // save 3D line as 2D coordinates
  float[] flatln = screenLine(ln);
  popStyle();

  // leave transform
  popMatrix();

  // draw 2D line with captured coordinates
  pushStyle();
  strokeWeight(20);
  stroke(255, 0, 0, 32);
  line(flatln[0], flatln[1], flatln[2], flatln[3]);
  println(flatln[0], flatln[1], flatln[2], flatln[3]);
  popStyle();
}


float[] screenLine(float[] ln) {
  return screenLine(ln[0], ln[1], ln[2], ln[3], ln[4], ln[5]);
}
float[] screenLine(float x1, float y1, float z1, float x2, float y2, float z2) {
  float[] result = new float[]{
    screenX(x1, y1, z1), 
    screenY(x1, y1, z1), 
    screenX(x2, y2, z2), 
    screenY(x2, y2, z2)
  };
  return result;
}
1 Like

Hi Jeremy,

Thank you - I appreciate the effort you put into the reply and yes, that would create the effect I’m after. That said I was hoping to find a way to achieve it without having to add so much computation to the sketch, but afraid you might be right.

That said, it is strange how P3D seems to render points still the same way it used to when directly using OpenGL as a renderer?

I’m not sure. Perhaps check the P3D / PGraphics 3D source code on Github? I had assumed it related to OpenGL internals, but I don’t know that code well.