diff options
-rw-r--r-- | dimension/realize.c | 133 | ||||
-rw-r--r-- | libdimension/geometry.c | 5 | ||||
-rw-r--r-- | tests/dimension/demo.pov | 3 | ||||
-rwxr-xr-x | tests/dimension/demo.sh | 6 |
4 files changed, 97 insertions, 50 deletions
diff --git a/dimension/realize.c b/dimension/realize.c index ea7fce8..11e37b9 100644 --- a/dimension/realize.c +++ b/dimension/realize.c @@ -152,12 +152,10 @@ dmnsn_realize_camera(dmnsn_astnode astnode) dmnsn_astnode_type camera_type = DMNSN_AST_PERSPECTIVE; dmnsn_vector location = dmnsn_new_vector(0.0, 0.0, 0.0); - dmnsn_vector look_at = dmnsn_new_vector(0.0, 0.0, 1.0); + dmnsn_vector direction = dmnsn_new_vector(0.0, 0.0, 1.0); dmnsn_vector right = dmnsn_new_vector(4.0/3.0, 0.0, 0.0); dmnsn_vector up = dmnsn_new_vector(0.0, 1.0, 0.0); dmnsn_vector sky = dmnsn_new_vector(0.0, 1.0, 0.0); - dmnsn_vector direction = dmnsn_new_vector(0.0, 0.0, 1.0); - double angle = 0.0; dmnsn_matrix trans = dmnsn_identity_matrix(); dmnsn_camera *camera = NULL; @@ -192,14 +190,66 @@ dmnsn_realize_camera(dmnsn_astnode astnode) break; /* Camera modifiers */ + case DMNSN_AST_LOOK_AT: - dmnsn_array_get(item.children, 0, &item); - look_at = dmnsn_realize_vector(item); - break; + { + dmnsn_array_get(item.children, 0, &item); + dmnsn_vector look_at = dmnsn_realize_vector(item); + + /* Line the camera up with the sky */ + + dmnsn_matrix sky1 = dmnsn_rotation_matrix( + dmnsn_vector_mul( + dmnsn_vector_axis_angle(up, sky, direction), + dmnsn_vector_normalize(direction) + ) + ); + up = dmnsn_matrix_vector_mul(sky1, up); + right = dmnsn_matrix_vector_mul(sky1, right); + + dmnsn_matrix sky2 = dmnsn_rotation_matrix( + dmnsn_vector_mul( + dmnsn_vector_axis_angle(up, sky, right), + dmnsn_vector_normalize(right) + ) + ); + up = dmnsn_matrix_vector_mul(sky2, up); + direction = dmnsn_matrix_vector_mul(sky2, direction); + + /* Line up the camera with the look_at */ + + look_at = dmnsn_vector_sub(look_at, location); + dmnsn_matrix look_at1 = dmnsn_rotation_matrix( + dmnsn_vector_mul( + dmnsn_vector_axis_angle(direction, look_at, up), + dmnsn_vector_normalize(up) + ) + ); + right = dmnsn_matrix_vector_mul(look_at1, right); + direction = dmnsn_matrix_vector_mul(look_at1, direction); + + dmnsn_matrix look_at2 = dmnsn_rotation_matrix( + dmnsn_vector_mul( + dmnsn_vector_axis_angle(direction, look_at, right), + dmnsn_vector_normalize(right) + ) + ); + up = dmnsn_matrix_vector_mul(look_at2, up); + direction = dmnsn_matrix_vector_mul(look_at2, direction); + + break; + } + case DMNSN_AST_ANGLE: - dmnsn_array_get(item.children, 0, &item); - angle = deg2rad*dmnsn_realize_float(item); - break; + { + dmnsn_array_get(item.children, 0, &item); + double angle = deg2rad*dmnsn_realize_float(item); + direction = dmnsn_vector_mul( + 0.5*dmnsn_vector_norm(right)/tan(angle/2.0), + dmnsn_vector_normalize(direction) + ); + break; + } /* Transformations */ case DMNSN_AST_ROTATION: @@ -221,53 +271,48 @@ dmnsn_realize_camera(dmnsn_astnode astnode) switch (camera_type) { case DMNSN_AST_PERSPECTIVE: { - /* TODO: this is not quite right, but it handles cameras specified with - `look_at' and `angle' correctly. `right' and `up' are assumed to point - in the x and y directions, respectively. `direction' and `sky' are - broken. */ - - /* Set the direction vector if we were given an angle */ - if (angle) { - direction = dmnsn_new_vector( - 0.0, - 0.0, - 0.5*dmnsn_vector_norm(right)/tan(angle/2) - ); - } - - /* These multiplications are in right-to-left order */ + /* These multiplications are in right-to-left order so that user + transformations happen after camera alignment */ trans = dmnsn_matrix_mul(trans, dmnsn_translation_matrix(location)); - /* Pan left-right */ - trans = dmnsn_matrix_mul( - trans, + /* Align y with `up' */ + + dmnsn_matrix align = dmnsn_rotation_matrix( + dmnsn_vector_mul( + dmnsn_vector_axis_angle(dmnsn_y, up, dmnsn_z), + dmnsn_z + ) + ); + + dmnsn_vector x = dmnsn_matrix_vector_mul(align, dmnsn_x); + dmnsn_vector y = dmnsn_matrix_vector_mul(align, dmnsn_y); + + align = dmnsn_matrix_mul( dmnsn_rotation_matrix( dmnsn_vector_mul( - dmnsn_vector_axis_angle( - direction, - dmnsn_vector_sub(look_at, location), - sky - ), - dmnsn_vector_normalize(sky) + dmnsn_vector_axis_angle(y, up, x), + x ) - ) + ), + align ); - /* Pan up-down */ - trans = dmnsn_matrix_mul( - trans, + + /* Align x with `right' */ + + align = dmnsn_matrix_mul( dmnsn_rotation_matrix( dmnsn_vector_mul( - dmnsn_vector_axis_angle( - direction, - dmnsn_vector_sub(look_at, location), - right - ), - dmnsn_vector_normalize(right) + dmnsn_vector_axis_angle(x, right, up), + dmnsn_vector_normalize(up) ) - ) + ), + align ); + trans = dmnsn_matrix_mul(trans, align); + + /* Scale the camera with `up', `right', and `direction' */ trans = dmnsn_matrix_mul( trans, dmnsn_scale_matrix( diff --git a/libdimension/geometry.c b/libdimension/geometry.c index 4aa46ec..dbc703a 100644 --- a/libdimension/geometry.c +++ b/libdimension/geometry.c @@ -91,10 +91,11 @@ dmnsn_vector_axis_angle(dmnsn_vector v1, dmnsn_vector v2, dmnsn_vector axis) dmnsn_vector_normalize(proj)); double angle = acos(c); - if (dmnsn_vector_dot(dmnsn_vector_cross(v1, proj), axis) > 0) + if (dmnsn_vector_dot(dmnsn_vector_cross(v1, proj), axis) > 0) { return angle; - else + } else { return -angle; + } } /* Matrix inversion helper functions */ diff --git a/tests/dimension/demo.pov b/tests/dimension/demo.pov index b99184b..9138dd1 100644 --- a/tests/dimension/demo.pov +++ b/tests/dimension/demo.pov @@ -23,8 +23,9 @@ camera { perspective location <0, 0.25, -4> right <1.6, 0, 0> - rotate <0, 53, 0> look_at <0, 0, 0> + + rotate <0, 53, 0> } background { diff --git a/tests/dimension/demo.sh b/tests/dimension/demo.sh index d129730..ab1d8e5 100755 --- a/tests/dimension/demo.sh +++ b/tests/dimension/demo.sh @@ -26,10 +26,10 @@ demo_exp=$(echo -n \ (location (vector (integer 0) (float 0.25) (integer -4) (integer 0) (integer 0))) (right (vector (float 1.6) (integer 0) (integer 0) (integer 0) (integer 0))) - (rotate (vector (integer 0) (integer 53) (integer 0) - (integer 0) (integer 0))) (look_at (vector (integer 0) (integer 0) (integer 0) - (integer 0) (integer 0)))) + (integer 0) (integer 0))) + (rotate (vector (integer 0) (integer 53) (integer 0) + (integer 0) (integer 0)))) (background (vector (integer 0) (integer 0) (float 0.1) (float 0.1) (integer 0))) (light_source |