Blender 3D is a modeling software used to develop animated films, video games, etc. The software application is open source and free to download and to use. This makes the software very appealing to use for development. Although Blender supports many different exported file formats all of the file formats are lacking many features that Blender supports. To have access to everything that Blender supports within a homemade program a developer can access the Blender file directly.
To begin read the file as you would normally from the hard-drive and store the file within accessible memory. The file header will begin with the ASCII characters BLENDER and then following this will be the file’s pointer size ‘_’ 32 Bit or ‘-‘ 64 bit. After the file’s pointer size is the file’s endianess ‘v’ for little endian or ‘V’ for big endian and finally the Blender version that saved the file (248 for Blender version 2.48).
The second step after parsing the file’s header is to store into memory each data object and the object’s header. You will need to create a map that will be indexed by the old memory address of the data object. You will also need to preserve the order of the objects read into the map (I recommend using a vector map of pointers). After reading the first object into the map you can use the size of the data object (that was detailed within the header) plus the header size to find the next data object within the file. Simply loop through the file storing each data object and it’s header until the run-time pointer has reached the end of the file. While walking through the file search for the ASCII code DNA1 and save the old memory address into a variable. (I will explain Blender’s DNA logic shortly.)
After reading the file’s header the next block of memory is the first data object and it’s header. When a user of Blender saves his/her work to the hard-drive then Blender takes all the data within accessible memory and “dumps” it onto the hard-drive. Each data object begins with a header that describes what that data object was in memory when the user was actively using Blender.
The Data Object’s Header & the Data Object
- 4 Bytes ASCII code – this describe the object’s type following the object’s header
- 4 Bytes integer – the size of the data object
- 4 or 8 Bytes Pointer – the data object’s old memory address while the data object was in Blender’s accessible memory.
- To determine the size of the pointer use the ‘v’ or ‘V’ that was within the file’s header.
- 4 Bytes SDNA index – An index to a Blender’s Structured DNA
- Think of SDNA as a class or structure prototype. An SDNA describes an object before its instantiation.
- 4 Bytes Number of Elements – the number of elements within the data block
- X Bytes – The memory dump of the object as it was in Blender’s accessible memory.
The next step, after organizing the Blender objects into the map is to parse the Blender SDNA or structured DNA. A Blender SDNA is a prototype of a Blender object, structure, function, arrays, or primitive types before instantiation.
So to begin parsing, after the SDNA header should be two ASCII identifiers “SDNA” and “NAME”. The identifier ‘NAME’ is a header for a list of variable names that will follow the identifier (and the list size); for example with an SDNA “stBobType” then “fBob” would be a SDNA name and will be part of this list.
Following the “NAME” identifier will be a 4 byte integer that will indicate the number of Blender variable names. Use the number as a counter within a loop and store each name into an array within that loop.
A few notes, Blender DNA structures are 4 byte aligned; variable names that begin with ‘*’ are pointers for example ‘*next’ is a pointer named next; variable names that end with brackets like ‘vector’ is an array of three elements named vector; and variable names that begin with ‘(*’ and end with ‘())’ are function pointers within Blender (don’t be to concern of these).
Following the list of variable names should be another identifier with the ASCII character array “TYPE”. As with the list of variable names the identifier is followed by the number of types and a list of types. This list is the names of various Blender types; float, int, Scene, Mesh, etc. If we were using our earlier example then stBobType would be within this list.
Following the list of Blender types should be the another list that has the ASCII identifier “TLEN”. The list contains lengths for each type that was previously defined before hand; for example 1 would indicate the char within the previously defined list has a size of 8 bits or 1 byte.
To read both of these list from a Blender file I recommend that you use a structure or a class that once instantiated can be tracked within a vector array.
The next step is to link the information that we just read into Blender SDNAs. At the end of the TLEN list and the 4 byte alignment adjustment there should be an ASCII identifier “STRC” which indicates the start of the SDNA list. Following the identifier is a 4 byte integer that indicates the number of SDNA class templates within the list.
For each SDNA structure read the memory begins with an index to the SDNA “TYPE” and “TLEN” that we have read earlier. Following this index is a 16 bit count of the number attributes contain within the SDNA structure. For each SDNA attribute read the memory begins with an index to the SDNA “TYPE” and “TLEN”. Following this index is another index to the variable’s string name “NAME”.
For each SDNA structure that you build you should store each of the attribute reads into a map that will be indexed by the attribute’s string name “NAME”. After reading each SDNA structure store the SDNA into a vector array for later use.
Now that we have read the SDNA types we have enough information to start to build Blender Objects and Components. For each Blender data block within our earlier built vector array we can check the data block’s code (within the data block’s header) to find out what the data object is.
I’m not going to go into detail on how to parse each component and object that Blender supports. As you can see in my code I’m only parsing the items that is useful for my home project. However, I do have a few examples in articles linked below. After reading these few articles you will soon discover a pattern on how to parse each Blender item and can use that pattern to decipher the components that you need for your own projects. I recommend that you start with Parsing Blender Objects and then Parsing Blender Materials followed by your desired link.
- Parsing Blender 3D Files (*.blend) – (2 of 3) Blender Objects
- Parsing Blender 3D Files (*.blend) – (3 of 3) Linking Blender Objects and Components
- The mystery of the blend, The blender file-format explained by Jeroen Bakker
- Blender’s Python API Documentation
- Blender’s Source Code: folders makesdna and makesrna under source/blender.