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