Skip to content

Modules

Crowfunder edited this page Jun 22, 2023 · 2 revisions

Modules are single-file scripts supposed to take a filename as an input, outputting the desired 3D model data into geometries list of dictionaries. Modules are recursively imported and placed in modules.__modules__ dictionary as "file_extension" : module_object. Each module is responsible for a single model type (file extension contained in the module's filename). All of them also have their own metadata.

It's important to note that all modules should del vars that will not be used any further , or at the very least those storing a lot of data (vertices, bone names, bone trees, indices etc.) Afterwards the module should call gc.collect() from gc library.

Module Structure

Module skeleton is quite simple:

module_data = {
'Name' : 'Module Name',
'Mesh' : True/False,
'Armature' : True/False,
'Animations' : True/False,
'Multimesh' : True/False
}

def Extract(file_name):

	...
	return geometries

(By all means, deviations from this structure such as other functions, imports etc. are allowed, this skeleton presents only the bare minimum.)

module_data

Module metadata in a dictionary. In case it's necessary more supported metadata tags will be added. For now, only these are available:

  • Name - Module name, doesn't have to be the file extension, can be the full name of the handled model type
  • Author - Module author
  • Mesh - Module supports standard mesh data such as geometries, texture mappings
  • Armature - Module supports armature data (bone names, indices, weights, hierarchies)
  • Animations - Module supports animation data (NOT YET IMPLEMENTED)
  • Multimesh - Module supports exporting multiple geometries from the file separately

Extract(file_name)

The function is exposed to main.py, returns geometries list and takes a file_name string as an parameter.

geometries is a list of dictionaries, each containing the data of a single geometry in the file. Even modules that do not support Multimesh have to return it as a list of dictionaries.

Each such dictionary is usually named args within the module, although it is not a necessity. However, all dictionary keys are standarized so that they comply with the templates. Every value of the dictionary has to be a string (otherwise, ExportXML will throw an exception).

IT IS ALSO IMPORTANT NOT TO LEAVE ANY VALUES AS AN EMPTY STRING, SPIRALVIEW PARSER WILL NOT ACCEPT A PARAMETER WITH AN EMPTY STRING AS A VALUE. IF YOU WISH TO LEAVE A PARAMETER EMPTY, USE A SPACE " " INSTEAD!

Keys of args:

  • min_extent/max_extend - min/max vertex coordinates. It represents the smallest AABB (axis aligned bounding box) that can contain the entire model.

  • mode - Geometry mode, in most cases TRIANGLES should be used, as it is the standard one. The rest are experimental: LINES, POLYGON

  • indices - Model indices. Important to note that in the standard SK model format all primitives use the same set of indices. In case a model has different indices for every primitive, it will be necessary to reorder all primitives to follow a single set of indices

  • indices_end - Biggest index from indices

  • vertices - An array combining Bone Indices, Bone Weights, Texcoords, Normals and Vertices. Note: Clyde supports only 4 Bone Index/Weight slots, unused ones have to be filled with 0.0, for example: 1.1, 2.2, 0.0, 0.0
    Vertices array is ordered as such:
    -- Has Armature: 4 Bone Index Slots, 4 Bone Weight Slots, 2 Texcoords, 3 Normal Coords, 3 Vertex Coords
    -- No Armature: 2 Texcoords, 3 Normal Coords, 3 Vertex Coords

  • bones - Bone/Joint Names Note: If this key is set to '', Kozmadeus will interpret it as if the model has no armature and will use the armature-less template

  • bone_tree - SKxml armature hierarchy. That's the single xml thing that cannot be filled into a template and has to be generated dynamically.

The bone_tree format:

<root>
    <name>%ROOT%</name>
    <transform>
        <matrix>{MATRIX_DATA}</matrix>
    </transform>
    <children>
        <entry>
            <name>{BONE_NAME}</name>
            <transform>
                <matrix>{MATRIX_DATA}</matrix>
            </transform>
            <children>
                <entry>
                    ...
                </entry>
                ...
            </children>    
        </entry>
        ...
    </children>         
</root>

The whole tree is constructed out of several bone nodes, that have three attributes:

  • <name> - Bone/Joint Name
  • <transform> - There are two ways of describing transformations:
    a) <translation>, <rotation> and <scale>: three separate tags describing bone translation and rotation
    b) <matrix>: 4D Matrix representing transformation data
    Note: "No transformation" can be done simply by not using any of the following method's tags, i.e no rotation eliminates the need for <rotation> tag
  • <children> - List of children nodes

There are several cosmetic differences between the root node and the children nodes:

  • Root Node: Note: Root node theoretically doesn't have to be named "%ROOT%", it's just the SK-wide standard
<root>
	<name>%ROOT%</name>
	<transform>
		{Any or no transform method}
	</transform>
	<children>
	</children>
</root>
  • Child Node:
<entry>
	<name>{BONE_NAME}</name>
	<transform>
		{Any or no transform method}
	</transform>
	<children>
	</children>
</entry>

Bundled Modules

At the moment, Kozmadeus comes prebundled with two modules. Capabilities comparision:

Wavefront Collada
Mesh YES YES
Armature NO YES*
Animations NO NO
Multimesh NO YES

*Partially supported, several issues are known to occur.

Wavefront [obj.py] (Legacy Module)

This module is basically a retrofit Bootshuze, its inner workings remain practically the same with some minor differences.

Collada [dae.py]

Collada module utilizes pycollada for parsing the file. Heed the warning, this module is extremely overcomplicated and is far from perfect, many issues may be present, some of which may not be ever patched. Unfortunately, in comparision to Collada, Clyde is extremely out of date and lacks many capabilities. Hence, in many ways the module will be limited.

Limitations and Known Issues:

  • Bone Indices and Weights support only 4 slots per data type. In case the model uses more than 4 weights, the script will attempt to remove the smallest ones, but it may not work properly. It is recommended to use blender weight limit function.
  • Most of the external armatures (that are pretty complex) turn out to be broken when imported, reasons unknown. Best bet is reusing the game armatures or simplistic armatures.
  • Reimported SK models behave unpredictably with stock SK animations, the issue may be solved once importing animations is implemented, for now use the Armor Import Method (See Usage).
  • Models should use a single primitive type (triangulate it) and a single material mapping (make sure it uses a single texture) per geometry. The importer will try to handle it but issues may arise, such issues will not be supported.

Precise code documentation to be added later. For now refer to the code comments if necessary.