Skip to content

b3d reader

Fatalist Error edited this page Jul 9, 2024 · 6 revisions

The b3d module provides a method to read and write b3ds, as well as understand their contents.

Reading a .b3d

Writing a .b3d

The structure of a b3d parsed to a lua table

general structure:

for models with ONE mesh, we find that typically (at least through GreenXenith's exporter [link])
the b3d will be in the given structure, where the mesh is in the root node.

version
textures
brushes
root node (mesh)
  node (root bone)
    node (child bone)

we see, however, with multiple meshes, that we have a structure as such:

version
textures
brushes
root node
  node (mesh)  
    node (root bone) 
      node (child bone) 
  node (mesh)  
    node (rot bone) 
      node (child bone) 

if you missed it, the difference being that the root bone itself is a mesh bone. This means that when we have one unparented mesh, it'll default as the root bone.

It's also important to note that ALL bones show up in ALL "unparented" meshes, they just don't have anything in their "bone table" (see Bones as Nodes).

Nodes

Nodes are what makes up the structure of a b3d. A node may contain several different tables containing attributes, however typically there's only really three types of nodes with their own different tables they use for our intents and purposes.

There's the root node the bone node and the mesh node. The root node (as we've seen) may be it's own sort of empty structure, or a mesh. The root node of modlib's b3d is indexed by the name node, i.e. b3d.node. Really there's no such think as a "bone", "root" or "mesh" node. But for our purposes they're all defined by if they contain a bone or a mesh table, or for roots- neither. It's possible that you run into empty "pivot" nodes within our structure outside of the root, meaning a node that contains neither a bone or a mesh. This is essentially what a root node is.

A node will always contain these things:

  • keys
    a list of keyframes for the node.
  • children
    a list of child nodes, this makes up the structure
  • position
    a Vec3 containing position relative to the parent node
  • rotation
    a Vec4 (quaternion) rotation relative to the parent node
  • name
    a string containing the name. "ROOT" is for the root node (if multi-meshed)

as mentioned prior, they also may contain either of:

  • bone
    a list of weights by vertex that this bone influences (based on mesh of nearest mesh above it on the hierarchy) or
  • mesh
    a table containing information about the mesh

Keyframes (keys)

keyframes are data structures that tell us about the animations of a node. They're fairly simple in concept, they contain a 3 vectors and the frame it represents "frame". Like the position, scale and rotation property in a node, these in the keyframe are all relative to the parent node, it's not "added" to the position and rotation property of the node that the table is present in, it replaces those default values.

a simple empty keyframe table, the index in the table starts with the lowest frame.

position = {0,0,0}
rotation = {0,0,0,1}
scale = {1,1,1}
frame = 0

also note that (for some forsaken reason) Green's b3d exporter (or Modlib) populates EVERY keyframe instead of them being actual keyframes, so it's more like just regular frames. (hopefully that gets fixed one day)

Bone chunk

Bones contain the bone table. This is simply a list of vertices and their respective weights in relation to the bone. These vertices will be of the nearest parent mesh.

{
  [1] = 1
  [2] = .5 --this vert would only be influenced half by the movements of the node.
  . . .
}

Mesh chunk

(no docs)