Page 7: The CS559 Framework Code (GraphicsTown)
CS559 Spring 2023 Sample Solution
Prelude to Graphics Town
For the remaining parts of the workbook (two exercises), you will work with some framework code we have created for this class. Learning to work with the Framework code is important practically (you will use it on most of the assignments from here on), but also pedagogically. In the real world, you often have to work with code that someone else wrote.
The framework code allows you to focus on creating graphics objects and defining their behavior (for animation). You don’t need to worry about setting up a user interface, or the basic stuff of the world. It will give you “good enough” defaults that you can focus on the parts of the assignment you care about. For example, in this assignment, you can focus on making hierarchical objects. In future workbooks you will focus on making appearances (just wait).
The framework provides a “thin wrapper” around THREE.JS - you still program using THREE.JS, but you put your objects inside of wrapper objects, and define their behaviors as methods of these objects.
You will use the framework code for the rest of the assignments in class, so it is worth learning about it.
The best documentation for the framework is the code itself, and the examples that we give you. The code is designed to be (reasonably) self-documenting. We are trying to structure the comments to automatically produce a documentation web (using jsdoc), but that only gets some of the information. Here is a link to the Framework Documentation.
The framework is really helpful for small exercises where we simply want you to make an object. It will let you put the object on the screen with simple lighting and a simple UI with very little code. However, the real point of the framework is to allow you make a world with lots of objects that are all defined independently. This will let you make much more complex worlds. It also lets you add objects that we give you (or even to share objects with other students).
The framework will allow us to build “Graphics Town” - where you will create a world with lots of “living” stuff in it. The last workbooks/assignments of the semester will ask you to do this. The new assignments will ask you to make some objects and put them into simpler “worlds”. However, the objects you create can be re-used later in later assignments.
If you’re wondering where the “fancy features” of the framework are (shadows, multi-pass rendering, or other fancy things), just wait. As we learn things in class, we will give you extended versions of the framework that support these kinds of things.
Modern JavaScript
Learning about features of “modern” JavaScript is a learning goal of this assignment.
The framework code uses “modern” JavaScript. That includes modules and classes. We’ve actually had some of that in prior assignments, but this time you will see more of it. You will not be able to avoid writing a class
or figuring out how to export
from a module. Fortunately, we will provide a lot of examples, so you can always do things by modifying something we’ve given you to start with. However, we do recommend that you take some time to actually understand what is going on with the code.
If you want to learn about JavaScript classes, we have a basic tutorial for class Traditional Object Oriented Programming in JavaScript. To learn more about them (and other nice JavaScript features), most up-to-date books have discussions. See the Javascript in CS559 for suggestions. One specific recommendation: Exploring JS Ch15 has a nice introduction before it starts a deep-dive into some gory details and tricks to do fancy stuff.
Box 1: Object3D and GrObject
Here’s a simple example in 07-07-01.js ( 07-07-01.html).
Notice that this example has a ground object (the big flat gray box), it has lights, it has a camera in a reasonable location, it has orbit controls. You know how to do all that in THREE. So now, we can use the framework to do it for us.
The code is a bit simpler than if you had to write it yourself in THREE (this is an excerpt from 07-07-01.js:
|
|
On line 12, we create a GrWorld
object. This object takes the place of the scene and renderer in THREE (or, to be more precise, it creates a scene and a renderer and stores it inside). In fact, the “world” sets up many things for us:
- it creates a
Scene
- it creates a
Renderer
for us - since the Renderer will create a canvas (DOM element) for us, we need to say where we want it to go. If we say nothing, it sticks it at the end of the DOM. Here, we find a<div>
and put it in there. - it creates some lights - if we don’t like those lights, we can tell it not to
- it creates a camera and places it in a reasonable location
- it creates a “groundplane” - here, we change its color to gray (by default, it’s green).
- it does some other stuff too - you can read the code to see what happens. some of the things are more useful when the get to future assignments
Normally, we don’t need to worry about the THREE objects inside of the world, we just use the GrWorld
.
By now, you should be familiar with THREE’s Object3D
- the base class of objects you can put in the world. These objects can be meshes (and have geometry), they have transformations, you put them into the THREE.js scene
, etc.
The Framework defines GrObject
- which contains a list of THREE Object3D
(these are stored in the objects
member variable). We add GrObject
s to the GrWorld
.
For example, on lines 18-20 we make a THREE.js cube (a mesh with a box geometry and a material). Then on line 23, we make a GrObject
that holds this cube. On 25, we add the cube to the GrWorld
(Note: this takes care of adding the internal cube to the THREE Scene).
We can define subclasses of GrObject
that create different kinds of objects (by creating the appropriate THREE.js objects). Some of these are built in. For example, there is a GrCube
that, well, you can guess. See the example on line 30.
The THREE objects are inside of the GrObject
. If we looked at cube1.objects[0]
we’d find the Mesh we made on line 20. If we looked at cube2.objects[0]
we’d find a similar Mesh created insider the GrCube
constructor.
On line 34, we call go()
- a method of GrWorld
that starts an infinite loop with a render loop (using window.requestAnimationFrame
).
Read the code or documentation to see all of the options for these objects.
Box 2: Getting Started with a simple example
07-07-02.js ( 07-07-02.html) is another spinning cube example (from Page 3 (Axis Angle Representations) and the previous workbook and lecture). This time in the framework:
Everything is pretty much the default - except that we made the groundplane gray, not its usual green, since the cube is green. We got some lighting, a camera, orbit controls, an animation loop, and some other stuff “for free”. It may not be exactly what we want, but we get a reasonable default and can always change things.
The key parts are:
|
|
Walking through this:
- The main thing we do is define a new object type, a spinning cube. We create a class
SpinCube
that subclasses the built-in Cube type. Thesuper
call in the constructor runs the constructor of the base class (giving it an option that tells us the color). - The main thing we do in the new object is to define its behavior by overriding the
stepWorld
method. The method gets called every frame and tells the object to update itself. The first parameter (ms
) gives an estimate of how long it has been since the last redraw. This way we can adapt the speed in case our frame rate drops, rather than assuming our computer keeps up with 60 frames per second (16 milliseconds per frame). - Inside the
stepWorld
method we do the same angle increments we did in the original program. Two things to note:- First, since we need access to the THREE
Object3D
, we have to look inside the list of objects that are “owned” by theSpinCube
GrObject. We took advantage of the fact that we know that aGrCube
has only oneObject3D
. - Second, notice how we scale the spin rate by the time.
- First, since we need access to the THREE
- In the main program (the function
go
that is called on window load), all we need to do is:- create the world (making the
new GrWorld
) - make objects and add them to the world
- start the animation loop
- We could do more (add more objects, adjust things), but we don’t have to. We get reasonable defaults.
- create the world (making the
- Since there is a ground, we needed to raise the cube above the ground. Again, this means accessing the internal
Object3D
.
For a simple example like this one, the framework isn’t that much easier than just writing the code from scratch using THREE.js directly. It does save us from having to remember to turn the lights on and point the camera the right way.
In the simple example, we re-used a basic object (a cube). Just as when we use THREE directly, usually we will make more interesting objects. You’ll see that on the next pages.
Box 3: Another Simple Example
The first example showed how to make a simple animation. 07-07-03.js ( 07-07-03.html) is a different example, inspired by Page 2 (Euler Angles Toys). This time, rather than animating the cube, we control it with sliders. The nice thing: the framework will make the sliders for us!
This defines a different subclass of cube:
|
|
The big difference here is that when we created the cube subclass, we defined a set of “parameters” (the X, Y, Z) for rotation. They each range from $-\frac{\pi}{2}$
to $\frac{\pi}{2}$
. Since these are defined (with a name, range, and default value), the AutoUI code can make a control panel for it. Also notice how rather than defining a stepWorld
method, we provided an update
method that takes the slider values as its argument.
The main body of the code created the UI - but all this required was telling AutoUI
to do its job.
Again, this is a really simple case where we extend the cube. Under normal circumstances, we would extend the base class GrObject
and populate it with THREE objects ourselves.
The Framework and Hierarchy
The Framework doesn’t really handle hierarchy. A GrObject
stores a list of THREE Object3D
- not other GrObject
s.
That doesn’t stop you from making hierarchical objects using THREE objects, and then putting this hierarchical object inside of a GrObject
. There an example of this in the framework example file TestObjects.js called HingeCube
. On Page 5 (Hierarchical Modeling in THREE) there was an example where a cube was made inside of a GrObject
and then put inside of another cube.
One thing to note: you only put the top level GrObject
into the GrWorld
, and only the top level Object3D
into the GrObject
. This is very similar to using THREE by itself: you only place the top level parent GrObject
into the Scene
.
The Framework Code Ground Rules
Some ground rules about the Framework Code:
- You are strongly recommended to read the framework code. The code is meant to be somewhat self-documenting (with comments and type declarations). Part of the “learning goal” is to be able to figure things out by reading someone else’s code.
- Please avoid changing the framework code. Do not edit the files in the framework directory unless we give you explicit instructions to do so. If you feel like you want to make your own version of something, copy the code into your own directory (
for_students
) and make changes (be sure to give the code proper attribution). - If you find a bug in the framework code, please notify the instructors by Piazza.
- We appreciate suggestions on how to make it better - this includes things we could document better, or functionality that we might want to add. The framework code will most likely be used by many classes, so suggestions may help many future students.
- You are strongly encouraged to use the framework code. Learning to work within someone else’s (imperfect) code is part of the learning goals of the assignments. However, if you choose to implement things yourself, you will be responsible for providing all of the functionality that the framework provides.
- Future assignments will use the Framework code, but they may use newer versions.
Summary: The Graphics Town Framework Code
The main way to learn about the Framework code is to read the code and its documentation. But the most important thing to do is to try it out and do things with it. You’ll get to do that in the next two exercises.
First, we’ll go make Graphics Park on Page 8 (Exercise 2: Graphics Park).