
Changing the camera position by dragging via the mouse is a tedious and error-prone task. Bryce allows you to enter and change the camera coordinates,which are in a counter-intuitive coordinate system. Since we had to come up with the coordinates for a ca. 600 frame animation, I spent some time figuring out how to compute coordinates for intermediate frames, given a start and an end frame. This page explains what I found out and provides some code-snippets.
Each camera position has 5 "interesting" values: the x and y angle, and the xyz origin. With respect to the world coordinate system, the camera position is obtained by first applying the rotation and then applying the origin. This leads to the counter-intuitive behavior that one can not just change the angle and expect the camera to stay put in the world coordinate system. As a corollary, changing the camera origin without changing the angle might position the camera in unexpected positions in world coordinates, that is, in relationship to the whole model.
In order to compute intermediate coordinates, I do three things:
Here are some code-snippets. They are all in Smalltalk. The hardest part forme to figure out was the correct transformation sequence, the rest of the code is not that exciting, and you should be able to implement the stuff below in any programming language, maybe even in some spreadsheet. The snippets assume a class called Transformation that represents 4x4 matrices and appropriate operations, as well as a Vector class for xyz values (constructed as x@y@z, e.g. 100@200@300 will generate a Vector instance with x=100, y=200, and z=300). The class all these snippets are in is called Bryce, all the methods are on the instance side.
The class Bryce has three instance variables, id (for identifying the frame), angle (the x and y angles), offset (the bryce camera origin).
toWorld: c "Return a vector in world coordinates, reflecting the given camera coordinate" "(Bryce angle: 30@0 offset: 100@-210@237) toWorld: 0@0@0" ^c * (Transformation translate: offset) * ((Transformation rotateX: angle x negated) * (Transformation rotateY: angle y)). toCamera: w "Return a vector in camera coordinates, reflecting the given world coordinate" ^w * ((Transformation rotateY: angle y negated) * (Transformation rotateX: angle x)) * (Transformation translate: offset negated). to: end frames: n "Return n bryce objects, interpolating from self to b." "(Bryce id: 1000 angle: 4@-68 offset: 394@-123@10000) to:(Bryce id: 2000 angle: 4@-68 offset: 394@-123@3000) frames: 10" | ws we delta deltaAngle | ws := self toWorld: 0@0@0. we := end toWorld: 0@0@0. delta := we - ws / n. deltaAngle := self deltaAngle: self angle to: end angle frames: n. ^(0 to: n-1) collect:[:i| | na w b bn | na := angle + (i * deltaAngle). "new angle" w := ws + (delta ** i). "** multiplies vector by scalar" b := Bryce angle: na. bn := Bryce id: (self id + (i * 4)) "compute new id" angle: na offset: (b toCamera: w). bn ]. newAngle: a "Return a new bryce object, keeping the camera at the same spot in world coordinates, but with a new angle, e.g. (Bryce angle: 0@0 offset: 100@0@100) newAngle: -45@0 should return: (Bryce angle: -45@0 offset: 100@-71@71)" | w b bn | w := self toWorld: 0@0@0. b := Bryce angle: a. bn := Bryce angle: a offset: (b toCamera: w). ^bn
Here is an example, a 25 second excerpt (1MB) and scaled down version of Humanscapes, a video proposal by Joye Peters and myself:

|
|
|
|
|
