xModels Info
Computer-generated graphics images are usually constructed in two stages: modeling followed by rendering. In the modeling stage, a geometric representation of the objects in the scene is constructed. The rendering stage produces the actual image, based on information in the model.
The xModels web app lets you describe scenes in a simple scene description language. Scenes are rendered as wireframe models, a very minimal kind of rendering which shows just the edges of all the objects in the scene — even edges that are behind other objects. The main point of the app is not to produce fancy images; the point is to learn some of the basic ideas of geometric modeling, not to produce attractive or realistic images.
(I wrote the original xModels program in the 1990s to use with my book, The Most Complex Machine, which was a survey of the field of computer science. Even though the book is now largely outdated, the principles illustrated by the program are still valid. The original program was written for Macintosh computers. It was later translated into Java, and now into the current version that runs on the Web.)
The xModels Interface
xModels is designed to be easy to use. This section describes the program's interface, but the major thing you need to learn about is the scene description language which is discussed in the other sections of this page.
The xModels web page has two main areas. At the top is a text editor where a scene description can be entered. And on the bottom is a large rectangle where the image will be displayed. Each area also includes some controls.
Above the text area is a popup menu that lists the sample scene descriptions that are available. (Note that scene descriptions are also referred to as "xModels programs.") Selecting an item from the popup menu will show the corresponding program in the text editor. The web page attempts to load nine sample programs into the popup menu. The first six samples are tutorial examples that you can read to learn about the xModels scene description language. You can probably learn enough about the language by reading the tutorial examples to create your own scenes.
If you want to create a new scene description of your own, select "[New Program]" from the pop-up menu. The text area will be cleared, and you can enter your own scene description. The "Save" button lets you save the scene description from the text area to a local text file on your computer. The "Load" button lets you select a text file on from your computer to be loaded into the text area. In most browsers, saving and loading files will use file save/open dialogs similar to those used in other programs. (Some browsers still use an older kind of file handling. In those browsers, saving a file will look just like downloading a file from the Internet, and loading a file will look like uploading a file to the Internet.) Saving and loading files is new in November, 2023.
Beneath the text editor is a "Compile and Apply" button. Click that button to render the image described by the program in the editor. But if there are syntax errors in the program, an error message will be displayed below the text editor instead. In the case of an error, the input cursor in the text editor will be moved to the point in the program where the error was found. Only the first syntax error in the program is found and reported.
Turning to the image display area, note that there is an input box above the image rectangle. Type commands from the xModels scene description language, and press return: The commands will be applied to the image. (Or if there is a syntax error in the commands, then the error will be reported.) This can be a great way to experiment with the scene description language!
There is also a column of controls to the left of the image. Clicking the "Clear and Reset" button will make the program forget any xModels commands that have been executed and will clear the image area.
The remaining controls in the graphics area allow you to control animated scenes. The animation capabilities of xModels are discussed later on the page and in several of the tutorial examples.
The Scene Description Language
Scenes in xModels are described in terms of three coordinates, x, y, and z. The computer's screen is the xy-plane, with the origin (0,0) at the center of the image. The positive y-axis extends upwards from this point, and the positive x-axis points to the right. The positive z-axis points directly out from the screen towards the viewer, so that points in front of the screen have positive z-values, and points behind the screen have negative z-values. This is a standard coordinate system for three-dimensional computer graphics. Of course, when a scene is rendered, all the points are projected onto the screen, that is, onto the xy-plane. But conceptually, the actual model can extend into 3D space.
The image display area includes the square region with -10 < x <10 and -10 < y <10. Since the display area in not square, it can actually extends beyond this range in the x direction. There is no way to increase or decrease the basic square region that is displayed, so scenes must be sized to fit into this region. (It is easy to scale objects up or down in size to fit.)
The three-dimensional world is projected onto the xy-plane from a point on the positive z-axis. The z-coordinate of this point is called the view distance, and its value can be specified as part of a scene description. (This name is somewhat deceptive. Since the display area always shows the same rectangle in the xy-plane, objects lying in that plane don't look any different as the viewDistance changes. The view distance affects object that lie in front of or behind the xy-plane.) The viewDistance can be set to "infinity" to give what is called a parallel projection.
Fundamentally, a scene description for xModels is a list of objects that appear in the scene, plus a few special commands. There are predefined commands, such as circle and cube, for adding objects to a scene, and predefined commands, such as red, for changing the color that is used to draw objects. There are special commands for specifying the background color, view distance, and animation parameters. There is also a special command for defining new objects and color names.
I should note that a scene description can contain comments. A comment begins with a semicolon (;) and continues until the end of the line. For multiline comments, a semicolon is required on each line. A comment doesn't have to start at the beginning of a line. Comments in a program are for human readers; they are ignored by the computer.
Except in the case of comments, xModels doesn't pay attention to ends-of-line. They are treated just like spaces. You can lay out your program any way you like on the page.
The xModels language is not case-sensitive: Upper and lower case letters are considered to be equivalent, so that for example, you can use xrotate, xRotate, and XROTATE interchangeably. Names can consist of letters, digits, and the underscore character (_). A name must begin with a letter or with an underscore. Names can be of any length.
Numbers can include decimal points and exponential notation. For example: 0, -17, 3.14, .5, 1.2e5. With just a few exceptions, anyplace where a number can appear in a program, a number range can also appear. Number ranges are used with animation, as described later on this page. Examples of number ranges are 1:10, -1:3:10, and 12::0. (The only places where number ranges cannot be substituted for numbers are in an animate command and for the first parameter of a lathe or extrude command.)
As a final preliminary point, I will note that commas can be included in a program to help make it more readable by humans. However, the computer ignores commas. More specifically, it treats them exactly the same as spaces.
Special Commands
The special commands in the xModels scene description language are animate, viewDistance, background, and define.
If the animate command occurs at all in a program, it must be the first word in the program (not counting any comments that might precede it). This command, which is used to specify the number of frames in an animation, is explained below.
The viewDistance command specifies the point along the z-axis that is used as the center of projection. An (x,y,z) point is projected onto the xy-plane by drawing a line from the center of projection through the point (x,y,z) and finding the (x,y) point where it intersects the xy-plane. Points with larger z-coordinates than the projection point are not displayed. The viewDistance command must be followed by a parameter that specifies the z-coordinate of the projection point. The parameter can be any positive number. If the scene is an animation, the parameter can be a number range. The parameter can also be the word infinity which specifies projection from infinity. A program can contain at most one viewDistance command. (However, you can use a viewDistance command in the input box above the image to change the view distance for an existing scene.) The viewDistance command does not have to come at the beginning of the program; however, it applies to the entire scene in any case. If no view distance is specified, a default value of 20 is used.
The background command is used to specify the background color for the scene. This command must be followed by a color specification, which can be either a color name or an RGB or HSB color, as discussed below. The background command can only be specified once in a program. (But you can change the background of the current image by entering a background command in the text input box above the image.) The default background color, if none is specified, is white.
The define command can be used to give a name to an object. Once a named object has been defined, it can be used in the same way as any of the built-in objects, including in other define commands. The word define must be followed by the name that is being defined, and then by the specification of the object itself. An object is generally a complex object, enclosed between [ and ], but that is not a requirement if the object specification consists of a single command. Defining an object does not make the object appear in the scene. To do that, you have to include the defined name as part of the scene description. The following example defines a "wheel" to consist of a circle and three lines:
define wheel [ circle line line rotate 60 line rotate -60 ]
You could then use the command wheel to add a wheel to the scene. Here is an example that defines a triangle command. The definition is a single command, so it does not have to be enclosed between [ and ].
define triangle polygon -1,-1 1,-1, 0,2
It is also possible to define new color names. For example:
define purple magenta define pink rgb 1 0.5 0.5
For color definitions, the definition should not be enclosed between [ and ].
Color Commands
The xModels scene description language has several predefined command for specifying colors. When a color command is given, it sets the drawing color to be used for all subsequent objects, up until the next color change. Color changes inside complex objects, that is between [ and ], have no effect past the closing ]. The default drawing color, if no color command has been given, is black.
A color can be specified by one of the following color names: red, green, blue, cyan, magenta, yellow, black, white, gray, lightGray, or darkGray. You can add new color names with the define command.
Color can also be specified with the rgb command and with the hsb command. The rgb command lets you specify a color by giving its red, blue, and green components. It requires three parameters to specify the three values. The values must be between 0 and 1, inclusive. For example:
rgb 0.5 0 0.5 ; specifies a purple color rgb 0:1 0 0 ; specifies a range of colors from black to red
The hsb command is similar, except it specifies a color by giving its hue, saturation, and brightness components. Again, these values must be between 0 and 1. (You can look this up in a graphics textbook if you don't know what it means.)
Objects
There are six predefined objects in xModels: line, square, circle, cube, cone, and cylinder. These objects are sized so that each object just fits inside a 1-by-1-by-1 cube, centered at the origin. The line object stretches along the x-axis from (-0.5,0) to (0.5,0). The square object has vertices at (-0.5,-0.5), (0.5,-0.5), (0.5,0.5), and (-0.5,0.5). The circle has center (0,0) and radius 0.5. The cone is oriented to point upwards along the y-axis; it has height 1, and the diameter of its base is 1. The cylinder also has a vertical orientation, with height and diameter equal to 1. To include one of these objects, just list its name in the scene description. Usually, the name will be followed by a transformation that affects the size, position, and orientation of the object.
There are also four commands for creating an object out of a list of points. These commands are polygon, polygon_3d, lathe, and extrude.
The polygon command takes a list of parameters that specify a sequence of (x,y) points. The polygon consists of these points joined by lines. Note that there must be an even number of parameters, since there are two parameters per point. For example, the following command creates a triangle:
polygon 0,0 4,0 2,2
The commas in this command are optional. (Remember that commas are treated exactly like spaces.) It's legal to have a polygon command with just two points. In that case, it specifies a line. The polygon-3d is similar, except that it takes a list of (x,y,z) points.
The lathe command takes a list of (x,y) points, joins those points with line segments, and then rotates the resulting curve about the y-axis to obtain a three-dimensional object. The original curve is actually copied several times, at different angles of rotation. These copies are then joined with further line segments. The number of copies must be specified as the first parameter to the lathe command. The remaining parameters specify the (x,y) points. For example, the following command makes four rotated copies of the line segment from (0,5) to (3,0) and then connects them with lines to produce a pyramid:
lathe 4 0,5 3,0
It is legal to have a lathe command with just one point. The result will be a regular n-sided polygon lying in the xz-plane.
The extrude command is similar to lathe in that it makes several copies of a curve that lies in the xy-plane, and it then joins those copies with lines. However, extrude makes the copies by translating the original curve along the z-axis. Each copy is separated from the next by one unit along the z-axis. The z-values are centered about 0. for example, for extrude 2, the two z-values are -0.5 and 0.5.
Besides all these basic objects, you can make complex objects. A complex object is a list of items enclosed between a left bracket, [, and a right bracket, ]. It can include objects and color specifications. Each object in a complex object can be followed by its own set of transformations, as described below. The commands in a complex object can be basic objects, named objects created with the define command, nested complex objects, and color commands. A color change inside a complex object affects the following commands inside the complex object, but it does not affect things outside the complex object.
Because of the ability to nest complex objects inside other complex objects, xModels is said to use hierarchical models.
Transformations
Any object can be followed by a list of one or more transformations that affect the size, position, and orientation of that object. This includes complex objects. Any transformation applied to a complex object is applied to that object as a whole. If an object inside a complex object has its own transformations, they are applied first, followed by the overall transformation of the object as a whole.
A transformation consists of a word specifying the type of transformation, followed by one or more parameters. For example, the command rotate 30 specifies that the object is to be rotated through an angle of 30 degrees about the z-axis. Some transformations take a variable number of parameters. For example, scale 3 will magnify the object by a factor of 3 in all directions, while scale 2,6,0.5 will scale it by factors of 2 in the x-direction, 6 in the y-direction, and 0.5 in the z-direction.
When an object is followed by several transformations, they are applied in the order given. For example, in
square xtranslate 5 rotate 30
the square is first translated 5 units in the positive x-direction, and is then rotated by 30 degrees about the origin. Putting the transformations in the opposite order:
square rotate 30 xtranslate 5
gives a different result, since the square is first rotated and then translated.
Here is a list of the transformations used in xModels, where A, B, C, D, E, F, and G are numbers (or possibly, in the case of an animation, number ranges):
- scale A B C — Scales by factors of A in the x direction, B in the y direction, and C in the z direction. Scaling by a fractional amount makes an object smaller. Scaling by a negative amount reflects the object through the corresponding coordinate plane. The scaling is centered at the origin; all other points move away from or towards the origin.
- scale A B — same as "scale A B B".
- scale A — same as "scale A A A".
- xscale A — same as "scale A 1 1"; scales in x-direction only.
- yscale A — same as "scale 1 A 1"; scales in y-direction only.
- zscale A — same as "scale 1 1 A"; scales in z-direction only.
- translate A B C — Moves each point (x,y,z) to (x+A,y+B,z+C). The effect is to move the object A units in the x-direction, B units in the y-direction, and C units in the z-direction.
- translate A B — same as "translate A B 0".
- translate A — same as "translate A 0 0"; same as "xtranslate A".
- xtranslate A — same as "translate A 0 0"; moves an object A units in the x-direction.
- ytranslate A — same as "translate 0 A 0"; moves an object A units in the y-direction.
- ztranslate A — same as "translate 0 0 A"; moves an object A units in the z-direction.
- xrotate A — Rotates everything though an angle of A degrees about the x-axis. The x-axis is fixed, and everything else pivots around it. The direction to use for positive angles is determined by the "right-hand rule": Point the thumb of your right hand in the direction of the positive axis, and the fingers of your right hand will curl in the direction of a positive angle.
- yrotate A — Rotates everything though an angle of A degrees about the y-axis.
- zrotate A — Rotates everything though an angle of A degrees about the z-axis.
- rotate A — same as "zrotate A". In the xy-plane, this looks like a rotation about the origin, with positive angles representing counterclockwise rotation and negative angles, clockwise rotation.
- rotate A about B C — Rotate through an angle of A degrees about the line that starts at the point (B,C,0) and extends in the same direction as the positive z-axis. In the xy-plane, this is just rotation about the point (B,C).
- rotate A about line B C D — Rotate by an angle of A degrees about the line that goes from the origin, (0,0,0), to the point (B,C,D). (The two words "about line" can also be written as a single word "aboutline".) If (B,C,D) = (0,0,0), nothing happens.
- rotate A about line B C D E F G — Rotate by an angle of A degrees about the line that goes from the point (B,C,D) to the point (E,F,G).
- xSkew A — This is the transformation which moves (x,y,z) to (x+Ay,y,z). Lines that were perpendicular to the xz-plane are tilted (or "skewed") to the left or right.
- ySkew A — This is the transformation which moves (x,y,z) to (x,y+Ax,z).
- xyShear A B — This is the transformation which moves (x,y,z) to (x+Az,y+Bz,z). Lines perpendicular to the xy-plane are skewed. (I have not included a complete set of skew/shear transformations, because I don't expect them to be used much.)
Note that although xModels is a 3-dimensional graphics program, you can restrict yourself to two dimensions if you want. The names and semantics of the transformations were chosen so that all the two-dimensional transformations are available with reasonable names. This explains the otherwise odd rotate A about B C, for example.
It is important to understand what a list of transformations does to an object. All the transformations are applied to the object before it is displayed. So, square scale 2 5 is just a way of specifying a 2-by-5 rectangle, and circle translate 5 is just a way of specifying a circle centered at the point (5,0). You don't actually see the object moving or changing shape. For that, you have to use an animation and specify a range of values for the transformation. In that case, each frame of the animation gets its own transformation to specify the shape or position of the object in that frame. The object can change from one frame to the next, because a different transformation is used in each frame.
Animation
An animation is just a sequence of frames. Each frame contains a separate image. If the images don't change too much from one frame to the next, the viewer will perceive continuous motion when the frames are played back in rapid succession.
In xModels, a scene description that starts with the command animate N, where N is a positive integer, is an animation with N+1 frames. The frames are numbered from 0 to N. (You should think of N as the number of intervals between frames.) Then, to get any kind of motion or change in the animation, you need to make some quantity change from frame to frame. This is done by using a number range in place of a number. A number range consists of a starting value, followed by a colon, followed by a final value. In each frame of the animation, the number range represents a different value. For example, in an 11-frame animation, the number range 0:5 represents 0 in frame 0, 0.5 in frame 1, 1 in frame 2, ..., and 5 in frame 11. Thus, the scene description:
animate 10 circle scale 0:5
shows a circle that grows from a size of 0 in the first frame to a size of 5 in the last frame. And
animate 30 square scale 5 rotate 0:90
shows a 5-by-5 square pivoting through a 90-degree turn about the origin. Note that the value 5 in this example is the same in each frame. You don't need to use a number range for each value in an animation — only for the values that you actually want to change during the animation.
By adding additional parameters to the animate command, you can make "segmented animations." For example, the command animate 30 50 specifies an animation with two segments. The first segment has 31 frames, and the second segment has 51. The final frame of the first segment is also the first frame of the second segment, so there are 81 frames in all. (Remember that the numbers 30 and 50 actually specify the number of intervals between frames.) An animation can contain any number of segments. The first frame of the animation, the last frame, and any frame that is on the boundary between two segments are called key frames.
A number range used in a segmented animation must specify a value for each of the key frames. Thus, it must have exactly as many colons as there are segments in the animation. For example, the number range 10:5:7 could be used in a two-segment animation. During the first segment, the value ranges from 10 to 5, and during the second segment, it ranges from 5 to 7. The number range 0:0:10 has the constant value 0 throughout the first segment, and then its value ranges from 0 to 10 during the second segment. Sometimes, you want a quantity that changes at a constant rate during the whole animation, rather than at different rates in different segments. The notation for doing this is to use two or more colons in a row, with no numbers between. For example, 0::10 represents a quantity that varies evenly from 0 to 10 across both segments of a two-segment animation.
The xModels web page has a set of controls for controlling animations, located to the left of the image display area. There is a "Run Animation" button for starting or resuming an animation, a "Pause Animation" button for pausing a running animation, and a "Next Frame" button that will display just the next single frame of an animation that is paused. These buttons are only enabled when using them makes sense.
A "Frames per Second" popup menu controls the speed at which an animations run, ranging from 60 frames per second down to 1 frame per second.
And an "Animation Style" menu specifies what happens in an animation when the last frame is reached. If this menu is set to "Loop," the animation is repeated starting back at frame zero. If it is set to "Back And Forth," the animation is played backwards, then forwards again, and so on. If it is set to "Once Through," the animation is paused when it reaches the final frame.