Beginning (3D) superprogrammer (57 years)

I have been a programmer for 57 years. Therefore, I find the introductory tutorials uninteresting. I have a very focused set of questions.

  • I need to draw lines in 3D space. Just lines. No extrusions. Practically no surface rendering.

  • I need to “walk around” my 3D line drawing. I want to use the mouse to rotate it in all three axes, alternatively, I want to be able to change the camera origin and axis. I do not want to deal with deep theory. I want to say, “Take the drawing I have just done and let me see it from various angles as determined by the mouse interaction”. I want 3D transformations without reading a thick book on quaternions (which I have).

  • I will need to show an animation of lines being drawn, and when a surface is defined (a definite condition I know of) issue a set of calls that fill in the flat space, and even move it into a window of “known sides”, which may or may not have to be assembled into a solid.

  • I will need to run this animation forwards and backwards, e.g., by using the scroll wheel. Or something. I have been writing GUIs for 30 years, and taught courses in GUI-based 2D graphics. I was doing 2D graphics long before I had GUI-based systems to run them on (no, you don’t want the long story of how to do 2D graphics on a character-based terminal).

  • I will need to mark one end of the first line with a solid circle, and then draw the lines from point A to point B with an arrowhead at the end of the line

  • A line is first drawn as a dotted line. Then, once its validity is established, it becomes a solid line. When two lines are successfully accepted, I want to create a transparent plane to show the plane on which the two lines lie, such that I can see other lines drawn behind the plane.

  • This can be standalone, and I will be providing a text file that tells what to do, e.g., “line x0 y0 z0 x1 y1 z1” and have my program draw the line (note that parsing this command line to extract the data is something I could do while sleeping soundly, so don’t worry about how I get the values out of it).

  • I will be using Java, and ideally this will later be incorporated into a Java app that already is generating the lines.

  • I would like to go from zero to seeing the line drawing in 3D, with rotation, in less than a day.

I have been doing 2D graphics for something over 40 years, I can do 2D transformation matrices without slowing down, about as fast as I can type. I have taught courses in 2D graphics, and I have delivered 2D graphics products to my clients (I’m now retired, and doing this for fun). I do not want to have to learn a lot of boilerplate code to get this up and running. Assume that for the first day, I type in the calls that draw the lines. Assume that I could have my program that is creating the lines write the source code, in Java, to make the library calls to do the drawing, thus eliminating the parsing component entirely.

I need a simple example framework for doing this, because it is just a diversion in a much more complex project and I can’t afford too much of a diversion right now.

Once I have the framework, I can reverse-engineer it to figure out what I need to do to enhance it. That’s the easy part. Getting the framework, at the moment, is the hard part.

Programming does not intimidate me. Building a 3D framework from the ground up would not intimidate me if I had more time to give to the process, but I don’t. I need it now. OK, I realize this is “instant gratification”. But it is all I have time to give to it in the next week or two.

Also, for “free and open”, it seems to insist on a donation before I can download it. Perhaps I have misunderstood the word “free”. If it is useful, and solves my problem, I will happily make a donation. But I’m not going to donate if I can’t give it a free test drive to know if it is what I need.

So how do I get started? What’s the best “sample app” to start with?

2 Likes

Hey, and welcome to the processing forum!

Great to have you here!

You can download processing for free, download starts automatically.

  • Also decide whether you go for processing p5.js (javascript I think), python processing or Java processing

code examples in Java processing

I just give you a few code examples to work from.

Parsing is easy too. (Strings don’t like ==, so use if(myString1.equals("Hello")) {....} though, or use switch())

Simple Sketch in 3D

Here is a simple Sketch in 3D.
It looks cool because of the lights() command.

PShape testShapeGroup; 

