2

I'm trying to use Jonathan Feinberg's Peasycam library for processing to rotate the camera around the objects' Z axis. The documentation specifies for rotation is around subject, but not the object. This seems incredibly difficult to achieve. The peasycam rotations act around the subject (i.e. camera) not object, although in control sense peasycam's emphasis is object-oriented. And setting the camera() seems problematic too, as I can't get the peasycam to remember the assigned camera's position. There's also a discrepancy whereby the peasycam's y axis maps to the data-space's z axis.

I've made a basic model to help explain this interactively. Grateful if some fresh eyes can help untangle this. Peasycam may need installing to the application's library folder. The overall aim is to be able to spin 3D data-plots on Z axis for animation purposes. Thanks in advance.

import peasy.*;
PVector camPos;
PVector[] points = new PVector[50];
float angleXY, d;
PeasyCam cam;

void setup() {
  size(300,300,P3D);
  cam = new PeasyCam(this, 100);
  cam.setMinimumDistance(50);
  cam.setMaximumDistance(150);

  for(int i=0; i<50; i++) points[i] = new PVector(random(-15,15),random(-15,15),random(-15,15));
}

void draw() {
  background(250);
  noFill();
  box(30);

  // axes for frame of reference
  stroke(255,0,0);         // red = Z
  line(0,0,-100,0,0,100);
  stroke(0,255,0);         // green = Y 
  line(0,-100,0,0,100,0);
  stroke(0,0,255);         // blue = X
  line(-100,0,0,100,0,0);

  // points on axes to denote positive orientation
  strokeWeight(3);
  for(PVector p:points) point(p.x, p.y, p.z);
  strokeWeight(5);
  point(40,0,0);
  point(0,40,0);
  point(0,0,40);
  strokeWeight(1);

  stroke(0);

  camPos = new PVector(cam.getPosition()[0], cam.getPosition()[1], cam.getPosition()[2]);  
  angleXY = degrees(atan2(camPos.z, camPos.x));  // camera XY angle from origin
  d = sqrt(pow(camPos.z, 2) + pow(camPos.x, 2)); // camera-object XY distance (compare to cam.getDistance())

  // ZX campera slots map to XY data plane:
  println("campos: " + camPos + " " + ", ang: " + angleXY + ", dist:" + d); 
}

void keyPressed(){
  if(key=='r') setup(); // restart
  if(key==' ') camera(camPos.x, camPos.y, camPos.z, 0, 0, 0, 0, 0, 1); // stabilise image on Z axis

  if(key=='d') {
    angleXY += radians(1);
    camera(sin(angleXY)*d, camPos.y, cos(angleXY)*d, 0, 0, 0, 0, 1, 0);
  }

  // peasycam's rotations work around the subject:
  if(key=='p') cam.rotateY(radians(2));
}
user2314737
  • 27,088
  • 20
  • 102
  • 114
geotheory
  • 22,624
  • 29
  • 119
  • 196
  • 2
    The thing with peasycam is that it always has "Rotations [that] are around axes that pass through the looked-at point". In order to fix that you have to compensate for the rotation around the other two axis and send that into peasycam. what you need is "tabletop" rotation. If I may provide a simple way to achieve your overall aim, remove peasycam from your sketch and add this: camera(70*sin(frameCount*.02),70*cos(frameCount*.02), 70,0,0,0,0,0,-1); – Petros Koutsolampros Jul 17 '13 at 11:24

2 Answers2

3

You are misunderstanding the word "subject" in Peasycam's documentation. The "subject" is merely the "look-at" point. Choose a point inside the thing you want to look at, and then either construct the Peasycam with that point, or set it later.

PeasyCam(PApplet parent, double lookAtX, double lookAtY, double lookAtZ, double distance);

camera.lookAt(double x, double y, double z);
camera.lookAt(double x, double y, double z, double distance);

Peasycam is not well-suited to programmatic control. If you want to manipulate the view yourself, you'd be better off with the excellent Proscene or OCD libraries.

Edit: If you want to constrain the Peasycam's movement to one axis or another, you may use these methods:

