# 3D camera view: TOP VIEW

Hello everybody,

Someone knows how to set the camera in processing in order to have the TOP view? and move It in x or y to find the object ?

Thanks!

2 Likes

The idea of 3D space

The idea of 3D space (with `size(1600, 900, P3D);`) is that you draw not on a canvas but inside a box / room where you can place stuff further away (away from you, into the screen depth) or nearer to you.

Imagine the room as the space on a table where you place your scene:

The idea is that

• the first parameter is x (you move something left and right on the table surface e.g.),
• the 2nd parameter (y) is the height (you move something up and down above the table) and
• the 3rd parameter (z) is that you move something back and forth on the table surface (depth).

The camera

The camera has 9 parameters: 3 for position, 3 for lookAt, 3 for UP vector.

For Top Down view:
top down camera is

• pos x = lookAt x,
• pos y = 300 above lookAt y,
• pos z = lookAt z,
• and you have to change the UP vector, as I did below.

Chrisir

``````// house
float inc = 0;
int depth= 125;

void setup() {
size(1600, 900, P3D);
noStroke();
}

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

if (!keyPressed) {
// top down !!!!!!!!!!!!!!!!!!!!!!!!
camera(width/2, height/2-300, 0,
width/2, height/2, 0,
0, 0, 1);
} else {
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);
}

translate(width/2, height/2);
rotateY(inc);

arrow();
inc += .01;
}

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

void arrow() {

// house

fill(255);

int[] x = {
-50, 0, 50, 25
};

int[] y = {
50, 0, 50, 50
//
};

int[] xWalls = {
25, 25, -25, -25, -50
};

int[] yWalls = {
50, 100, 100, 50, 50
}
;

fill(255, 0, 0);
beginShape();
for (int i = 0; i<4; i++)
vertex(x[i], y[i]);
endShape(CLOSE);

fill(255, 0, 0);
beginShape();
for (int i = 0; i<4; i++)
vertex(x[i], y[i], depth+10);
endShape(CLOSE);

fill(0, 255, 255);
fill(255, 0, 0);
for (int i = 0; i<4; i++) {
vertex(x[i], y[i]);
vertex(x[i], y[i], depth+10);
}
int i2 = 0;
vertex(x[i2], y[i2]);
vertex(x[i2], y[i2], depth);
endShape(CLOSE);

fill(0, 255, 255);
for (int i = 0; i<4; i++) {
vertex(xWalls[i], yWalls[i]);
vertex(xWalls[i], yWalls[i], depth);
}
i2 = 4;
vertex(xWalls[i2], yWalls[i2]);
vertex(xWalls[i2], yWalls[i2], depth);
endShape(CLOSE);

// ---------------------------------------
fill(255, 0, 0);
fill(0, 255, 255);
beginShape();
for (int i = 0; i<4; i++)
vertex(xWalls[i], yWalls[i]);
endShape(CLOSE);

fill(255, 0, 0);
fill(0, 255, 255);
beginShape();
for (int i = 0; i<4; i++)
vertex(xWalls[i], yWalls[i], depth);
endShape(CLOSE);
}
//
``````
2 Likes

in this new version, use mouse to move the camera (not the objects) in x and z direction

(As discussed above, in top view when you search something, search in in x and z direction,
so mouseX and mouseY is used as x and y position of the camera)

• The camera always looks straight down so you see objects that are far away from the side
• Alternatively you could look at 0,0,0 or at your object always, then the camera would tilt towards the center or your object while moving

Chrisir

``````// house
float inc = 0;
int depth= 125;

PVector mousePV = new PVector();

void setup() {
size(1600, 900, P3D);
noStroke();
}

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

if (!keyPressed) {
// top down !!!!!!!!!!!!!!!!!!!!!!!!

//mousePV.set(mouseX, mouseY);
mousePV.set (
map(mouseX, 0, width, -50, width+50),
map(mouseY, 0, height, -300, 300)
);

camera(mousePV.x, height/2-300, mousePV.y,
mousePV.x, height/2, mousePV.y,
0, 0, 1);
} else {
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);
}

translate(width/2, height/2);
rotateY(inc);

arrow();
inc += .01;

camera();
fill(255);
text("camera is at "
+int(mousePV.x)
+", "
+int(mousePV.y),
14, 17);
}

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

