Peasy cam: rotate and zoom to what actually happens

Hello all.

Let's say I draw a 3D scene that I don't know beforehand. I just know the min and max position (how long it stretches out) in each direction x y z.

How can I get from these 6 points to tell Peasy Cam its zoom and rotation?

Thanks....

Chrisir

Answers

  • edited August 31

    Hello,

    Okay, I obviously need to ask that again.

    What would be the solution without PeasyCam, just with the normal camera in P3D please?

    My goal is to place the camera automatically in a way that the whole scene is visible but not much more; so I need the eye and center/ look at of the camera to be placed.

    The center should be easy (average of min and max for x and y and z) but the eye / camera position is a problem for me.

    (My final goal is to be able to make a good screenshot automatically)

    Thanks to you all!

    Chrisir ;-)

  • Do you have a camera angle (pitch) in mind? Straight on, or angling down? That probably changes the optimal camera distance if you don't want any clipping of the cube volume. Does the scene always fill the entire volume? Should the camera be pointed at the center of the cube, or is it pointed at a center-offset point?

  • Do you have a camera angle (pitch) in mind? Straight on, or angling down?

    I don't mind really. Straight on like the default.

    Does the scene always fill the entire volume?

    It belongs to the Turtle project where you helped me a great deal indeed. So it mostly are single lines in that cube volume. Or some planes. But the Turtle log-files / protocols the min and max ranges for x, y and z. So the volume is mostly empty but the min and max is known for x, y and z. So, yes, I guess we need the entire volume.

    Should the camera be pointed at the center of the cube, or is it pointed at a center-offset point?

    center of the cube.

  • initial thoughts.

    given an wider than tall window, rotate until the longest axis is x, next longest is y (and thus narrowest is in/out)

    distance from the object (along z) is such that the x dimensions fill the width.

    something like d = (width / 2) / tan(pi / 6)

    (pi / 6 is half of pi / 3 which is the default fov used in perspective command (aka half of 60 degrees))

  • edited September 1 Answer ✓

    (bad) picture in an attempt to explain

    Untitled

    the camerax (at the bottom) is the average of minx and maxx.

    the distance d is a function of the view angle (alpha), which is typically 60 degrees, or two pi by 6 radians.

    take the left hand right-angled triangle

    tan (alpha / 2) = opposite / adjacent, opposite is (maxx - minx) / 2, adjacent is d, alpha is 60

    so d = ((maxx - minx) / 2) / tan(30)

  • And..... hmm......

    ok, I can calculate center/lookAt see above

    So camere Position/ eye is at lookAt position and here Z minus d, correct?

  • if you arrange the long axis of your thing to be along x then yes, camx is in the middle and camz is -d (or +d, i can never remember) (and y is (maxy + miny) / 2 and up is (0, 1, 0))

    try it! (i haven't!)

    (have arranged the long axis along x because, assuming the screen is wider than it is tall, that's how you minimise d, which means the object looks as large as it can)

    alternatively, you could put lookat as the centre of the object and have distance as the 3d pythagorus of the point of your object furthest from the centre, plus a bit to avoid clipping. so, for a cube, slightly outside the distance of any corner from the centre.

  • Thank you so much, I 'll look into it - when I find the time, hopefully next weekend

  • Does it make any sense? I'd throw an example together but have no real idea about the objects you're generating.

  • edited September 11

    Absolutely it makes sense

    I am on a journey and can't test it really

    The context is my 3D Turtle program where the user writes his own script to draw a 3D shape. See my other discussion.

    https://forum.processing.org/two/discussion/comment/88164/#Comment_88164

    But since I don't know the size of the shape the Turtle Script generates I am planning to let the Turtle store the range of the cube it moved in for one shape and adjust peasyCam or processing camera accordingly to make sure the entire shape is in the view.

    Then I can make a proper screen shot automatically which I am planning to store on hard drive as a preview for the saved Turtle Scripts that the user saved.

    But thank you!

    Chrisir

  • edited September 12

    hello,

    thank you again.

    I had time to look at it.

    your formula d = ((maxx - minx) / 2) / tan(30) in processing is missing the radians, so it's float d = ((maxx - minx) / 2) / tan(radians(30));

    ok, instead of using my Turtle Sketch right away I made a simulation for that.

    Instead of the Turtle Scene I want to look at later, I use 3 boxes. When you draw them min and max is defined for x,y,z.

    You test this by placing the 3 boxes outside the screen at x being around 1800 or so or by spreading them further apart.

    The camera has to adjust to that. There are different camera types, you call them by 0,1,2,3 keys. 2 should be the best.

    this works good, when you place 3 boxes next to each other on the x-axis

    it works less good when you distribute the boxes more

    (it's not peasyCam but classical camera)

    Best, Chrisir

    // def  camera(eyeX, eyeY, eyeZ,              // position 
    //             centerX, centerY, centerZ,     // look at
    //             upX, upY, upZ)
    
    int cameraType=0; 
    
    PVector minAll; 
    PVector maxAll;
    
    PVector myEye;
    
    float eyeAngle;  // for rotate  
    
    void setup() {
      // init
      size(800, 600, P3D);
      minAll=new PVector(100000, 100000, 100000); 
      maxAll=new PVector(-100000, -100000, -100000);
    } // func 
    
    void draw() {
      // runs on and on 
      background(0);
      lights(); 
    
      useCamera(); 
    
      minAll=new PVector(100000, 100000, 100000); 
      maxAll=new PVector(-100000, -100000, -100000);
    
      // small control box
      stroke(255); // white 
      pushMatrix();
      translate(0, 0, 0); 
      box(50);
      popMatrix();
    
      float x1 = -600; // 1000;
      float y1 = 600; 
      float z1 = -550; 
    
      //  myBox(x1+100, y1, z1, false); 
      //  myBox(x1+420, y1, z1, true); 
      //  myBox(x1+700, y1, z1, false);
    
      myBox(x1+100, y1, z1-888, false); 
      myBox(x1+120, y1+2300, z1, true); 
      myBox(x1+150, y1, z1, false);
      //
    } // func 
    
    // ----------------------------------------------------------
    
    void myBox( float x, float y, float z, 
      boolean filled ) {
      pushMatrix();
      translate(x, y, z); 
      if (filled) {
        fill(255, 0, 0); // red
        stroke(111);
      } else {
        stroke(255, 0, 0); // red
        noFill();
      }
      box(60);
      popMatrix();
    
      // take data
      minAll = getMin(minAll, new PVector(x, y, z) ); 
      maxAll = getMax(maxAll, new PVector(x, y, z) );
    }
    
    PVector getMin(PVector minAll1, PVector newData) {
      if (newData.x < minAll1.x)
        minAll1.x=newData.x;
      if (newData.y < minAll1.y)
        minAll1.y=newData.y;
      if (newData.z < minAll1.z)
        minAll1.z=newData.z;
      return minAll1;
    }
    
    PVector getMax(PVector maxAll1, PVector newData) {
      if (newData.x > maxAll1.x)
        maxAll1.x=newData.x;
      if (newData.y > maxAll1.y)
        maxAll1.y=newData.y;
      if (newData.z > maxAll1.z)
        maxAll1.z=newData.z;
      return maxAll1;
    }
    
    // ----------------------------------------------------------
    
    void keyPressed() {
    
      // the keys 0..3 determine the camera type 
    
      switch (key) {
    
      case '0': 
        // The default camera
        cameraType=0; 
        break; 
    
      case '1': 
        cameraType=1; 
        break;
    
      case '2': 
        cameraType=2; 
        break;
    
      case '3': 
        cameraType=3; 
        break;
    
      default:
        println("Error: "+key);
        break;
      }//switch
      //
    }//func 
    
    void useCamera() {
    
      // using the camera type 
    
      // calc center
      PVector centerAll = new PVector( 
        (minAll.x + maxAll.x) /2, 
        (minAll.y + maxAll.y) /2, 
        (minAll.z + maxAll.z) /2); 
    
      // calc distance 
      float d, d2;
    
      // calc distance 
      d = ( (maxAll.x - minAll.x) / 2) / tan(radians(30));
      d2 = ( (maxAll.y - minAll.y) / 2) / tan(radians(30));
      d = max(d, d2);
      d2 = ( (maxAll.z - minAll.z) / 2) / tan(radians(30));
      d = max(d, d2);
      d = max(d, 160 + d);
      d = max(d, maxAll.x - minAll.x);
    
      switch (cameraType) {
    
      case 0: 
        // The default camera
        camera(width/2.0, height/2.0, (height/2.0) / tan(PI*30.0 / 180.0), 
          width/2.0, height/2.0, 0, 
          0, 1, 0);
        break; 
    
      case 1: 
        // only the lookAt changes (2nd line): 
        camera(width/2.0, height/2.0, (height/2.0) / tan(PI*30.0 / 180.0), 
          centerAll.x, centerAll.y, centerAll.z, 
          0, 1, 0);
        break;
    
      case 2:
        // ALL changes: position and lookAt  
        camera(centerAll.x, centerAll.y, centerAll.z - d, 
          centerAll.x, centerAll.y, centerAll.z, 
          0, 1, 0);
        break;
    
      case 3:
        // ALL plus rotation 
        // eye rotates around the scene     
        PVector myEye=new PVector(
          d* cos (eyeAngle) + centerAll.x, // x value on circle
          centerAll.y-155, // bit above sceene  
          d* sin (eyeAngle) + centerAll.z );   // z value on circle
        camera(myEye.x, myEye.y, myEye.z, 
          centerAll.x, centerAll.y, centerAll.z, 
          0, 1, 0);
        eyeAngle+=.03; // rotate
        break;
    
      default:
        println("Error - reset");
        cameraType=0; 
        break;
      }//switch
      //
    }//func 
    //
    
  • little simplified version

    int cameraType=0; 
    
    PVector minAll; 
    PVector maxAll;
    
    float eyeAngle;  // for rotate  
    
    void setup() {
      // init
      size(800, 600, P3D);
      minAll=new PVector(100000, 100000, 100000); 
      maxAll=new PVector(-100000, -100000, -100000);
    } // func 
    
    void draw() {
      // runs on and on 
      background(0);
      lights(); 
    
      useCamera(); 
    
      minAll=new PVector(100000, 100000, 100000); 
      maxAll=new PVector(-100000, -100000, -100000);
    
      // small white box
      stroke(255); // white 
      pushMatrix();
      translate(0, 0, 0); 
      box(50);
      popMatrix();
    
      float x1 = -600; // 1000;
      float y1 = 600; 
      float z1 = -550; 
    
      myBox(x1+100, y1, z1, false); 
      myBox(x1+420, y1, z1, true); 
      myBox(x1+700, y1, z1, false);
      //
    } // func 
    
    // ----------------------------------------------------------
    
    void myBox( float x, float y, float z, 
      boolean filled ) {
      pushMatrix();
      translate(x, y, z); 
      if (filled) {
        fill(255, 0, 0); // red
        stroke(111);
      } else {
        stroke(255, 0, 0); // red
        noFill();
      }
      box(60);
      popMatrix();
    
      // take data
      minAll = getMin(minAll, new PVector(x, y, z) ); 
      maxAll = getMax(maxAll, new PVector(x, y, z) );
    }
    
    PVector getMin(PVector minAll1, PVector newData) {
      if (newData.x < minAll1.x)
        minAll1.x=newData.x;
      if (newData.y < minAll1.y)
        minAll1.y=newData.y;
      if (newData.z < minAll1.z)
        minAll1.z=newData.z;
      return minAll1;
    }
    
    PVector getMax(PVector maxAll1, PVector newData) {
      if (newData.x > maxAll1.x)
        maxAll1.x=newData.x;
      if (newData.y > maxAll1.y)
        maxAll1.y=newData.y;
      if (newData.z > maxAll1.z)
        maxAll1.z=newData.z;
      return maxAll1;
    }
    
    // ----------------------------------------------------------
    
    void keyPressed() {
    
      // the keys 0..3 determine the camera type 
    
      switch (key) {
    
      case '0': 
        cameraType=0; 
        break; 
    
      case '1': 
        cameraType=1; 
        break;
    
      case '2': 
        cameraType=2; 
        break;
    
      case '3': 
        cameraType=3; 
        break;
    
      default:
        println("Error: "+key);
        break;
      }//switch
      //
    }//func 
    
    void useCamera() {
    
      // using the camera type 
    
      // calc center
      PVector centerAll = new PVector( 
        (minAll.x + maxAll.x) /2, 
        (minAll.y + maxAll.y) /2, 
        (minAll.z + maxAll.z) /2); 
    
      // calc distance 
      float d, d2;
    
      // calc distance 
      d = ( (maxAll.x - minAll.x) / 2) / tan(radians(30));
      d2 = ( (maxAll.y - minAll.y) / 2) / tan(radians(30));
      d = max(d, d2);
    
      // for rotating
      PVector myEye;
    
      switch (cameraType) {
    
      case 0: 
        // The default camera
        camera(width/2.0, height/2.0, (height/2.0) / tan(PI*30.0 / 180.0), 
          width/2.0, height/2.0, 0, 
          0, 1, 0);
        break; 
    
      case 1: 
        // only the lookAt changes (2nd line): 
        camera(width/2.0, height/2.0, (height/2.0) / tan(PI*30.0 / 180.0), 
          centerAll.x, centerAll.y, centerAll.z, 
          0, 1, 0);
        break;
    
      case 2:
        // ALL changes: position and lookAt  
        camera(centerAll.x, centerAll.y, maxAll.z + d, // Z is positive, means coming at you
          centerAll.x, centerAll.y, centerAll.z, 
          0, 1, 0);
        break;
    
      case 3:
        // ALL plus rotation 
        // eye rotates around the scene     
        myEye=new PVector(
          d* cos (eyeAngle) + centerAll.x, // x value on circle
          centerAll.y-155, // bit above sceene  
          d* sin (eyeAngle) + centerAll.z );   // z value on circle
        camera(myEye.x, myEye.y, myEye.z, 
          centerAll.x, centerAll.y, centerAll.z, 
          0, 1, 0);
        eyeAngle+=.03; // rotate
        break;
    
      default:
        println("Error - reset");
        cameraType=0; 
        break;
      }//switch
      //
    }//func 
    //
    
Sign In or Register to comment.