MrClock's Documentations
  • 🏠Welcome
  • 📄Documents
    • Arma 3 models
      • Proxy coordinates
      • Vertex normals
      • Sections
    • Arma 3 animations
      • Armature reconstruction
      • Frame properties
      • Import into Blender
      • BMTR to plain RTM
  • 📦Blender add-ons
    • Arma 3 Object Builder
  • 🐍Python tools
    • Color converter
  • 🔧Visual Basic .NET tools
    • Color converter
      • Color library TXT
    • Color library and converter
      • Color library XML
    • Class list extractor
    • Editor preview processor
    • Texture converter
  • 🛠️Visual Basic .NET Framework tools
    • Color library and converter
      • COLORLIB file
    • Class list extractor
    • Editor preview processor
    • Generic name ID generator
    • Texture converter
Powered by GitBook
On this page
  • Introduction
  • Differences
  • Conversion
  • Conceptual code
  1. Documents
  2. Arma 3 animations

BMTR to plain RTM

Documentation of the steps needed to restore a plain RTM file

Last updated 1 year ago

This page is meant to supplement and clarify certain informations written on the about the transformation data stored in binarized (BMTR) RTM files, prior knowledge of that article is required.

Introduction

Similar to P3D model files, RTM animation files are also converted into a format which is designed for easier operation for the Arma 3 engine. However, unlike the MLOD -> ODOL conversion, the RTM "binarization" is reversible without data lost (not counting the floating point, and other precision error side effects of the data compression).

Differences

While the plain RTM format stores transformation matrices, describing the absolute model space transformations of each bone from the resting pose, the BMTR format instead stores transformations in quaternion-location pairs. In addition to this, these transformations are also not absolute in model space, but relative to the parent bone, which means that the data is meaningless without a known skeleton bone structure.

Conversion

Quaternions are stored as fixed precision values. Each quaternion is made up of 4 (qx, qy, qz, qw) 16-bit signed integers. To get the actual floating point values, we need to divide each number by 16384 (2^14). The location vector on the other hand is stored as 3 (x, y, z) 16-bit half precision floating point numbers. They can either be read as unsigned integers, and converted to fractional numbers with some calculations, or read directly if the employed programming language supports it.

From the quaternion and location, we can recreate the 4×4 matrix representation of the same transformation.

Since Arma 3 uses a left-handed coordinate system, the commonly known conversion formulas need to be adjusted (certain component orders changed, some signs reversed).

Once these relative transformation matrices are colculated, we need to take the skeleton structure, and multiply the matrix of each bone with the absolute matrix of its parent bone, such that the final transformation matrix equals to matrix_parent × matrix_bone.

The multiplications must be preformed on the bones in hierarchical order.

Conceptual code

The following conceptual code snippets show how to read data from a "binarized" RTM file, and transform it into a format acceptable for Blender.

import struct
import numpy as np

# Following function reads a BMTR quaternion and a location vector from
# a file-like object, and returns the right-handed matrix representation
def transform_to_matrix(file):
    qx, qz, qy, qw = struct.unpack('<4h', file.read(8))
    x, y, z = struct.unpack('<3e', file.read(6))
    
    r00 = 1 - 2*qy**2 - 2*qz**2
    r01 = 2*qx*qy - 2*qz*qw
    r02 = 2*qx*qz + 2*qy*qw
    
    r10 = 2*qx*qy + 2*qz*qw
    r11 = 1 - 2*qx**2 - 2*qz**2
    r12 = 2*qy*qz - 2*qx*qw
    
    r20 = 2*qx*qz - 2*qy*qw
    r21 = 2*qy*qz + 2*qx*qw
    r22 = 1 - 2*qx**2 - 2*qy**2
    
    matrix = [
        [r00, r01, -r02, x],
        [r10, r11, -r12, y],
        [-r20, -r21, r22, z],
        [0, 0, 0, 1]
    ]

    return output

# We can collect the transformation matrices in a dictionary, where the key
# is the bone the transformation belongs to, and the value is the matrix
# With a second dictionary having the bone-parent pairs in hierarchical
# order, the RTM-like absolute matrices can be calculated
def calculate_absolute_matrices():
    matrices = {
        "base_bone": ..., # matrix
        "bone2": ..., # matrix
        "bone1": ... # matrix
    }
    bone_hierarchy = {
        "base_bone": "",
        "bone1": "base_bone",
        "bone2": "base_bone"
    }
    
    default = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
    for bone in bone_hierarchy:
        mat_bone = np.matrix(matrices[bone])
        mat_parent = np.matrix(matrices.get(bone_hierarchy[bone], default))
        
        matrices[bone] = (mat_parent @ mat_bone).tolist()
    
    return matrices

📄
community wiki