void arrow() {

// house

fill(255);

int[] x = {
-50, 0, 50, 25
};

int[] y = {
50, 0, 50, 50
//
};

int[] xWalls = {
25, 25, -25, -25, -50
};

int[] yWalls = {
50, 100, 100, 50, 50
}
;

fill(255, 0, 0);
beginShape();
for (int i = 0; i<4; i++)
vertex(x[i], y[i]);
endShape(CLOSE);

fill(255, 0, 0);
beginShape();
for (int i = 0; i<4; i++)
vertex(x[i], y[i], depth+10);
endShape(CLOSE);

fill(0, 255, 255);
fill(255, 0, 0);
for (int i = 0; i<4; i++) {
vertex(x[i], y[i]);
vertex(x[i], y[i], depth+10);
}
int i2 = 0;
vertex(x[i2], y[i2]);
vertex(x[i2], y[i2], depth);
endShape(CLOSE);

fill(0, 255, 255);
for (int i = 0; i<4; i++) {
vertex(xWalls[i], yWalls[i]);
vertex(xWalls[i], yWalls[i], depth);
}
i2 = 4;
vertex(xWalls[i2], yWalls[i2]);
vertex(xWalls[i2], yWalls[i2], depth);
endShape(CLOSE);

// ---------------------------------------
fill(255, 0, 0);
fill(0, 255, 255);
beginShape();
for (int i = 0; i<4; i++)
vertex(xWalls[i], yWalls[i]);
endShape(CLOSE);

fill(255, 0, 0);
fill(0, 255, 255);
beginShape();
for (int i = 0; i<4; i++)
vertex(xWalls[i], yWalls[i], depth);
endShape(CLOSE);
}
//
``````
2 Likes

another sketch with 5 different views:

``````/*

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

wenn man von 2 auf 4 geht oder 1 auf 3, schiesst er durch den Würfel durch.
besser wäre lerp auf einer Kreisbahn über einen radius

*/

// 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; // This var dictates how current camera mode!!!!!!!

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

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

void setup() {
size(1500, 600, 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..5 for top view (0, from top) / north (1) / east (2) / south (=3, processing default) / west view (4) / rotate (5). "
+"\nClick and hold mouse to see processing default view."
+"\nCurrent view: "
+viewText[viewMode],
15, 15);
}//func

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