void setup() {
  // init
  size(800, 600, P3D);

  // Make a group PShape
  testShapeGroup = createShape(GROUP);

  // Make shapes (children)
  PShape rectangle = createShape(BOX, 90, 7, 90); // #1
  rectangle.translate(0, 44, 0);
  rectangle.setFill(color(0, 0, 255));

  PShape circle = createShape(SPHERE, 40 ); // #2 
  circle.setStroke(false);
  circle.setFill(color(255, 0, 0)); 

  // Add as children
  testShapeGroup.addChild(rectangle);
  testShapeGroup.addChild(circle);
} // func 

void draw() {
  // runs on and on 
  background(0);
  lights(); 

  translate(mouseX, mouseY);
  shape(testShapeGroup);
} // func 
//

You can use the line() command. It comes as 2D AND 3D.

see https://www.processing.org/reference/line_.html

Or use this small line with a bit of surface:

void MyBox(float x1, float y1, float z1, float x2, float y2, float z2, float weight, color strokeColour)
// was called drawLine; programmed by James Carruthers
// see http://processing.org/discourse/yabb2/YaBB.pl?num=1262458611/0#9
{
  PVector p1 = new PVector(x1, y1, z1);
  PVector p2 = new PVector(x2, y2, z2);
  PVector v1 = new PVector(x2-x1, y2-y1, z2-z1);
  float rho = sqrt(pow(v1.x,2)+pow(v1.y,2)+pow(v1.z,2));
  float phi = acos(v1.z/rho);
  float the = atan2(v1.y,v1.x);
  v1.mult(0.5);

  pushMatrix();
  translate(x1,y1,z1);
  translate(v1.x, v1.y, v1.z);
  rotateZ(the);
  rotateY(phi);
  noStroke();
  fill(strokeColour);
  // box(weight,weight,p1.dist(p2)*1.2);
  box(weight,weight,p1.dist(p2)*1.0);
  popMatrix();
}

Yes, check out PeasyCam. It’s a library.

There is also QueasyCam like in a first person shooter.

Here is a PeasyCam example for zoom, pan, rotate:



// Demo for PeasyCam

// http://mrfeinberg.com/peasycam/

import peasy.*;


PeasyCam pcam;

// -------------------------------------------

void setup() {
  size(400, 400, P3D);
  pcam = new PeasyCam(this, 1000);
  //  hint(DISABLE_OPTIMIZED_STROKE);
}

void draw() {
  background(255);
  lights();
  drawPyramid(150);

  pcam.beginHUD();
  noLights();
  fill(0);
  text("Use PeasyCam by dragging the mouse, pan etc. ", 12, 12); 
  pcam.endHUD();
}

// -------------------------------------------

void drawPyramid(int t) {

  coor();

  fill(255, 0, 255);
  makeSphere(-t, t, -t);

  strokeWeight(1);
  stroke(0);

  beginShape(TRIANGLES);

  fill(255, 0, 0, 150); // Note that each polygon can have its own color.
  vertex(-t, -t, -t);
  vertex( t, -t, -t);
  vertex( 0, 0, t);

  fill(150, 150);
  vertex( t, -t, -t);
  vertex( t, t, -t);
  vertex( 0, 0, t);

  fill(255, 150);
  vertex( t, t, -t);
  vertex(-t, t, -t);
  vertex( 0, 0, t);

  fill(150, 150);
  vertex(-t, t, -t);
  vertex(-t, -t, -t);
  vertex( 0, 0, t);

  endShape();
}

// -------------------------------------------

void coor() {
  //
  // Draw axis X, Y, Z
  strokeWeight(3);
  stroke(255, 0, 0); // red
  line(0, 0, 0, 400, 0, 0);
  fill(255, 0, 0); 
  makeSphere(400, 0, 0);

  stroke(0, 255, 0); //green
  line(0, 0, 0, 0, 400, 0);
  fill(0, 255, 0);
  makeSphere(0, 400, 0);

  stroke(0, 0, 255); // blue
  line(0, 0, 0, 0, 0, 400);
  fill(0, 0, 255); // blue
  makeSphere(0, 0, 400);
}