// By default, the camera is in "free rotation" mode, but you can
// constrain it to any axis, around the look-at point:
camera.setYawRotationMode();   // like spinning a globe
camera.setPitchRotationMode(); // like a somersault
camera.setRollRotationMode();  // like a radio knob
camera.setSuppressRollRotationMode();  // Permit pitch/yaw only.

// Then you can set it back to its default mode:
camera.setFreeRotationMode();
Jonathan Feinberg
  • 44,698
  • 7
  • 80
  • 103
  • Thanks for clarifying Jonathan. The documentation might make this clearer - if _subject_ is by default the (0,0,0) origin, then its z axis (around which I wanted to rotate) is not related to the data space but actually position relative to the camera, which is why I was confused. I'll check out your suggestions. Great library though :) – geotheory Jul 17 '13 at 14:30
1

Not an exact answer to this question, but something similar - I wanted to simply set the position (move) the camera, but that seems to be complicated with peasycam. So I wanted to try what looked the next easiest library, OCD.

So - since OCD apparently does not contain examples at the moment in the installation (only in the Obsessive Camera Direction API reference) - below is the .pde code of the basic example from peasycam, modified to work with OCD library (the sketch actually refers to both libraries, and allows you to easily compare the behavior of either by setting the USEPEASY variable). Most of the peasycam interaction is replicated for OCD - however, you won't get the animation "tweening" with OCD as with PeasyCam.

// modification of example on http://mrfeinberg.com/peasycam/
// sdaau, 2014

private static final boolean USEPEASY = false;

// cannot do conditional import in Java! (expecting EOF, found 'if')
// http://stackoverflow.com/questions/11288083/javaconditional-imports
//if(USEPEASY) {
  import peasy.*;
//} else {
  import damkjer.ocd.*;
//}

// ... nor conditional globals! (expecting EOF, found 'if')
//if(USEPEASY) { 
  PeasyCam cam;
//} else {
  Camera cam1;
//}

void setup() {
  size(200,200,P3D);
  if(USEPEASY) {
    cam = new PeasyCam(this, 100); // (PApplet parent, double distance); // look at 0,0,0
    cam.setMinimumDistance(50);
    cam.setMaximumDistance(500);
  } else {
    cam1 = new Camera(this, // (parent,
      0, 0, 100,            // cameraX, cameraY, cameraZ, 
      0, 0, 0,              // targetX, targetY, targetZ
      50, 500               // nearClip, farClip) //(doesn't clip as peasycam!)
    ); 
  }
}
void draw() {
  if(!USEPEASY) {
    cam1.feed(); //"send what this camera sees to the view port"
  }
  // these rotates seem just to set initial view, in either case:
  rotateX(-.5);
  rotateY(-.5);
  // actual drawing:
  background(0);
  fill(255,0,0);
  box(30);
  pushMatrix();
  translate(0,0,20);
  fill(0,0,255);
  box(5);
  popMatrix();
}

// ... nor conditional methods! (expecting EOF, found 'if')
//if(!USEPEASY) {
void mouseDragged() {
  if(!USEPEASY) {
    if (mouseButton == LEFT) {
      // http://www.airtightinteractive.com/demos/processing/bezier_ribbon_p3d/BezierRibbons.pde
      cam1.arc(radians(-(mouseY - pmouseY))/4);
      cam1.circle(radians(-(mouseX - pmouseX))/4);
    } else if (mouseButton == RIGHT) {
      cam1.zoom(radians(mouseY - pmouseY) / 2.0);
    } else if (mouseButton == CENTER) {
      // peasycam calls this .pan(); damkjer.ocd calls it .track()
      cam1.track(-(mouseX - pmouseX), -(mouseY - pmouseY));
    }
  } // end if(!USEPEASY)
}
void mouseWheel(MouseEvent event) {
  if(!USEPEASY) {
    float e = event.getCount();
    cam1.zoom(e/3.0);
  } // end if(!USEPEASY)
}
//} // end if(!USEPEASY)
sdaau
  • 36,975
  • 46
  • 198
  • 278