Arthur, Nendo Nessie, and Avalon 3D

Download the ArthurTest sample

Download nessie.obj

Just before I started working at Microsoft nearly three years ago, I wrote a hobby project called Windows OpenGL Classes (WOC). It’s written in VC++ 6.0 (but it compiles with VS.NET 2002) and it’s a kind of MFC for OpenGL. So it provides classes for application and window, as well as scene-graph and rendering management, and even a very flexible declarative animation system. It features geometry-generation and normal-calculation and the ability to read and write Wavefront OBJ files. The main feature missing from WOC is picking (i.e. selection, or hit-testing). I never got round to implementing picking, so I never got to experiment with 3D Windows controls which is something I’m greatly interested in.

 

Of course, Avalon provides most of the above features so I thought it’d be interesting to see if there were any parts of WOC which would add value to Avalon. For this experiment I’ve been using the March CTP of Avalon, running on Windows XP SP2. By the way, if you’d like a primer on 3D in general and Avalon in particular I recommend Daniel Lehenbauer’s blog (https://blogs.msdn.com/danlehen). I’ve called my new project Arthur, and there’s a screenshot of it above. The three main features which I’ll talk about in this post are: interactive camera manipulation, geometry generation, and geometry loading.

 

Help yourself to the ArthurTest sample source code from the link above. In Arthur\Viewport3D.cs you’ll find the definition of a class derived from Avalon’s System.Windows.Controls.Viewport3D. The added value of Arthur’s Viewport3D is to provide mouse manipulation of the camera. Depending on whether the symbol DX is defined, mouse input is handled either via DirectInput (for which you’ll require the DirectX 9 SDK) or via normal mouse input. By default, mouse manipulation is inactive for a viewport. In order to toggle into and out of mouse manipulation mode, use Ctrl+right mouse button. Once in mouse manipulation mode, if you depress both left and right mouse buttons whilst moving the mouse you will pan the scene. If you depress only the right mouse button whilst moving the mouse you will zoom the camera. If you don’t depress either button then you will effectively rotate the entire scene (lights and all). The rotation is actually achieved by moving the camera over the surface of an imaginary sphere. Up/down mouse motion affects the camera’s latitude (clamped to the range [0,180]), and left/right mouse motion affects the camera’s longitude.

 

There is some geometry generation code in Arthur\MeshGenerator.cs – I plan to add to it in time. You can use the static methods to generate meshes, and specify whether you want texture coordinates to be generated. Do be aware, though, that if you choose not to generate texture coordinates then you shouldn’t use an ImageBrush for your material otherwise nothing will be seen. Incidentally, the sphere’s geometry is calculated so that if you do set its material to an ImageBrush, the image will be upright with its center facing the default camera position.

 

Finally, in Arthur\FileLoaders.cs, you will find code to read geometry from Wavefront OBJ files. The ArthurTest sample uses this feature to read in a file called nessie.obj. It’s actually a textured model I created using Nendo 1.1. However, it isn’t textured in the screen shot above because the way OBJ files specify texture coordinates isn’t compatible with Avalon. I need to do some work yet to handle that difference. Another constraint is that the code currently only handles OBJ files having a single group in them.

 

So with the ability to load OBJ files we have an easy way to define geometry. I can use simple OBJ files to demonstrate how Avalon calculates normals when they are not supplied. The following OBJ file content defines two triangles at an angle to one another, sharing two common vertices. For this geometry, Avalon calculates vertex normals and the result is smooth-shading.

 

v -0.5 -0.5 0.5

v -0.5 0.5 0.5

v 0.5 0.5 0.5

v 0.5 -0.5 0

f 1 4 3

f 1 3 2

 

This next OBJ file content defines the same two triangle but this time there is no vertex sharing. For this geometry, Avalon calculates face normals and the result is flat-shading.

 

v -0.5 -0.5 0.5

v -0.5 0.5 0.5

v 0.5 0.5 0.5

v -0.5 -0.5 0.5

v 0.5 0.5 0.5

v 0.5 -0.5 0

f 4 6 5

f 1 3 2

 

As WOC handles its own normals, it can calculate face or vertex normals on request. Arthur doesn’t have that feature yet but it’s on my wish-list. If you do experiment with OBJ files, remember that Avalon (and the OBJ file format) uses a right-hand coordinate system and therefore triangles should be wound counter-clockwise. The ‘v’ and ‘f’ markers signify vertex data (x,y,z values) and face data (either triangles or quads) respectively. Make sure there’s a carriage-return between each set of data.

I no longer need WOC’s animation features. But in WOC, just like in Avalon, a camera is a model and can therefore be animated. WOC’s animations are provided by relays of signal-generating objects feeding into chains of functions, and ultimately bound to the properties of models. This way position, colour, etc can be animated. You can see some examples of this animation system in the Graphics Samples section of my website.

So what’s next? Well, because Avalon intrinsically provides most of WOC’s value proposition, there’s actually not a great deal more of WOC to port. There are one or two more geometry-generation methods to add (including my favorite, the ripple-grid). I’m very excited by what Avalon has to offer, and I’m looking forward to playing with its picking features to finally do those experiments with 3D controls I’ve been wanting to do. Watch this space!