Perspective and Camera Projection

CS 381 Lecture, Dr. Lawlor

Perspective is a funny thing.  Objects that are far away appear smaller than close objects.

Here's an example of what I'm talking about.  So I was riding in the backpack of my enormous Chinese lumberjack friend, "Big" Genbin Zheng:

Dr. Lawlor sprouting from Gengbin Zheng's Shoulder
















No, that's a lie.  Genbin is a normal-sized human.  It's just I'd been shrunk by a mysterious ray at Los Alamos National Labs, and Genbin was smuggling me out.

Dr. Lawlor tiny, in backpack
















Ok, that's a lie too.  Really, I was mugging for the camera about 30 yards behind Gengbin, which you can see by the shrinking path, and the angle at which Sameer Kumar is staring at me:
Dr. Lawlor tiny, in backpack





The human brain is really good at reversing the effect of perspective, and estimating the true size and shape of objects distorted by it.  We're so good at doing this, that actually just drawing exactly what you see--perspective--is pretty tricky. 

The ancient Egyptians never really got perspective, even in their amazing tombs.  The ancient Greeks never got perspective, even in their gorgeous vases.  The ancient arcade game Qbert didn't use perspective.

Perspective really started taking off in the 1400's in Italy--note how the floor is no longer a line in these images.   Hokusi got perspective, although he'd often use the hack (er, idiom) of interposing a layer of mist between foreground and background.  

Terminology:
In an OpenGL vertex program, an orthographic projection is easy to implement, by just dropping one of the input coordinates:
	vec4 v = gl_Vertex;
gl_Position =vec4(v.x,v.y, 0.0,1.0);
General isometric projections are a little trickier.  I always do this by first figuring out where I want the input axes to go onscreen, and then setting the scale factors so the axes lie in the right place:
	vec4 v = gl_Vertex;
gl_Position = vec4(
/* output X_w */ +0.7*v.x +0.0*v.y -0.6*v.z -0.3*v.w,
/* output Y_w */ -0.2*v.x +0.8*v.y -0.3*v.z -0.5*v.w,
/* output Z_w */ 0,
/* output w */ 1.0 );
This makes the input x axis lie at (+0.7,-0.2) onscreen (the scale factors on v.x), the Y axis lie at (0.0,+0.8) onscreen, the Z axis at (-0.6,-0.3) onscreen, and the origin at (-0.3,-0.5).  Try it!  You can even keep adding axes, to draw 4D or 5D isometric pictures, but your brain won't actually understand them...

True perspective can only be implemented with a divide operation--specifically, we divide by the distance from the camera Z.  But be careful!  If Z is negative (behind your head), it just results in negative X_w and Y_w--object behind you are just mirror-reversed, but still there.  OpenGL provides ways to "clip" out geometry that's too near or far away.
	vec4 v = gl_Vertex;
float s=1.0/(v.z+3.0); /* perspective scale factor */
gl_Position =vec4(
/* output X_w */ v.x*s,
/* output Y_w */ v.y*s,
/* output Z_w */ 0,
/* output w */ 1.0 );
To think about: how could you represent the perspective divide with a matrix?