I've been fiddling a little into raymarching SDFs in GLSL ES (Shadertoy) and found myself wanting to describe a camera as follows:
vec2 VISIBLE_SIZE = vec2( 20.0, 15.0 ); // how much World Resolution should be visible
vec3 CAM_POI = vec3( 0.0,0.0,0.0 ); // the Point of Interest in my scene
vec3 CAM_UP = vec3( 0.0,1.0,0.0 ); // camera up-direction
vec3 CAM_DIR = vec3( 0.0,0.0,1.0 ); // camera forward-direction
float CAM_FL = 2.5; // focal length of our camera
Thinking about how that might work brought up this:
//+ -VS.x/2 + POI + VS.x/2 || with d = length( POI - cam ):
// \ | / || -----------------------------
// \ | / || VS.x/2 1
// \ | / || ------ = -- => d = fl * VS.x / 2
// \ | / || d FL
// \ | / ||
// \ | / || for both dimensions: d = fl * VS/2 gives a vec2
// \ | / || => which d do we choose? Probably the maximum of
// -1.0 + + + 1.0 || both, so: d = max( fl*VS.x/2, fl*VS.y/2 )
// \ | / ||
// \f|l/ || Now that would make POI - d * CAM_DIR be our RayOrigin
// \|/ ||
// + cam || Also Aspect ratio should be used to reshape VS.x!
vec2 vis = CAM_FL * VISIBLE_SIZE * vec2( uResolution.y / uResolution.y, 1. ) / 2.0;
float d = max( vis.x, vis.y );
// that gives us a cam Position:
vec3 ro = CAM_POI - d * CAM_DIR
// Now we can build a coordinate base
vec3 forward = normalize( CAM_DIR );
vec3 right = cross( CAM_UP, forward );
vec3 up = cross( forward, right );
// Now we can calculate the screen center intersection point
vec3 sc = CAM_POI + forward * ( CAM_FL - d );
// Here UV applies -> we get the intersection point
vec3 ip = sc + ndc.x * right + ndc.y * up;
// From camera origin to intersection point is this pixels raydir
rd = normalize( ip - ro );
// Finally things between Camera and Screen are of no interest
ro = ip;
Now, trying this shows not to really work. Calculating this example thru gives:
vis: 2.5 * (20.0) * (600./800.) / 2.0 = ( 18.75 )
(15.0) (1.) ( 18.75 )
d: max( 18.75, 18.75 ) = 18.75
ro: (0,0,0) - (0,0,1)*18,75 = ( 0, 0, -18.75 )
forward: = ( 0, 0, 1 )
right: cross( ( 0,1,0 ), ( 0,0,1 ) ) = ( 1, 0, 0 )
up: cross( ( 0,0,1 ), ( 1,0,0 ) ) = ( 0, 1, 0 )
sc: ( 0,0,0 ) + ( 0,0,1 )*( 2.5-18.75 ) = ( 0, 0, -16.25 )
ip: with ndc=(1,1)
( 0, 0, -16.25 ) + ( 1, 1, 0 ) = ( 1, 1, -16.25 )
rd: norm(( 1, 1, -16.25 ) - ( 0, 0, -18.75 ))= normalize( 1, 1, 2.5 ) = ( 0.34816, 0.34816, 0.87039 )
ro: = ( 1, 1, -16.25 )
This looks pretty correct in a way. I AM MISSING SOMETHING, please - if you find it - point me towards it!