void makeSphere(float x, float y, float z) {
  pushMatrix(); 
  translate(x, y, z);
  noStroke();
  sphere (10); 
  popMatrix();
} 
//

when you have an list of points use vertex to connect them:

// Make the shape
PShape myShape; // see https: // www.processing.org/tutorials/pshape/

void setup() {
  size (800, 800, P3D);

  fill(255, 0, 0);

  myShape = createShape();
  myShape.beginShape(); 

  myShape.vertex(100, 100, -300);  // can be a for loop over an array of points (or `ArrayList`)
  myShape.vertex(100, 200, -300);   
  myShape.vertex(100, 100, 0);

  myShape.endShape();
}

void draw() {
  background (0, 0, 0);
  lights();

  pushMatrix();
  translate (width/2, height/2, 0);
  rotateX (radians(map(mouseY, 0, width, 0, 360)));
  rotateY (radians(map(mouseX, 0, width, 0, 360)));

  shape(myShape, 0, 0);

  popMatrix();
}


// arrow

float angle;

// ------------------------------------------------------------

void setup() {
  size(1600, 900, P3D);
}

void draw() {
  background(0);
  lights();

  // this is only to show with the mouse !!
  translate(width/2, height/2); 
  rotateY(map(mouseX, 0, width, -TWO_PI, TWO_PI*2)); 
  rotateX(map(mouseY, 0, height, -TWO_PI, TWO_PI*2)); 

  // the line 
  myLine(new PVector(0, 0, 0), 
    new PVector(10, 210, -510));

  // translate(200, 200, 0);
  // rotateY(angle+=.122);
}

// ------------------------------------------------------------

void myLine(PVector from, PVector to) { 

  // basic line 
  linePV(from, to); 

  // sphere 
  pushMatrix();
  noStroke();  
  translate(from.x, from.y, from.z);
  fill(0, 255, 0); 
  sphere(9); 
  popMatrix();
  stroke(255, 0, 0);

  // draw the arrow head 
  PVector ortho = findOrtogonalPVectorLEFT(from, to);
  PVector behind = PVector.lerp( ortho, from, 0.12 ); 
  linePV(to, behind);

  ortho = findOrtogonalPVectorRIGHT(from, to);
  behind = PVector.lerp( ortho, from, 0.12 ); 
  linePV(to, behind);
}

// ----------------------------------------------------------

void linePV(PVector from, PVector to) { 
  stroke(255, 0, 0);
  strokeWeight(5); 

  line(from.x, from.y, from.z, 
    to.x, to.y, to.z);
  strokeWeight(1); // reset
}

PVector findOrtogonalPVectorLEFT (PVector a, PVector b) {
  PVector dir = PVector.sub(b, a);
  dir.setMag(47);
  PVector c = b.copy();
  c.x -= dir.y;
  c.y += dir.x;

  return c;
}

PVector findOrtogonalPVectorRIGHT (PVector a, PVector b) {
  PVector dir = PVector.sub(b, a);
  dir.setMag(47);
  PVector c = b.copy();
  c.x += dir.y;
  c.y -= dir.x;

  return c;
}

// --------------------------------------------------------------

void arrow() {

  // some color consts
  final color RED = color(255, 0, 0);
  final color GREEN = color(0, 255, 0);
  final color BLUE = color(0, 0, 255);

  final color LIGHTGRAY = color(111);

  // points in 2D
  final int[] x = {
    -50, 0, 50, 25, 25, -25, -25, -50
  };
  final int[] y = {
    0, -50, 0, 0, 50, 50, 0, 0
  };

  // how thick is the arrow (1/2)
  final int halfOfTheThickness = 12; 

  pushMatrix();

  // all no Stroke
  noStroke();

  // arrow Form - ceiling 
  fill(RED); // RED
  beginShape();
  for (int i = 0; i<8; i++) {
    vertex(x[i], y[i], -halfOfTheThickness);
  }
  endShape(CLOSE);
  //
  // arrow Form - floor
  fill(RED); // BLUE
  beginShape();
  for (int i = 0; i<8; i++) {
    vertex(x[i], y[i], halfOfTheThickness);
  }
  endShape(CLOSE);
  //
  // walls of the arrow
  fill(BLUE); //  GREEN
  beginShape(QUAD_STRIP);
  for (int i = 0; i<x.length; i++) {
    vertex(x[i], y[i], -halfOfTheThickness);
    vertex(x[i], y[i], halfOfTheThickness);
  }
  endShape(CLOSE);

  popMatrix();
} // func
//

