Camera: How top down view

Hello,

it is well known that

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);

delivers the normal view.

I am trying to implement a top down view:

My best guess is

    camera(0, -1200, 0, 
      0, 0, 0, 
      0, 0, -1);

So the camera is very high above (0, -1200, 0) the scene, looking straight down (0,0,0).

My question is about the 3 last, the UP parameters. I have 0,0,-1 there hoping that means “look straight down with neg. z-axis is up”. Is that correct?

(My goal: Let’s say the camera standard front view looks toward north at a house with a car on the right. Then you want the top view in a way that the car is still right from the car (and north is at the top of the screen and not left or right) )

Are my assumptions and my camera parameters correct?

Thanks!

Best, Chrisir :wink:

1 Like

By default the Z axis point toward the top of the screen.
After trying an understanding the camera parameters, I think that you have to set the Z upward axis to 1 :

void setup() {
  size(400, 400, P3D);
  stroke(255, 0, 0);
  lights();
}


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

  if (mousePressed) {
    camera(width/2, height/2-1200, 0, width/2, height/2, 0, 0, 0, 1);
  } else {
    camera();
  }

  translate(width/2, height/2, 0);
  fill(255);
  box(100);
  translate(100, 0, 0);
  fill(255, 0, 0);
  box(50);
  translate(-200, 0, 0);
  fill(0, 255, 0);
  box(50);
  translate(100, -100, 0);
  fill(0, 0, 255);
  box(50);
}

camera_simplecamera_changed

1 Like

Excellent

thank you so much

New version with key input 0…4 for 5 different views

Chrisir


// default values are 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).

int viewMode=3; 
String[] viewText={
  "top view", 
  "from north", 
  "from east", 
  "from south (processing default)", 
  "from west"
};

void setup() {
  size(1400, 400, P3D);
  stroke(255, 0, 0);
  //  stroke(111); 
  lights();
}


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

  if (!mousePressed) {

    switch (viewMode) {

    case 0:
      // top down 
      camera(width/2, height/2-400, 0, 
        width/2, height/2, 0, 
        0, 0, 1);
      break; 

    case 1: 
      //from north 
      camera(width/2, height/2, -400, 
        width/2, height/2, 0, 
        0, 1, 0);
      break; 

    case 2: 
      //from east 
      camera(width/2+500, height/2, 0, 
        width/2, height/2, 0, 
        0, 1, 0);
      break; 

    case 3:
      //from south // default 
      camera();
      break; 

    case 4:
      //from west 
      camera(width/2-500, height/2, 0, 
        width/2, height/2, 0, 
        0, 1, 0);
      break;
    default:
      println("error 55 in switch");
      exit();
      return;
    }//switch 
    //
  } else {
    // default (from south)  
    camera();
  }

  translate(width/2, height/2, 0);

  fill(255); //white 
  box(100);  // big box 

  translate(100, 0, 0); // right 
  fill(255, 0, 0);  // red 
  box(50);

  translate(-200, 0, 0); // left
  fill(0, 255, 0);  // green 
  box(50);

  translate(100, -100, 0); // center above 
  fill(0, 0, 255);  // blue 
  box(50);

  camera();
  fill(255);
  text("Camera test: Hit 0..4 for top view / north / east / south / west view. "
    +"\nClick and hold mouse to see processing default view."
    +"\nCurrent view: "
    +viewText[viewMode], 
    15, 15);
}

void keyPressed() {
  if (key>='0'&&key<='4') {
    viewMode=int(key+"");
  }
}
//
2 Likes

This sketch is based on the following assumptions:

  • in 3D the scene is on a table. So placing things left and right on the table is x, placing it more in front or in the back is Z and placing it above the scene (blue box) is Y

  • The center of the scene is at width/2, height/2, 0

Chrisir

Thanks for your answer @Chrisir have a nice day !

:wink:

2 Likes

New version with class Carmera and a smoother transition between the different views (lerp())


/*

 New version with camera class AND smooth transitions (damping) ============================================================
 
 This sketch is based on the following assumptions:
 * in 3D the scene is on a table. So placing things left and right on the table is x, placing it more in front or in the back is Z and placing it above the scene (blue box) is Y
 * The center of the scene is at width/2, height/2, 0
 
 https://discourse.processing.org/t/camera-how-top-down-view/1178/3
 
 */

// demonstrates view from top down (above the sceen), 
// and from north, east, south and west. 

// The interesting part: the UP-vector when view from top.  

// default values are 
// 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).

CameraMy cam;  

// view mode and its texts  
int viewMode=3; 
String[] viewText={
  "top view", 
  "from north", 
  "from east", 
  "from south (processing default)", 
  "from west"
};

void setup() {
  size(1400, 400, P3D);
  stroke(255, 0, 0);
  cam = new CameraMy();
}

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

  if (!mousePressed) {
    // apply view mode
    cam.apply();
    //
  } else {
    // default (from south)  
    camera();
  }//else 

  // draw scene 
  drawScene();

  // HUD : text
  camera();
  fill(255);
  text("Camera test: Hit 0..4 for top view / north / east / south / west view. "
    +"\nClick and hold mouse to see processing default view."
    +"\nCurrent view: "
    +viewText[viewMode], 
    15, 15);
}//func

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