void drawScene() {

// the sculpture

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() {
// for keys from 0 to 5
if (key>='0'&&key<='5') {
// apply as camera mode
viewMode=int(key+"");
setViewFromViewMode();
}//if
}

void setViewFromViewMode() {

cam.rotateFlag=false;

switch (viewMode) {

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

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

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

case 3:
//from south // default
// cam.reset();
cam.setEye(width/2, height/2, 400);
cam.setUpVectorToStandard();
break;

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

case 5:
cam.setUpVectorToStandard();
cam.rotate();
break;

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

//===========================================================

class CameraMy {

// to use the camera more easily

// standard values
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;

// for rotation
boolean rotateFlag=false;
float angle=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

// -----
// 3 set methods :

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

// ----
// 3 set methods for standard :

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 rotate() {
//init rotate
rotateFlag = true;
setLookAtToStandard();
}

// ----

void apply() {

// apply values

// rotation mode ?
if (rotateFlag) {
// rotation mode
eyePV = new PVector ( width/2.0 + cos(angle) * 400,
height/2.0,
sin(angle) * 400  ); // eye = camera position
angle+=.05;

camera (eyePV.x, eyePV.y, eyePV.z,
lookAtPV.x, lookAtPV.y, lookAtPV.z,
upPV.x, upPV.y, upPV.z);

return; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}//if rotateFlag

// normal modes :

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

PVector eyePV2, lookAtPV2, upPV2;

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

if (amt<1)
amt+=.025;
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) {

// help function: lerp for a PVector

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

return new PVector (  x, y, z  );
}//method
//
}//class
//
``````

update version of the previous sketch.

Added a new view “From Below” and a Batch Mode.

``````/*
New version with camera class AND smooth transitions (damping).
Demonstrates view from top down (above the sceen),
and from north, east, south and west and bottom and rotation.
The interesting part: the UP-vector when view from top.

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

Remark:
going from view 2 to 4 or 1 to 3 etc. it wasn't a nice transition.
To avoid this, we have a HashMap hmBatchList which is used to make
one inbetween-view between 2 and 4 (and 4 and 2, 1 and 3 etc.), so it looks nicer.

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

// The core class
CameraClass cam;

// view mode and its texts :

int viewMode=3; // This var dictates the current camera mode!

String[] viewText={
"top view",
"from north",
"from east",
"from south (processing default)",
"from west",
"rotating",
"From below"
};

// keys to change views
char oldKey=' ',
currentKey=' ';

// A HashMap hmBatchList and Batch variables:
// Note the HashMap's "key" is a String and "value" is a String
HashMap<String, String> hmBatchList = new HashMap<String, String>();
String resultStringBatch=""; // Batch commands
boolean inBatchMode=false;
int inBatchCounter=0;

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

void setup() {
size(1500, 600, P3D);
stroke(255, 0, 0);

// set cam
cam = new CameraClass();

// set Batch list
hmBatchList.put("from2to4", "34");
hmBatchList.put("from4to2", "32");

hmBatchList.put("from1to3", "23");
hmBatchList.put("from3to1", "21");

hmBatchList.put("from0to6", "36");
hmBatchList.put("from6to0", "30");

hmBatchList.put("from0to1", "21");
hmBatchList.put("from1to0", "20");

hmBatchList.put("from6to1", "21");
hmBatchList.put("from1to6", "26");
}

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..6 for: top view (0) / north (1) / east (2) / south (=3, processing default) / west view (4) / rotate (5) / from below (6). "
+"\nClick and hold mouse to see processing default view."
+"\nCurrent view: "
+viewText[viewMode],
15, 15);
}//func

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

void drawScene() {

// the sculpture

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

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

// ---

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

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

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

// ---

translate(0, 100, 100); // in front
fill(0, 0, 255);  // blue sphere
noStroke();
sphere(12);

translate(0, 0, -200); // behind the white center box
fill(0, 255, 0);  // green sphere
noStroke();
sphere(12);

// ---

translate(0, 100, 100); // behind the white center box
fill(255, 0, 0);  // red sphere
noStroke();
sphere(12);
//
}

//-----------------------------------------------------------------------------
// Inputs

void keyPressed() {
// for keys from 0 to 6

oldKey=currentKey;
currentKey=key;
resultStringBatch=null;

String searchString="from"
+ trim(str(oldKey))
+ "to"
+ trim(str(currentKey));

resultStringBatch = hmBatchList.get(searchString);

// Did we get a Batch result?
if (resultStringBatch==null) {
// No
// normal: just use the key
if (key>='0'&&key<='6') {
// apply as camera mode
cam.amt=0;
viewMode=int(key+"");
setViewFromViewMode();
inBatchMode=false;
}//if
} else {
// Yes
// apply resultStringBatch as camera mode in Batch Mode
inBatchMode=true;
inBatchCounter=0;
cam.amt=0;
viewMode=int(resultStringBatch.charAt(inBatchCounter)+"");
setViewFromViewMode();
} // else
} //func

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

void setViewFromViewMode() {

cam.rotateFlag=false;

switch (viewMode) {

case 0:
// top down
cam.setUpVector(0, 0, 1);  // Good: cam.setUpVector(0, 0, 1);
break;

case 1:
//from north
cam.setUpVectorToStandard();
break;

case 2:
//from east
cam.setUpVectorToStandard();
break;

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

case 4:
//from west
cam.setUpVectorToStandard();
break;

case 5:
// rotate
cam.setUpVectorToStandard();
cam.rotate();
break;

case 6:
// from below
cam.setUpVector(0, 0, -1);
break;

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

//===========================================================

class CameraClass {

// class to use the camera more easily

// standard values
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;

// for rotation
boolean rotateFlag=false;
float angle=0;

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

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

// -----
// 3 set methods :

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

// ----
// 3 set methods for standard :

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 resetPVOld() {
eyePVold=eyePV.copy();
lookAtPVold=lookAtPV.copy();
upPVold=upPV.copy();
}

//----

void rotate() {
//init rotate
rotateFlag = true;
setLookAtToStandard();
}

// ----
// Tools:

void apply() {

// apply values

// rotation mode ?
if (rotateFlag) {
// rotation mode
eyePV = new PVector ( width/2.0 + cos(angle) * 400,
height/2.0,
sin(angle) * 400  ); // eye = camera position
angle+=.05;

camera (eyePV.x, eyePV.y, eyePV.z,
lookAtPV.x, lookAtPV.y, lookAtPV.z,
upPV.x, upPV.y, upPV.z);

return; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}//if rotateFlag

// normal modes : ------------------------------

// we don't use the new values (eyePV,lookAtPV,upPV) directly but
// with eyePVold etc. and lerp (and its amt) we calculate eyePV2, lookAtPV2 and upPV2

PVector eyePV2, lookAtPV2, upPV2;

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

if (amt<1) {
amt += 0.025;
} else {
// amt is done
amt = 1.0;

// When we are in Batch Mode we go to next batch command
if (inBatchMode) {

inBatchCounter++; // go to next batch command
resetPVOld();

// if we finished the Batch
if (inBatchCounter >= resultStringBatch.length()) {
//reset
inBatchMode=false;
inBatchCounter=0;
resultStringBatch=null;
} else {
viewMode=int(resultStringBatch.charAt(inBatchCounter)+"");
setViewFromViewMode();
}//else
amt=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) {

// help function: lerp for a PVector

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

return new PVector (  x, y, z  );
}//method
//
}//class
//
``````
2 Likes