A big part of creating the SOUR format was writing a parser to get the models into Away3D. (A parser is a part of a program which reads data in a storage format and changes it into a usable format.) In this article, I’m going to go through the basics of writing an Away3D parser.

The Parts

An Away3D parser has six fundamental functions you need to use:

  • the constructor and super() in it
  • proceedParsing()
  • hasTime()
  • supportsType()
  • supportsData()
  • finalizeAsset()

The Parent Class: ParserBase

You’ll need to extend Away3D’s ParserBase class to get access to the functions mentioned above, and to make your parser compatible with the AssetLibrary.

The Constructor

Like any AS3 constructor, the constructor function will have the same name as a parser class. So for our parser, SOURParser, the constructor is SOURParser(). The only thing you need to worry about doing in the constructor (though you can do more if you so choose) is using the super() function. ParserBase, the parent class, takes a single argument, either ParserDataFormat.PLAIN_TEXT or ParserDataFormat.BINARY, depending on what kind of 3D file is being parsed.

Compatibility Checking

Away3D parsers attempt to determine whether the data being fed to them is compatible in two ways: by examining the file extension and by checking the contents of the file for certain strings which are a part of the file’s formatting. supportsType() does the former and supportsData() the latter. Both return a boolean. Override them and modify them as is appropriate for your 3D file format.

The Actual Parsing

How a parser reads your data is really up to you. For SOUR, I chose to do a line-by-line approach in a while loop, much like the OBJ parser does. All the parsing gets done in proceedParsing().

One nice feature of Away3D’s ParserBase though, is that it has the hasTime() function, which allows you to do the parsing over the course of several frames rather than all at once. Why does that make a difference? If you’re attempting to read a file all at once and the file is too large to be processed in the time in between frame renders, the parsing will continue until it’s done and THEN the next frame will get rendered, causing frame loss. Using hasTime(), you can determine if you’ve exceeded the time limit between frames yet, in order to break the job of parsing down into smaller pieces, and not lose frames. If everything gets preloaded, it won’t make a difference, but if some assets are loaded on the fly, it’s rather important.

When you finish reading data from your 3D file and reconstructing it as a Mesh, Geometry, Animation, Texture, etc., you’ll want to pass that 3D-formatted data back to your application. You do that with finalizeAsset(), which takes the data itself, automatically figures out the AssetType, and delivers it back to your application via an AssetEvent. The process of turning a 3D file into Mesh data is the subject of another article.

Note: SOUR was created during my time with Kumoshi.

Our custom 3D format, SOUR, has gotten an upgrade. SOUR now has the capability to include “attachment points”, which will allow us to put things in avatars’ hands, things on their heads, etc. Behold:

sour2_1

The mechanism is pretty simple. See the red and blue dots? Their positions get saved alongside the animation keyframes. Moving the attached objects with them is as simple as telling the attached object to “go” to the red one and “look” at the blue one. Of course, the red and blue dots needn’t actually be shown.

Working on a game or 3D project that could use this sort of functionality? Check out SOUR’s Github page.

SOUR is a custom 3D file format designed to bridge the gap between Blender and Away3D. Aren’t there other formats which Blender exports and Away3D reads? Yes there are: OBJ, 3DS, MD2, MD5, AC3D, DAE. However, none of these formats except for DAE can save vertex tangents, and the DAE export script for Blender doesn’t save them.

What are vertex tangents, and why do they matter? Let me break it down.

What’s a Vertex Tangent?

You may know that 3D models are made of triangles. Each triangle has three points, called vertices. A vertex is a point in 3D space. Like a point in 2D space, a vertex has an X and a Y coordinate, but for 3D space, a vertex also needs a Z coordinate. There is other information related to each of a triangle’s three vertices too. I won’t go too deep into it except to say that the other information is used to light the 3D shapes correctly, and that part of that information about each vertex includes a second set of three numbers called a “vertex tangent”.

Vertex tangents are very important for “normal mapping”, a technique used to make a low-detail version of a 3D model look like it’s a high-detail version. Using normal mapping reduces the amount of power your graphics card needs to render a given 3D model, and thus increases performance without sacrificing much quality.

Back to Away3D and SOUR

Since none of the currently existing Blender export formats save vertex tangents, when Away3D reads the models, it realizes that there are no vertex tangents and attempts to figure them out itself. This is all well and good if the program used to create the 3D model’s normal map and Away3D are using the same vertex tangent generation math. Blender and Away3D don’t. The result is ugly seams on models using normal maps.

sour1_1

SOUR solves this problem by saving vertex tangent information into the 3D file. Away3D never gets a chance to generate (not incorrect but) mismatching vertex tangents, and the models look spiffy.

sour1_2

SOUR has a few other features too:

  • indexed & compressed to save space
  • bone or keyshape-based vertex animation
  • also exports vertex normals
  • has a Blender export script, an Away3D parser, and a Github page

If you do a Google search for “normal map seams”, you’ll find that Away3D isn’t even remotely the only engine which suffers from the nonstandard normal map generation problem. JMonkey, OGRE, XNA, and others all have this issue. I would love to see SOUR used more widely. If you have any suggestions for the format, leave them in the comments.