Introduction

A hallway conversation which Chris Anderson made me realize that when people ask me about 3D support in Avalon I have a bad habit of telling them everything they do not need to know.  After all, it is all the details you do not have to worry about that consume the waking hours of our 3D team (and it is what gives the Avalon 3D platform its value.)  However, despite our efforts to abstract the hardware, to encapsulate the mathematics, and to keep the 2D and 3D APIs symmetrical, there are some concepts which are inherently unique to 3D such as cameras and lighting.

This is the first in a series of posts intended to fill in the missing pieces for a developer familiar with a 2D graphics API who wants to dabble in 3D with the Avalon platform.  The topics I initially intend to cover are:

  • The 3D coordinate system
  • Transforms - (Part 2 now online)
  • The Camera
  • Defining 3D Geometry
  • Lighting
  • Materials

...but I am happy to adjust according to feedback.

The 3D Coordinate System

Most people are aware that 3D adds an extra dimension, Z, perpendicular to the X and Y they are familiar with from 2D.  The 3D coordinate system is frequently explained to 2D developers as follows:

  • The origin is now in the center of the screen instead of the upper left.
  • The positive X axis still points right, but Y now points up instead of down.
  • There is a new axis, Z, that points out of the screen (assuming a right handed coordinate system like Avalon).

This is expressed pictorially in figures 1 and 2 below:

The issue with this description is that while we can choose a camera orientation consistent with the above criteria (Figure 3) we can also choose vantage points like Figures 4 or even turn the camera upside down like Figure 5.

LookAtPoint=(0,0,0)
Position=(0,0,5)
Up=(0,1,0)
Figure 3
LookAtPoint=(0,0,0)
Position=(3,3,-3)
Up=(0,1,0)
Figure 4
LookAtPoint=(1,1,0)
Position=(3,3,-3)
Up=(0,-1,0)
Figure 5

The global frame of reference (aka World Space)

From Figures 3-5 hopefully the reader begins to get a sense that there exists a space created by the 3 perpendicular axes.  This space is commonly referred to as world space.  World space extends infinitely in both the positive and negative directions for all three axes.  In the above screenshots (Figures 3-5), the three axes always meet at (0,0,0) in world space (even though the location on the screen changes).  In world space, the model of the arrow labeled X extends along the positive X-axis <1,0,0>, the Y arrow along <0,1,0>, and the Z along <0,0,1>.  Again this is true in all three screenshots (Figures 3-5) even though the directions appear to change based on the camera orientation.

The point is, we can position our camera anywhere in world space and point it in any direction to generate images, but moving the camera does not change where things exist in world space.  World space is the stationary global frame of reference.  Since we are not focusing on positioning the camera this time around we will choose to adopt an orientation like Figure 6 (which was used to make the screenshot in Figure 3) for the remainder of this post. 

Local Frames of Reference (aka Model space)

The fact that I stated that world space is the global frame of reference implies that there are other frames of reference.  Each model object has a Transform property which we can use to move, size, orientate, etc. the model.  When we do this, we create a local frame of reference.  These local frames of references are commonly referred to as model spaces.  The concept of model spaces also exists in 2D, although we do not call them that.  Consider a canvas which contains a red rectangle defined to as (0,0)-(100,100) relative to the canvas:

Now consider Figure 8 which shows the canvas in relation to the screen.  Here we can see that while the rectangle exists in (0,0) - (100,100) relative to the canvas' local frame of reference, it may actually occupy (50,50)-(150,150) on the screen.

In 3D, it is common practice to author your geometry centered about the origin like the teapot shown in Figure 9.
 

Figure 9

And then use the three basic transforms (translate, scale, and rotate) to position, size and orientate the model to where you want it in world space.  The Avalon 3D object model exposes these transforms as the TranslateTransform3D, ScaleTransform3D and RotateTransform3D classes.  Like the camera, we will touch on how to configure these transform classes in a future post.  The point we want to make this time is that just like in Figure 8 where when the canvas is moved the rectangle is still defined as (0,0)-(100,100), when you apply a transform to a model 3D you are transforming the space in which the model is defined rather than the positions of the points in the geometry.  This local frame of reference is called model space.

translate
Figure 10
translate & scale
Figure 11
translate, scale, and rotate
Figure 12

Figures 10 through 12 show the effects of the basic transforms when applied to our teapot model.  A second axis has been added to show the effect this has on the model space of the teapot.  In Figure 10 we can see that when we add a translation of <0.5, 0,5, 0.5> this moved the teapot up, right, and towards the viewer.  This also created a model space where (0,0,0) in the model space is equal to (0.5, 0.5, 0.5) in the global world space.

Similarly, Figure 11 illustrates that adding a uniform scale of 0.5 not only scales the teapot, but also scales the local model space in which the teapot resides.  Moving 1 unit in this model space moves 0.5 units in global space.  Finally Figure 12 shows that applying a rotation changes the orientation of the teapot and at the same time changes the orientation of model space.  Moving along the Z axis in figure 12, for example, causes a change in all of X, Y, and Z in world space.

The importance of model space will became more clear next time when we investigate the transforms and the Model3DCollection class which allows us to build hierarchies of model spaces that allow us to do things like take the cone and cylinder which make one of the arrows in the axes we have been seeing in the screenshots and treat them as one "arrow" model even though they are separate primitives.

Continue: Part 2 now online