rotate a proscene camera around an aribtrary point

edited November 2017 in Library Questions

Hello All,

There must be an easy way to rotate a proscene camera around a point, but I don't know how to do it.

The regular rotation methods don't work on the proscene camera.

I don't want to rotate the camera around any default axis, I want to rotate it around a pre-defined point, OR (even better) a processing object, like a text(); object.

Anyone have any thoughts on this?

I'm not posting my code, bc it is enormous, but I can if you really want to look at it.

Tagged:

Answers

  • Check the example that comes with the proscene lib. Go to: contributed libraries>>proscene>>Eye and then try PointUnderPixel. Read the comments in the sketch as you might find it useful.

    Kf

  • here is an example without using proScene

    see CheckCameraSinusLevel ()

    // Lamppost
    int lampPost_XValue = 250; // nach rechts
    int lampPost_YValue = 330; // nach unten
    int lampPost_ZValue = -150; // nach hinten
    
    String actualTextMessage = "Use 0,1,2,3 for Camera";
    String actualTextMessage2 = "Camera circles at constant height";
    
    // =================================================
    // Kamerasteuerung:
    
    float Angle = 0.0; // Angle 
    float Height = 130;    // Height
    float Radius = 210.0;  // Radius
    
    // Camera
    int LookAtX;
    int LookAtY;
    int LookAtZ;
    
    // ==============================================
    
    void setup() {
      size(600, 600, P3D);
    
      // LookAt
      LookAtX=lampPost_XValue;
      LookAtY= lampPost_YValue;
      LookAtZ= lampPost_ZValue;
    } // function
    
    void draw() {
      background(153);
      lights();
    
      // the scene 
      CheckCameraSinusLevel();
      fill(242);
      stroke(22);
      PaintLamppost();
      Angle=Angle+1.0;
    
      // HUD to display text 
      camera();
      noLights();
      hint(DISABLE_DEPTH_TEST); 
      text ("Fixed", 30, 30);
    }
    
    // ==============================================
    
    void PaintLamppost () {
    
      pushMatrix();
    
      int myHeight = 220;
      fill(190, 3, 3);
      translate(lampPost_XValue-0, 
        lampPost_YValue+(myHeight / 2), 
        lampPost_ZValue-0);
      box(11, myHeight, 11);
      popMatrix();
    }
    
    void CheckCameraSinusLevel () {
    
      // camera rotates in height "Height"
      // position of camera is on a circle calculated with cos and sin
      // look to scene (center/lampPost)
      camera (
        Radius*sin (radians(Angle)) + lampPost_XValue, Height, Radius* cos (radians(Angle)) + lampPost_ZValue, 
        lampPost_XValue, lampPost_YValue, lampPost_ZValue, 
        0.0, 1.0, 0.0);
    }
    //
    
  • @kfrajer <-- not sure how to respond to someone; hey, I don't really understand that example very well / am not sure what you think I should extract from it; can you give me any indication; thank you for the help with the proscene library; it seems pretty powerful, but I haven't fully absorbed operating within a 3D framework yet.

  • @chrisir thank you, that is beautiful code; let me show you what I am doing here:

    class Mark {
      float mark_lat = 0;
      float mark_lon = 0;
      String sign_text = "";
      float sign_height = random(100, 200);
      float sign_rot = random(360);
      Vec3D TweetCoordiante;
      Vec3D convertedTweetCoordiante;
      Mark(float mlat, float mlon, String st) {
        mark_lat = mlat;
        mark_lon = mlon;
        sign_text = st;
      } 
      void calculate() {
        //coordinates
        TweetCoordiante = new Vec3D(mark_lat, mark_lon, 0);  
        convertedTweetCoordiante=mapzen.convert(TweetCoordiante);
    
        //CAMERA:
        scene.camera().setPosition(convertedTweetCoordiante.x(), convertedTweetCoordiante.y()+200, sign_height);
        scene.camera().lookAt(convertedTweetCoordiante.x(), convertedTweetCoordiante.y(), sign_height);
        scene.camera().addKeyFrameToPath(1);
      }
      void display() {
        //MARK:
        pushMatrix();
        pushStyle();
        strokeWeight(10);
        stroke(255, 0, 255);
        translate(convertedTweetCoordiante.x(), convertedTweetCoordiante.y(), 0);
        float tp=map(sin(frameCount*.2), -1, 1, 0, 800);
        line(0, 0, 0, 0, 0, tp);
        popStyle();
        popMatrix();
        //TEXT w/two rotations:
        pushMatrix();
        translate(convertedTweetCoordiante.x()-textWidth(sign_text)/2, convertedTweetCoordiante.y(), sign_height);
        rotateX(radians(-90));
        translate(textWidth(sign_text)/2, 0, 0);
        rotateY(radians(sign_rot));
    
        translate(0, 0, 200);
        box(20);
        translate(0, 0, -200);
    
        translate(-textWidth(sign_text)/2, 0, 0);
        translate(-convertedTweetCoordiante.x(), -convertedTweetCoordiante.y(), -sign_height);
        translate(0, 0, sign_height);
        println(sign_height);
        text(sign_text, convertedTweetCoordiante.x(), convertedTweetCoordiante.y(), 200, 200); //xy
        translate(0, 0, -sign_height);
        popMatrix();
      }
    }
    

    I am trying to make a mark class that takes in a lat/lon on a map, lays down a marker, allow you to create a billboard on top of that marker, and then rotate the billboard a random amount (so e.g. the billboard could face east). I've gotten all that working. I can also rotate the billboard to randomly face a direction; what I've been having difficulty doing is figuring out how to ALSO rotate the camera so that the camera is always facing the billboard. I tried using the rotate processing functions on scene.camera() but that didn't work. A hack around all this might be to rotate something like a sphere and then get its 3D coordinates, and then feed that into the position for the camera, which is why I made this post:

    https://forum.processing.org/two/discussion/24860/get-a-3d-vector-from-box-object-in-p3d

    but part of me thinks there must be some easy way to rotate the camera using a proscene method; I was just digging through the library and couldn't find it. Thoughts on the best approach here (again, am grateful for both of your responses). Here is what the project currently looks like when it runs:

    https://www.instagram.com/p/BGnt9WFiuEB/?taken-by=saito_koriel

  • also, just to clarify, I have no problem always getting the camera to look at the billboard, but I always want the camera to look at the billboard "head on"; so if I rotate the camera 90 degrees, I also want to rotate the camera 90 degrees.

  • Answer ✓

    without using proscene

    please note that in my code the scene does NOT rotate

    instead the camera rotates on a circle around the scene in CheckCameraSinusLevel() above.

    the trick is to understand the 9 camera parameters:

    camera(eyeX, eyeY, eyeZ, 
      centerX, centerY, centerZ, 
      upX, upY, upZ)
    

    eye is where the camera is, and center is where it looks at

    so when you have your billboard position, that is also your center position !

    so no matter what your eye is, you look at the billboard.

    below I show a code where the camera rotates but the letter rotate against this so the letters always look at the camera ("head on")

      // camera 
      if (keyPressed&&key=='r')
        camCurrentAngle++;
      if (keyPressed&&key=='l')
        camCurrentAngle--;
      lookAtAngle();
    

    maybe it would help to make a mcve:

    https://stackoverflow.com/help/mcve

    Chrisir ;-)


    String initText = "SUN IS SHINING";
    
    // States
    final int HELP = 0; // consts 
    final int GAME = 1;
    int state = HELP;   // current 
    
    
    final int viewsTotal = 0;
    final int viewsNeighbours = 1;  // 26 Neighbours 
    final int viewsPlaneXY = 2;
    final int viewsNeighboursInThePlaneXZ = 3;  // 8 Neighbours 
    final int viewsNeighboursInThePlaneXY = 4;
    final int viewsNeighboursInThePlaneYZ = 5;
    final int viewsNeighboursDiagonally = 6;   // 8 Neighbours 
    
    int view = viewsTotal;
    
    // boxes 
    BoxClass[][][] boxes = new BoxClass[6][6][6];
    
    // cam 
    PVector camPos;     // its vectors 
    PVector camLookAt;
    PVector camUp;
    
    // cam rotation 
    float camCurrentAngle;       // for cam rot around center
    float camRadius=859;         // same situation 
    
    PFont font1 ;
    
    PVectorInt selected;
    
    String currEntry = ""; 
    
    boolean showGrid = false;  
    
    // --------------------------------------------------------
    // main funcs 
    
    void setup() {
      size(800, 800, OPENGL);
    
      // set cams vectors 
      camPos    = new PVector(width/2.0, height/2.0, 600);
      camLookAt = new PVector(width/2.0, height/2.0, -300);
      camUp     = new PVector( 0, 1, 0 );
    
      defineBoxes();
      background(111);
      font1 = createFont("Arial", 32);
      textFont(font1); 
      selected = new PVectorInt (0, 0, 0);
    
      camCurrentAngle=90;
      lookAtAngle();
    
      println ("X to reset. F1 Help");
      //
    } // func 
    
    void draw() {
      background(111);
      switch (state) {
    
      case HELP:
        showTheHelp();
        break; 
    
      case GAME:
        playTheGame();   
        break;
      } // switch 
      //
    } // func draw()
    
    // ----------------------------------------------------
    
    void showTheHelp () {
      textSize(21);
      int i=80;
      fill(255, 0, 0);
      text ( "The game Boggle", 20, i +=0 );
      fill(255);
      i+=20;
      text ( "F1 - This Help", 20, i +=20 );
      i+=20;
      fill(255, 0, 0);
      text ( "How the game works ", 20, i +=20 );
      fill(255);
      text ( "You can select a cell / letter (see below please) ", 20, i +=20 );
      text ( "With space you add the cell/letter to your word", 20, i +=20 );
      text ( "With Backspace you delete the last letter", 20, i +=20 );
      text ( "With Return you submit your word", 20, i +=20 );
      text ( "The longer the word the more points you get", 20, i +=20 );
      text ( "(not working)", 20, i +=20 );
      text ( "X - new letters (Shift-X)", 20, i +=20 );
      i+=20;
      fill(255, 0, 0);
      text ( "How to select a cell", 20, i +=20 );
      fill(255);
      text ( "use mouse button L/R and wheel", 20, i +=20 );
      text ( "use cursor", 20, i +=20 );
      text ( "Four red spheres mark the cell,", 20, i +=20 );
      text ( "its outline is thicker.", 20, i +=20 );
      i+=20;
      fill(255, 0, 0);
      text ( "How to change view", 20, i +=20 );
      fill(255);
      text ( "use keyboard L/R ", 20, i +=20 );
      text ( "use 0..6", 20, i +=20 );
      text ( "use PAGE UP / DOWN", 20, i +=20 );
      i+=20;
      fill(255, 0, 0);
      text ( "Press any key", 20, i +=20 );
      fill(255);
    }
    
    void playTheGame() {
      // reset some stuff that was set differently by the HUD
      hint(ENABLE_DEPTH_TEST);
      textSize(32);
    
      camera (camPos.x, camPos.y, camPos.z, 
        camLookAt.x, camLookAt.y, camLookAt.z, 
        camUp.x, camUp.y, camUp.z);
    
      lights();
      showTheGridDependingOnCurrentView();
    
      // show the selected cell with thick outline 
      strokeWeight(5);          
      boxes[ selected.x][ selected.y][ selected.z].show(true);
      strokeWeight(1);
    
      // show Red Spheres 
      showRedSpheres();
    
      // camera 
      if (keyPressed&&key=='r')
        camCurrentAngle++;
      if (keyPressed&&key=='l')
        camCurrentAngle--;
      lookAtAngle();
    
      // 2D part / HUD  ---------------------------------------------
      camera();
      //  hint(DISABLE_DEPTH_MASK);
      hint(DISABLE_DEPTH_TEST);
      noLights();
      textMode(MODEL);
      //  textMode(SHAPE);
      textSize(22);
      text("selected letter: " + boxes[ selected.x][ selected.y][ selected.z].letter+
        ". Hit space to add. Return to submit. " + "Current: "+ currEntry+".", 
        10, 20 );
      // text(mouseX + "," + mouseY, mouseX+7, mouseY-7);
    }
    
    // ------------------------------------------------------------------
    
    void showTheGridDependingOnCurrentView() {
    
      switch (view) {
    
      case viewsTotal:
        // show boxes : all
        for (int i = 0; i < boxes.length; i++) {
          for (int j = 0; j < boxes[i].length; j++) {
            for (int k = 0; k < boxes[i][j].length; k++) {
              if (selected.x==i&&selected.y==j&&selected.z==k)
                strokeWeight(5); 
              else
                strokeWeight(1); 
              boxes[i][ j][k].show(false);
            }
          }
        }// for
        break;
    
      case viewsNeighbours:
        // show boxes : only the neighbours of the selected cell 
        for (int i = 0; i < boxes.length; i++) {
          for (int j = 0; j < boxes[i].length; j++) {
            for (int k = 0; k < boxes[i][j].length; k++) {
              if (abs (selected.x-i) <= 1 && 
                abs (selected.y-j) <= 1 && 
                abs(selected.z-k) <= 1) {
                if (selected.x==i&&selected.y==j&&selected.z==k)
                  strokeWeight(5); 
                else
                  strokeWeight(1); 
                boxes[i][ j][k].show(false);
              } // if
            }
          }
        }// for
        break;
    
      case viewsPlaneXY:
        // show boxes in the plane of the selected cell (all)
        // for (int i = 0; i < boxes.length; i++) {
        for (int j = 0; j < boxes[1].length; j++) {
          for (int k = 0; k < boxes[0][j].length; k++) {
            if (selected.y==j && selected.z==k)
              strokeWeight(5); 
            else
              strokeWeight(1); 
            boxes[int(selected.x)][ j][k].show(false);
          }
        }
        // }// for
        break;
    
      case viewsNeighboursInThePlaneXZ:
        // show boxes in the plane of the selected cell (neighbours)
        for (int i = 0; i < boxes.length; i++) {
          for (int j = 0; j < boxes[i].length; j++) {
            for (int k = 0; k < boxes[i][j].length; k++) {
              if (abs (selected.x-i) <= 1 && 
                selected.y==j && 
                abs(selected.z-k) <= 1) {
                if (selected.x==i&&selected.y==j&&selected.z==k)
                  strokeWeight(5); 
                else
                  strokeWeight(1); 
                boxes[i][ j][k].show(false);
              }
            }
          }
        }// for
        break;
    
      case viewsNeighboursDiagonally:
        // show boxes in the diagonal of the selected cell (neighbours)
        for (int i = 0; i < boxes.length; i++) {
          for (int j = 0; j < boxes[i].length; j++) {
            for (int k = 0; k < boxes[i][j].length; k++) {
              if (abs (selected.x-i) == 1 && 
                abs (selected.y-j) == 1  && 
                abs(selected.z-k) == 1) {
                if (selected.x==i&&selected.y==j&&selected.z==k)
                  strokeWeight(5); 
                else
                  strokeWeight(1); 
                boxes[i][ j][k].show(false);
              }
            }
          }
        }// for
        strokeWeight(5);          
        boxes[ selected.x][ selected.y][ selected.z].show(true);
        strokeWeight(1); 
        break;
    
      case viewsNeighboursInThePlaneXY :
        //
        // show boxes in the plane of the selected cell (neighbours)
        for (int i = 0; i < boxes.length; i++) {
          for (int j = 0; j < boxes[i].length; j++) {
            for (int k = 0; k < boxes[i][j].length; k++) {
              if ( (selected.x==i) && 
                abs(selected.y-j) <= 1 && 
                abs(selected.z-k) <= 1) {
                // 
                if (selected.x==i&&selected.y==j&&selected.z==k)
                  strokeWeight(5); 
                else
                  strokeWeight(1); 
                boxes[i][ j][k].show(false);
              }
            }
          }
        }// for
        break;
    
      case viewsNeighboursInThePlaneYZ :
        // 
        // show boxes in the plane of the selected cell (neighbours)
        for (int i = 0; i < boxes.length; i++) {
          for (int j = 0; j < boxes[i].length; j++) {
            for (int k = 0; k < boxes[i][j].length; k++) {
              if (abs (selected.x-i) <= 1 && 
                abs(selected.y-j) <= 1    && 
                selected.z==k ) {
                //
                if (selected.x==i&&selected.y==j&&selected.z==k)
                  strokeWeight(5); 
                else
                  strokeWeight(1); 
                boxes[i][ j][k].show(false);
              }
            }
          }
        }// for
        break;
    
      default:
        // error 
        break;
      } // switch 
    
      //
    } // func 
    
    void showRedSpheres() {
    
      float x1=  boxes[ 0][ selected.y][ selected.z].x-41;
      float y1=  boxes[ selected.x][ selected.y][ selected.z].y-0;
      float z1=  boxes[ selected.x][ selected.y][ selected.z].z-0;
      sphereParam(x1, y1, z1);
    
      x1=  boxes[ boxes.length-1][ selected.y][ selected.z].x+41;
      y1=  boxes[ selected.x][ selected.y][ selected.z].y-0;
      z1=  boxes[ selected.x][ selected.y][ selected.z].z-0;
      sphereParam(x1, y1, z1);
    
      x1=  boxes[ selected.x][ selected.y][ selected.z].x+0;
      y1=  boxes[ selected.x][ 0][ selected.z].y-44;
      z1=  boxes[ selected.x][ selected.y][ selected.z].z-0;
      sphereParam(x1, y1, z1);
    
      x1=  boxes[ selected.x][ selected.y][ selected.z].x+0;
      y1=  boxes[ selected.x][ boxes.length-1][ selected.z].y+44;
      z1=  boxes[ selected.x][ selected.y][ selected.z].z-0;
      sphereParam(x1, y1, z1);
    } 
    
    // ----------------------------------------------------
    // input funcs
    
    void keyPressed () {
    
      switch (state) {
    
      case HELP:
        state = GAME; 
        break;
    
      case GAME:
        if (!(key==CODED)) {
          // not CODED -----------------------------------
          if (key=='X') {
            // reset  
            defineBoxes();
          } else if (key>='0' && key <= '9') {
            view = key-48;
            println ("view: "+view);
          } else if (key == ' ') {
            // space key 
            currEntry+=boxes[ selected.x][ selected.y][ selected.z].letter;
            println (currEntry);
          } else if (key == 's') {
            showGrid=!showGrid;
          } else if (key == RETURN || key == ENTER) {
            // submit
            println ("You submitted "+currEntry);
            currEntry="";
          } else if (key==BACKSPACE) {
            if (currEntry.length()>0) {
              currEntry=currEntry.substring(0, currEntry.length()-1);
            }
          } else {
            // do nothing
          }
        } else {
          // if (key==CODED) { --------------------------------------------
          //
          switch (keyCode) {
    
          case java.awt.event.KeyEvent.VK_F1:
            // help
            state=HELP;
            break;
    
          case java.awt.event.KeyEvent.VK_PAGE_UP:
            camRadius-=4;
            break;
    
          case java.awt.event.KeyEvent.VK_PAGE_DOWN:
            camRadius+=4;
            break;
    
          case UP:
            selected.y--;
            if (selected.y<0)
              selected.y = 0;
            break;
    
          case DOWN:
            selected.y++;
            if (selected.y>=boxes.length)
              selected.y = boxes.length-1;
            break;
    
          case LEFT:
            selected.x--;
            if (selected.x<0)
              selected.x = 0;
            break;
    
          case RIGHT:
            selected.x++;
            if (selected.x>=boxes.length)
              selected.x = boxes.length-1;
            break;
    
          default:
            // do nothing 
            break;
          } // switch
        } // else
    
        //
        break;
      } // switch 
      //
    } // func 
    
    // ----------------------------------------------------
    // misc funcs
    
    void defineBoxes() {
      // define boxes
      int k2=0;
      char letter=' ';
      for (int i = 0; i < boxes.length; i++) {
        for (int j = 0; j < boxes[i].length; j++) {
          for (int k = 0; k < boxes[i][j].length; k++) {
            // prepare values 
            color currentCol = color (random(255), random(255), random(255));
            boolean exist = true;
            // the percentage 
            if (random(100) > 50) { 
              exist = true;
            } else
              exist = false;
            if (k2<initText.length())
              letter = initText.charAt(k2);
            k2++;  
            // create a box   
            boxes[i][ j][k] = new BoxClass( 158 + i*(height/10), 
              158 + j*(height/10), 
              - k*(height/10), 
              currentCol, 
              exist, 
              ' ' );
          }
        }
      }
    
    
      int j = 1;
      String initText2 = "CHRIST"; //  HAS RISEN
      for (int i = 0; i < boxes.length; i++) {
        // for (int j = 0; j < boxes[i].length; j++) {
        for (int k = 0; k < boxes[i][j].length; k++) {
          //      if (selected.x==i&&selected.y==j&&selected.z==k)
          //        strokeWeight(5); 
          //      else
          //        strokeWeight(1); 
          if (k<initText2.length())
            boxes[i][ j][k].letter = initText2.charAt(k);
        }
        // }
      }// for
    
    
      j = 3;
      initText2 = "HAS"; //  HAS RISEN
      for (int i = 0; i < boxes.length; i++) {
        // for (int j = 0; j < boxes[i].length; j++) {
        for (int k = 0; k < boxes[i][j].length; k++) {
          //      if (selected.x==i&&selected.y==j&&selected.z==k)
          //        strokeWeight(5); 
          //      else
          //        strokeWeight(1); 
          if (k>1 && k<initText2.length()+2)
            boxes[i][ j][k].letter = initText2.charAt(k-2);
        }
        // }
      }// for
    
    
      j = 5;
      initText2 = "RISEN"; //  HAS RISEN
      for (int i = 0; i < boxes.length; i++) {
        // for (int j = 0; j < boxes[i].length; j++) {
        for (int k = 0; k < boxes[i][j].length; k++) {
          //      if (selected.x==i&&selected.y==j&&selected.z==k)
          //        strokeWeight(5); 
          //      else
          //        strokeWeight(1); 
          if (k<initText2.length())
            boxes[i][ j][k].letter = initText2.charAt(k);
        }
        // }
      }// for
    } // func 
    
    void lookAtAngle() {
      // rotate in the plane : cam 
      //camRadius = camLookAt.dist (camPos); 
      // camRadius = 100;
      camPos.x = camRadius * cos (radians(camCurrentAngle)) + camLookAt.x;
      camPos.z = camRadius * sin (radians(camCurrentAngle)) + camLookAt.z;
    } // func 
    
    // ----------------------------------------
    
    void mousePressed() {
    
      if (mouseButton==LEFT) {
        selected.x--;
        if (selected.x<0)
          selected.x = 0;
      } else {
        // RIGHT 
        selected.x++;
        if (selected.x>=boxes.length)
          selected.x = boxes.length-1;
      }
    }
    
    void mouseWheel(MouseEvent event) {
      // mousewheel 
    
      // scroll 
    
      float e = event.getAmount();
      // eval 
      if (e<0) { 
        // away 
        selected.z++;
        if (selected.z>=boxes.length)
          selected.z = boxes.length-1;
      } // if 
      else if (e>0) {
        // towards 
        selected.z--;
        if (selected.z<0)
          selected.z = 0;
      } // else if
      //
    } // func
    
    void sphereParam(float x1, float y1, float z1) {
      // the red spheres 
      pushMatrix();
      translate(x1, y1, z1);
      noStroke();
      fill(255, 2, 0);
      sphere(16);
      popMatrix();
    }
    
    // =====================================================
    // classes
    
    class BoxClass {
    
      // this class represents one Box / Cell
    
      float x;
      float y;
      float z;
    
      char letter = ' ' ; //  char ( int ( random (65, 65+24) )) ;  
    
      color col;
      boolean exist = true; 
    
      // constr
      BoxClass(float x_, float y_, float z_, 
        color col_, 
        boolean exist_, 
        char letter_) {
        x = x_;
        y = y_;
        z = z_;
        col = col_;
        exist = exist_;
        letter = letter_;
      } // constr
    
      void show(boolean showBox) {
        if (exist||showGrid) {
          if (true) {
    
            pushMatrix();
            translate(x-0, y+0, z);
    
            pushMatrix();
            rotateY (-radians(camCurrentAngle+270));
            noStroke();
            fill(col);
            fill(0);
            text (letter, -12, 12);
            popMatrix();
    
            noFill();
            stroke(col);
            // stroke(255);
            if (showBox||true) {     
              box(55);
            }
            popMatrix();
            //
          } // if
        }
      } // method
    } // class 
    
    // ==============================================================
    
    class PVectorInt {
      // it's like a PVector but int (not float)
      int x, y, z;
      PVectorInt(int x_, int y_, int z_) {
        x=x_;
        y=y_;
        z=z_;
      } // constr
    }
    // ===============================================================
    
  • edited November 2017

    @chrisir So, modelX, Y, etc. worked; I was just calling it in the wrong place (I needed to call it in setup -- calculate(), not in the draw -- display(), the following code works for the object. So, if anyone needs to feed in a processing method's xyz into a proscene object, we know it's doable (I'm having some weird rotation problems, but I'm going to open up a new ticket for that).

    class Mark {
      float mark_lat = 0;
      float mark_lon = 0;
      String sign_text = "";
      float sign_height = random(100, 200);
      float sign_rot = random(360);
      float ulx = 0;
      float uly = 0;
      float ulz = 0;
      Vec3D TweetCoordiante;
      Vec3D convertedTweetCoordiante;
      Mark(float mlat, float mlon, String st) {
        mark_lat = mlat;
        mark_lon = mlon;
        sign_text = st;
      } 
      void calculate() {
        //coordinates
        TweetCoordiante = new Vec3D(mark_lat, mark_lon, 0);  
        convertedTweetCoordiante=mapzen.convert(TweetCoordiante);
    
        //calculate the camera position based upon a rotate box
        //I know that this looks complicated [...]
        pushMatrix();
        translate(convertedTweetCoordiante.x()-textWidth(sign_text)/2, convertedTweetCoordiante.y(), sign_height);
        rotateX(radians(-90));
        translate(textWidth(sign_text)/2, 0, 0);
        rotateY(radians(sign_rot));
        translate(0, 0, 200);
        box(20);
        ulx = modelX(0, 0, 0);
        uly = modelY(0, 0, 0);
        ulz = modelZ(0, 0, 0);
        translate(0, 0, -200);
        translate(-textWidth(sign_text)/2, 0, 0);
        translate(-convertedTweetCoordiante.x(), -convertedTweetCoordiante.y(), -sign_height);
        translate(0, 0, sign_height);
        println(sign_height);
        translate(0, 0, -sign_height);
        popMatrix();
    
        //CAMERA:
        //scene.camera().setPosition(convertedTweetCoordiante.x(), convertedTweetCoordiante.y()+200, sign_height);
        scene.camera().setPosition(ulx, uly, ulz);
        scene.camera().lookAt(convertedTweetCoordiante.x(), convertedTweetCoordiante.y(), sign_height);
        scene.camera().addKeyFrameToPath(1);
      }
      void display() {
        //MARK:
        pushMatrix();
        pushStyle();
        strokeWeight(10);
        stroke(255, 0, 255);
        translate(convertedTweetCoordiante.x(), convertedTweetCoordiante.y(), 0);
        float tp=map(sin(frameCount*.2), -1, 1, 0, 800);
        line(0, 0, 0, 0, 0, tp);
        popStyle();
        popMatrix();
        //TEXT w/two rotations:
        pushMatrix();
        translate(convertedTweetCoordiante.x()-textWidth(sign_text)/2, convertedTweetCoordiante.y(), sign_height);
        rotateX(radians(-90));
        translate(textWidth(sign_text)/2, 0, 0);
        rotateY(radians(sign_rot));
        translate(0, 0, 200);
        box(20);
        ulx = modelX(0, 0, 0);
        uly = modelY(0, 0, 0);
        ulz = modelZ(0, 0, 0);
        translate(0, 0, -200);
        translate(-textWidth(sign_text)/2, 0, 0);
        translate(-convertedTweetCoordiante.x(), -convertedTweetCoordiante.y(), -sign_height);
        translate(0, 0, sign_height);
        println(sign_height);
        text(sign_text, convertedTweetCoordiante.x(), convertedTweetCoordiante.y(), 200, 200); //xy
        translate(0, 0, -sign_height);
        popMatrix();
      }
    }
    
  • Well, you use modelX etc. inside display after all translates are in place

    not in setup

Sign In or Register to comment.