Align box with vector

edited January 2017 in How To...

Hi forums :)

I'm new to 3D and can't get my head around this very basic 3D logic problem. Say I have two 3D vectors, and I want to draw an elongated box or rod connecting the two. How? In 2D it's easy - get the angle with simple trigonometry, push matrix, rotate, draw, pop matrix.

I understand that in 3D two angles are needed, and I've come across some different ways of calculating them. I can't get any reasonable results though - I think because the first rotation rotates the entire system and makes that second angle I calculated invalid.

Another way of wording it - how can I align the matrix's rotation with a specific unit vector?

What I get:

What I want:

(images stolen from here: https://forum.openframeworks.cc/t/rotate-3d-object-to-align-to-vector/5085 , this guy had the same problem but that environment could be asked to rotate along an arbitrary axis which doesn't seem possible in processing)

Tagged:

Answers

  • edited January 2017 Answer ✓

    Oh, I solved it! What's the etiquette around here, should I delete the thread or just post my solution for others to see?

    For now I'll post it:

    This code draws a sphere at pos, and an elongated box between pos and parentPos.

         PVector pos, parentPos
    
         pushMatrix();
    
         translate(pos.x, pos.y, pos.z);
    
         PVector rtVc = pos.copy().sub(parent.pos).setMag(1.0);//unit vector
         float dst = dist(pos.x, pos.z, pos.y, parentPos.x, parentPos.z, parentPos.y);
    
         float rotx = -atan2(rtVc.y, rtVc.z);
         float roty = atan2(rtVc.x, sqrt(rtVc.y*rtVc.y + rtVc.z*rtVc.z));
    
         rotateX(rotx);
         rotateY(roty);
    
         sphere(5);
    
         translate(0, 0, -dst*0.5); //go half the dist to draw box in-between points
    
         box(2, 2, dst);
    
         popMatrix();
    
  • Just found the formulas in an old project, maybe still helpful, since i cannot run your code.

    PVector p1, p2, dir;
    
    void setup() {
      size(800, 800, P3D);
      p1 = new PVector(-200, 100, -200);
      p2 = new PVector(200, 100, -500);
    }
    
    
    
    void draw() {
      background(200);
    
    
      // vary position of sphere
      p1.x = map(mouseX, 0, width, -300, 300);
      p1.y = map(mouseY, 0, height, -300, 300);
    
      // calculate direction and angles
      PVector dir = PVector.sub(p2, p1);
      float pitch = asin(dir.y / dir.mag());
      float yaw = -asin( dir.x / (cos(pitch)*dir.mag()) );
    
    
      // draw the stuff
    
      translate(width/2, height/2, 0);
    
      pushMatrix();
      translate(p1.x, p1.y, p1.z);
      sphere(10);
      popMatrix();
    
      pushMatrix();
      translate(p2.x, p2.y, p2.z);
      rotateX(pitch);
      rotateY(yaw); 
      box(100);
      popMatrix();
    }
    
  • Yes, post solution for others unless homework

  • @benja: Woe, this is amazing. What does this sketch do?

    Let the box look at the sphere wherever you move it?

  • btw the old 2D line command has a version with 6 paramy which is in fact a 3D version. It looks crappy though.

    additionally let me mention a 3D-ine by James :

      void line3D(float x1, float y1, float z1, 
      float x2, float y2, float z2, 
      float weight, color colorLine)
        // drawLine was programmed by James Carruthers
        // see http://processing.org/discourse/yabb2/YaBB.pl?num=1262458611/0#9 
      {
        // scale(90);
    
        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();
        PVector v2 = new PVector ( x1, y1, z1 );
        translate(v2.x, v2.y, v2.z);
        translate(v1.x, v1.y, v1.z);
        rotateZ(the);
        rotateY(phi);
        noStroke();
        fill(colorLine);
    
        box(weight, weight, p1.dist(p2));
        popMatrix();
      } // method
    
  • Impressive!

    Kf

  • edited January 2017

    amazing. It is like a tree in space. A star tree.

    I think Dan Simmons has an Orbital that's a growing tree around a sun. He calls it star tree. IIRC.

    @benja:

    I tried to add to your sketch a Z-component for the sphere, and I don't think that works really. Could you improve that for me please? Or have I made a mistake?

    To invoke the z component of the sphere you need to hold a key while moving the mouse vertically.

    At first the sphere is to near towards you then, so you have to move the mouse UP

    Thank you!

    Best Chrisir ;-)

    // https : // forum.processing.org/two/discussion/20235/align-box-with-vector#latest
    
    
    
    
    PVector spherePos, boxPos, dir;
    
    void setup() {
      size(800, 800, P3D);
      spherePos = new PVector(-200, 100, -200);
      boxPos = new PVector(200, 100, -500);
    }
    
    
    
    void draw() {
      background(200);
      lights();
    
      // vary position of sphere (target)
    
      // mouse x is always on changing sphere x
      spherePos.x = map(mouseX, 0, width, -300, 300);
    
      // mouse y is on changing sphere x OR z !!!!!!!!!!!!!!!
      if (keyPressed)
        spherePos.z = map(mouseY, 0, height, -900, 900);
      else
        spherePos.y = map(mouseY, 0, height, -300, 300);
    
      // calculate direction and angles
      PVector dir = PVector.sub(boxPos, spherePos);
      float pitch = asin(dir.y / dir.mag());
      float yaw = -asin( dir.x / (cos(pitch)*dir.mag()) );
    
    
      // draw the stuff
    
      translate(width/2, height/2, 0);
    
      fill(255);
      stroke(0);
    
      // sphere 
      pushMatrix();
      noStroke(); 
      fill(0, 255, 0);
      translate(spherePos.x, spherePos.y, spherePos.z);
      sphere(10);
      popMatrix();
    
      pushMatrix();
      stroke(0);
      fill(255);
      translate(boxPos.x, boxPos.y, boxPos.z);
      rotateX(pitch);
      rotateY(yaw);
      box(100);
      noStroke();
      fill(255, 0, 0); 
    
      // eyes -----------------
    
      int xOffset=21;
      int yOffset=18;
      int zOffset=57;
    
      pushMatrix();
      translate(-xOffset, -yOffset, zOffset );
      sphere(11); 
      popMatrix();
    
      pushMatrix();
      translate(xOffset, -yOffset, zOffset );
      sphere(11);
      popMatrix();
    
      //
      popMatrix();
    }
    
  • edited January 2017

    I see what you mean, you ave to adjust yaw, if direction is facing positive z-values. Try this:

    [...]

      // calculate direction and angles
      PVector dir = PVector.sub(boxPos, spherePos);
      float pitch = asin(dir.y / dir.mag());
      float yaw = -asin( dir.x / (cos(pitch)*dir.mag()) );
    
      // handle positive z- values
      if (dir.z>0) {
        yaw = PI-yaw;
      }
    

    [...]

    @JLJac: looks great :)

  • Not quite so solved after all :(

    Even rotation on the XY plane, and Z angle attached to moouse. That perpendicular line is supposed to be in the same direction and not wobble.

    There's some strange rotation going on along the Z axis. I vaguely recognize the pattern (could it be a tangent?) but I'm too bad at trigonometry to figure out exactly what's going on. If I could figure out the formula for the wobble I could just apply the opposite rotation. I've tried brute forcing the problem (applying a bunch of random trigonometry operations to that z rotation) but to no avail.

    Here's what my code looks like:

    Any ideas?

Sign In or Register to comment.