I am not sure about the plane you mentioned.

Here is a dotted line though.



// ------------------------------------------------------------

void setup() {
  size(1200, 400, P3D);
}

void draw() {
  background(0);
  lights();

  translate(width/2, 200, 0);
  rotateY(map(mouseX, 0, width, 0, TWO_PI)); 
  rotateX(map(mouseY, 0, height, 0, TWO_PI)); 

  dottedLine(new PVector(0, 0, 0), 
    new PVector(10, 210, -510));
}

// ------------------------------------------------------------------

void dottedLine(PVector from, PVector to) { 
  stroke(255, 0, 0);
  strokeWeight(2); 

  for (int i = 0; i < 100-5; i+=10) {

    //   if (i%10==0) {
    PVector step = PVector.lerp( from, to, i / 100.0 ); 
    PVector step2 = PVector.lerp( from, to, (i+5) / 100.0 );

    //point(step.x, step.y, step.z);
    line(step.x, step.y, step.z, 
      step2.x, step2.y, step2.z);
    // }
  }
  strokeWeight(1); // reset
}
//

use String[] txtFileAsArray = loadStrings("....");, a for-loop and split(), then for-loop again

here is an example

text file content:

line 100 120 122 300 100 120
line 300 320 322 400 400 120

Sketch to read and execute the lines:


import peasy.*;

PeasyCam cam; 

String[] list;
// ------------------------------------------------------------

void setup() {
  size(1400, 900, P3D);
  cam = new PeasyCam(this, 400);

  list=loadStrings("test1.txt");
}

void draw() {
  background(0);
  lights();

  for (String s1 : list) {
    // for (int i = 0; i < 1; i++) {
    String[] oneLine = s1.split(" "); 
    switch (oneLine[0]) {
    case "line":
      PVector start = pvFromString(oneLine[1], oneLine[2], oneLine[3]); 
      PVector stop  = pvFromString(oneLine[4], oneLine[5], oneLine[6]);
      dottedLine(start, stop);
      pvSphere(start);
      pvBox(stop);
      break; 

    default:
      println("Unknown command! " +s1);
      break;
    }//switch
  }//for
}//func

// ------------------------------------------------------------------

void pvSphere (PVector pv) {
  pushMatrix();
  translate(pv.x, pv.y, pv.z);
  noStroke(); 
  sphere(13); 
  popMatrix();
}

void pvBox (PVector pv) {
  pushMatrix();
  translate(pv.x, pv.y, pv.z);
  noStroke(); 
  box(13); 
  popMatrix();
}

PVector pvFromString (String s0, String s1, String s2) {
  PVector pv = new PVector (float(s0), float (s1), float (s2)); 
  return pv;
}

void dottedLine(PVector from, PVector to) { 

  stroke(255, 0, 0);
  strokeWeight(2); 

  for (int i = 0; i < 100-5; i+=10) {

    PVector step = PVector.lerp( from, to, i / 100.0 ); 
    PVector step2 = PVector.lerp( from, to, (i+5) / 100.0 );

    line(step.x, step.y, step.z, 
      step2.x, step2.y, step2.z);
  }
  strokeWeight(1); // reset
}
//

No.
You can download it for free.

Please tell me when I can be of more help.

I am looking forward to see your results.

Warm regards,

Chrisir

4 Likes