summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dimension/realize.c133
-rw-r--r--libdimension/geometry.c5
-rw-r--r--tests/dimension/demo.pov3
-rwxr-xr-xtests/dimension/demo.sh6
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