void setViewFromViewMode() {

  switch (viewMode) {

  case 0:
    // top down 
    cam.setEye(width/2, height/2-400, 0); 
    cam.setUpVector(0, 0, 1); 
    cam.apply();
    break; 

  case 1: 
    //from north 
    cam.setEye(width/2, height/2, -400); 
    cam.setUpVectorToStandard();
    cam.apply(); 
    break; 

  case 2: 
    //from east 
    cam.setEye(width/2+500, height/2, 0); 
    cam.setUpVectorToStandard();
    cam.apply(); 
    break; 

  case 3:
    //from south // default 
    cam.reset();
    cam.apply(); 
    break; 

  case 4:
    //from west 
    cam.setEye(width/2-500, height/2, 0); 
    cam.setUpVectorToStandard();
    cam.apply(); 
    break;

  default:
    println("error 55 in switch");
    exit();
    return;
  }//switch
}//func 

void drawScene() {
  translate(width/2, height/2, 0);

  fill(255); //white 
  box(100);  // big box 

  translate(100, 0, 0); // right 
  fill(255, 0, 0);  // red 
  box(50);

  translate(-200, 0, 0); // left
  fill(0, 255, 0);  // green 
  box(50);

  translate(100, -100, 0); // center above 
  fill(0, 0, 255);  // blue 
  box(50);

  translate(0, 100, 100); // center above 
  fill(0, 0, 255);  // blue 
  noStroke(); 
  sphere(12);

  translate(0, 0, -200); // center above 
  fill(0, 255, 0);  // green 
  noStroke(); 
  sphere(12);
}

void keyPressed() {
  if (key>='0'&&key<='4') {
    viewMode=int(key+"");
    setViewFromViewMode();
  }
}
//===========================================================

class CameraMy {

  // standards
  final PVector eyePV_Standard     = new PVector ( width/2.0, height/2.0, (height/2.0) / tan(PI*30.0 / 180.0)); // eye = camera position 
  final PVector lookAtPV_Standard  = new PVector ( width/2, height/2, 0 );  // look At or center
  final PVector upPV_Standard      = new PVector ( 0, 1, 0);  // the up vector for rotating the camera around itself 

  // the changing values: 
  PVector eyePV, lookAtPV, upPV;

  // old PVectors
  PVector eyePVold, lookAtPVold, upPVold;

  // for lerp
  float amt = 0;

  // constr 
  CameraMy() {
    eyePV    = eyePV_Standard.copy(); 
    lookAtPV = lookAtPV_Standard.copy();
    upPV     = upPV_Standard.copy();

    eyePVold    = eyePV.copy(); 
    lookAtPVold = lookAtPV.copy();
    upPVold     = upPV.copy();
  }//constr 

  // -----

  void setEye( float x, float y, float z) {
    eyePVold=eyePV.copy(); 
    eyePV=new PVector(x, y, z);
    amt=0;
  }
  void setLookAt( float x, float y, float z) {
    lookAtPVold=lookAtPV.copy();
    lookAtPV=new PVector(x, y, z);
    amt=0;
  }
  void setUpVector( float x, float y, float z) {
    upPVold=upPV.copy();
    // set UP vector 
    upPV=new PVector(x, y, z);
    amt=0;
  }

  // ----

  void setEyeToStandard() {
    eyePVold=eyePV.copy(); 
    eyePV = eyePV_Standard.copy();
    amt=0;
  }
  void setLookAtToStandard() {
    lookAtPVold=lookAtPV.copy();
    lookAtPV = lookAtPV_Standard.copy();
    amt=0;
  }
  void setUpVectorToStandard() {
    upPVold=upPV.copy();
    upPV = upPV_Standard.copy();
    amt=0;
  }

  // ----

  void reset() {
    // reset 
    // store old values 
    eyePVold=eyePV.copy(); 
    lookAtPVold=lookAtPV.copy();
    upPVold=upPV.copy();
    // reset 
    eyePV    = eyePV_Standard.copy(); 
    lookAtPV = lookAtPV_Standard.copy();
    upPV     = upPV_Standard.copy();
    // set amt to 0 for lerp
    amt=0;
  }

  // ----

  void apply() {

    // apply values

    // we don't use the new values (eyePV,lookAtPV,upPV) directly but with eyePVold etc. and lerp   

    PVector eyePV2, lookAtPV2, upPV2;

    eyePV2    = lerpPV ( eyePVold, eyePV, amt );
    lookAtPV2 = lerpPV ( lookAtPVold, lookAtPV, amt );
    upPV2     = lerpPV ( upPVold, upPV, amt );

    if (amt<1)
      amt+=.05;
    else 
    amt = 1.0; 

    camera (eyePV2.x, eyePV2.y, eyePV2.z, 
      lookAtPV2.x, lookAtPV2.y, lookAtPV2.z, 
      upPV2.x, upPV2.y, upPV2.z);
  }//method

  PVector lerpPV(PVector pvOld, PVector pvNew, float amt) {

    PVector result;

    // lerp: 
    float x = lerp(pvOld.x, pvNew.x, amt);
    float y = lerp(pvOld.y, pvNew.y, amt);
    float z = lerp(pvOld.z, pvNew.z, amt);

    result = new PVector (  x, y, z  ); 

    return result;
  }
  //
}//class 
//
3 Likes