Grimrukh / soulstruct-blender

Blender plugins for FromSoft games, via `soulstruct`.
98 stars 4 forks source link

Soulstruct for Blender

This Blender add-on enables you to import and export a large number of different FromSoftware file formats.

It's powered by Soulstruct, my giant Python library of FromSoftware formats, and Soulstruct Havok, an experimental expansion library.

I developed these tools over the years in parallel with the development of Dark Souls: Nightfall, and finally put aside some time to polish and release them. I hope they serve you well and anticipate whatever mods they enable :)

Blender 4.1 or later is required. Earlier Blender versions use Python 3.10 (released in 2021), which I sadly do not have the bandwidth or inclination to support any longer in Soulstruct. Surface vertex normal handling was also greatly improved in Blender 4.1, making FLVER import/export significantly easier.

Older releases (<=1.9.3) are still available in the Releases section, which support Blender versions all the way back to 3.7, but lack many features and are no longer updated.

Table of Contents

Game Support

Game FLVER Collision Navmesh Animation MSB
Demon's Souls ✔️ ✔️ ✔️ ✔️
Dark Souls (PTDE) ✔️ ✔️ ✔️ ✔️ ✔️
Dark Souls (Rem.) ✔️ ✔️ ✔️ ✔️ ✔️
Dark Souls 2 ✔️
Bloodborne ✔️
Dark Souls 3 ✔️
Sekiro ✔️ ⚠️
Elden Ring ✔️ ⚠️ ⚠️

Other Features

I hope to eventually turn most remaining ⚠️ and ❌ symbols in the above table into ✔️ symbols, but it's hard work -- especially support for huge modern MSB files and Havok formats. If there's one feature that you want to see soon, I'm happy to consider it as a commission (which is how Demon's Souls support was added).

However, before you ask, it's unlikely that Collision export support will expand much further. Havok's collision physics system changed radically in 2014 (Bloodborne onwards) and I don't have the tools (or expensive Havok SDK) to be able to regenerate the bounding volume tree structures in these newer files (hkcd and hknp Havok classes). I may eventually add import support so you can at least view the collision meshes in Blender, though.

Installation

This is an experimental add-on that is not yet published to Blender. To install the add-on manually, follow these steps:

  1. Ensure you have Blender 4.1 or later, as Python 3.11 is required.
  2. Download the add-on .zip file from the GitHub repository (Releases).
  3. Unzip the contents into your Blender's user scripts/addons directory.
    • On Windows, the directory is typically at C:/<User>/AppData/Roaming/Blender Foundation/Blender/<version>/scripts/addons/.
    • Do not unzip the contents into the Blender installation directory (e.g. in Program Files). The Soulstruct module may not have write access there. If you see a PermissionError when trying to enable the add-on in Blender, check you haven't done this!
  4. Open Blender and go to Edit > Preferences > Add-ons.
  5. In the Add-ons tab, find Import-Export: Soulstruct and enable it by checking the box next to it.
    • If you see an error, particularly one about soulstruct module import, double check that io_soulstruct_lib is installed in the scripts/addons directory next to io_soulstruct.
  6. Press the N key in the 3D View window or click the little arrow in the top-right and you should see many new tabs including FLVER, Animation, and so on.

If you would like to install or update the add-on directly from Git without an official GitHub release, clone and update (or just download) the repo, and update the contents of scripts/addons/io_soulstruct from the main io_soulstruct folder in the repo.

Note that updated io_soulstruct versions without zip releases may also use newer versions of soulstruct and soulstruct-havok that need to be installed into scripts/addons/io_soulstruct_lib. I'll eventually add these as Git submodules to the repo. (You can update io_soulstruct_lib/soulstruct yourself using the Soulstruct repo, but as soulstruct-havok isn't public yet, this will be impossible to update.)

Whenever you update an add-on in Blender, you will need to either restart Blender (recommended) or call the Reload Scripts function from Blender.

Add-ons directory (you may have other add-ons and files here, like I do): addons_dir.png

Add-ons tab in Blender Preferences, after searching for 'Soulstruct': addons_tab.png

Basic Usage

The add-on implements many different operators for importing and exporting supported file types. These can be accessed in the new menus on the right of the 3D View.

The add-on also defines new Blender Object subtypes for the FromSoft file types supported by Soulstruct. You can see the subtype (if any) of the currently active Object at the bottom of the General Settings tab. (You can also theoretically modify its subtype here, but usage of this would be rare and require lots of other steps.)

NOTE: Blender uses a vertical Z axis and a right-handed coordinate system, while FromSoft games use a vertical Y axis and a left-handed coordinate system. Soulstruct will automatically convert between these systems when importing and exporting 3D positions and rotations. You should never need to worry about it when just working inside Blender, but keep it in mind, as copy-pasting 3D coordinates/rotations from raw FromSoft data or other applications like DSMapStudio will require you to do the transformations yourself. To transform between FromSoft and Blender positions and rotations, follow these rules (noting that they work in both directions):

general_settings.png

If an Object has a Soulstruct subtype, that subtype's properties will be exposed in a new Panel in the Object Properties window:

flver_properties.png

File import/export is handled using a Game directory and a Project directory, both of which can be set in General Settings. The Game directory is the root directory of a game installation (containing the EXE or BIN) and the Project directory should be a directory that mimicks the structure of the Game directory.

Many import operators will automatically find all relevant files in either the Game or Project directory (depending on which is defined and whether Prefer Import from Project is enabled) and offer a convenient choice of file to import. Many export operators will automatically export files to the selected Project directory if given (and the Game directory, if Also Export to Game is enabled). Some of these operators also require a current Selected Map, which should have format m??_??_??_?? and correspond precisely to a folder inside the 'map' subdirectory of the Game/Project directory. You can edit the name of this map directory, or use one of the buttons provided to choose an existing folder name from the Game or Project.

Format Information

FLVER Models

The core FLVER object is represented by a Blender Mesh Object. For simple static FLVERs such as Map Pieces, the Mesh and its Blender materials may hold all necessary data. However, for other FLVERs that support animations (or Map Pieces that use FLVER bones as a way to offset certain groups of vertices), the Mesh Object will be a child of a Blender Armature Object that holds the FLVER bones and controls the Mesh through weighted vertex groups.

This is done through Blender vertex groups that match the name of one of the bones in the Armature (see the Data Panel in the mesh's Object Properties window). If you're in Edit Mode on this Mesh, you can use the Data Panel to select vertices in groups or re-assign them. Unfortunately, it's not straightforward to tell how many different bones a vertex is weighted to (i.e. how many groups it appears in), but Soulstruct will report the index of any vertex illegally weighted to no bones or more than four bones (or more than one bone for Map Pieces).

NOTE: Every FLVER file needs at least one bone, including static Map Pieces. If this bone is at the origin and has no non-default properties (and the FLVER has no Dummies), Soulstruct will not bother creating an Armature parent when that FLVER is imported as long as the Omit Default Bone option is enabled, and will instead just re-create that default bone, and weight all vertices to it, when the Mesh-only FLVER is exported.

If a FLVER has any Dummies -- arbitrary points in the model that can be used for various purposes like sound effects, visual effects, hitboxes, and event scripting commands (also known by names like 'Model_dmy', 'dummy poly', or 'damipoly'-- these will also be children of the FLVER Armature (which will always be created if any Dummies are present) next to the Mesh. Dummies are a new Soulstruct subtype of Empty Objects in Blender and have several properties that can be set in the FLVER Dummy Properties Panel in the Object Properties window. Some info:

Each FLVER Material -- and some Submesh properties -- are represented by a Blender Material. Each material has a number of properties that can be set in the FLVER Material Properties Panel in the Material Properties window:

material_tab.png

Each FLVER Mesh in Blender is a combination of all 'submeshes' that appeared in the FLVER file, which are already optimized for rendering but often painful to edit separately due to being disconnected along certain edges (e.g. where a grass texture changes to a rock texture on the ground). If Merge Submesh Vertices is enabled when the FLVER is imported, these submeshes will be merged into a single mesh by Soulstruct using a complicated algorithm that takes materials and vertex information into account. Otherwise, the submeshes will remain disconnected. Either way, each face in the Blender Mesh is assigned to a Blender Material that reflects a combination of its FLVER material and a handful of FLVER submesh properties that Soulstruct stores on each Blender Material:

Soulstruct will attempt to find the MTD file (or MATBIN in Elden Ring) that defines each FLVER Material. This is necessary to properly handle FLVER UV layers, as these are tightly packed in each FLVER submesh and need to be properly assigned to named layers in Blender depending upon their material usage (otherwise, lightmap UVs may overlap with standard texture UVs, and so on). Soulstruct will also attempt to build a faithful Blender node tree that reflects the type of shader used by that MTD. This is all done manually by me right now and may not work, but even if FLVER materials aren't displayed properly, all of their information can be manipulated and exported as above.

NOTE: When exporting a FLVER model, only the part of its Blender name before the first space and/or dot (whichever comes first) will be used as the model name. This means you can add any extra information you want, and Soulstruct itself will e.g. add known Character names inside angular brackets for your convenience on FLVER import.

Map Collision Models (HKX)

Collision meshes are Havok mesh files (.hkx) that are placed in maps to define physical boundaries, killplanes, and more. The HKX file is complicated, but ultimately is just a collection of one or more simple meshes, each with a material index that determines its physical material, sound effects, and so on (wood, stone, metal, grass, ...). Each mesh subpart is assigned to a different Blender Material containing the material index in its name; this index is the only actual information associated with each Collision model.

NOTE: Just as with FLVER models, when exporting a Collision model, only the part of its Blender name before the first space and/or dot (whichever comes first) will be used as the model name. The hi-res ('h') and lo-res ('l') collision HKX files will both be created, with the appropriate subparts (by Blender Material) saved to each. It doesn't matter whether the model name itself starts with an 'h' or 'l'.

Demon's Souls users: If you are importing collisions from the unused map m07_00_00_00, note that these collisions do not have FromSoft's custom material data attached. Soulstruct will initialize the entire mesh with default material 0 but you will want to assign materials yourself before exporting. (Exporting will automatically use the proper format.)

Navmesh Models (NVM)

These are just meshes that define the walkable areas of a map. They are tightly connected to the MCG 'navigation graph'. Each face can have one or more flags attached to it (typically just zero or one), which is represented by a Blender Material (but not stored in that Material, unlike collision materials above). The flags can be modified through the NVM Navmesh Tools Panel under the Navmesh tab, as can the Obstacle Count of each face. The material will be updated in Blender automatically when the flags are changed.

navmesh_flags.png

NOTE: Just as with FLVER models, when exporting a Navmesh model, only the part of its Blender name before the first space and/or dot (whichever comes first) will be used as the model name.

Navmesh Models (NVMHKT)

Elden Ring navmeshes are stored in Havok files. Currently, Soulstruct has rudimentary import support for these meshes, so you can look at Elden Ring navmeshes. I have no plans to support export, as the Havok file contains a ton of other navigation data that would have to be reconstructed.

Navigation Graph (MCG)

A complicated navigation graph that accompanies the navmeshes for each map in DS1. It directly indexes Navmesh parts in the MSB of the same map; these MSB parts must be imported before the MCG can be imported, as the Nodes and Edges in the MCG directly reference the MSB parts in Blender.

Each MCG node sits at the boundary between exactly two MSB Navmesh parts and connects to all other Nodes that touch either of those navmeshes. The MCG edges that connect the nodes reference the MSB Navmesh part they pass through, and have a Weight property that affect how the game calculates paths through the graph. Soulstruct displays these weights by default.

mcg_graph.png

Each MCG node also references the index of at least one Navmesh model face for each of the two MSB Navmesh parts that it touches. These faces should be flagged as Exit in the Navmesh model (dark green) and typically lie very close to the node. If you select an MCG edge, the faces of that edge's linked MSB Navmesh that are referenced by the two nodes of that edge will (by default) by drawn in red (Node A) and blue (Node B), which you can use to check the graph.

mcg_selected_edge.png

I have reverse-engineered the algorithm that the game uses to calculate edge weights -- in most cases, at least, as it depends on the Navmesh model flags too. You can test it out under the NavGraph (MCG) tab in the MCG Generator Panel by selecting at least one edge and clicking Recompute Edge Costs. This will use my attempted algorithm to calculate the weight of that edge based on the position of its nodes and the linked MSB Navmesh part's model. The new value will be stored under Custom Properties as New Cost and compared to the real Cost under MCG Edge Properties. Depending on how close these values are, the cost that appears in the 3D View will be colored green with a tick (exact match), yellow (close match), or red (far off), so you can quickly see how my algorithm does.

mcg_edge_cost.png

Alternatively, you can select the full Collection of MSB Navmesh parts for a map, and click Create MCG from Navmeshes. Soulstruct will create MCG nodes wherever adjacent Navmesh Exit faces touch and connect them with edges through all shared Navmesh parts, computing edge costs with my approximate algorithm (realistically, you probably won't notice the effects of any differences).

NOTE: When an MCG is exported, if Auto-generate MCP is enabled, Soulstruct will automatically create the MCP file that goes with it, which is a simple collection of connected AABBs that correspond to the list of MSB Navmesh parts and their MCG connections.

Animations (HKX)

Animation files (HKX) that animate FLVER skeletons are supported for import and export. These animations are stored in ANIBND Binders for Characters and Objects/Assets (nested inside OBJBND/GEOMBND Binders for the latter). If you select a Character or Object/Asset FLVER in Blender (Mesh or its parent Armature), the Import Character Anim or Import Object/Asset Anim operators will become available in the Animation tab. These will automatically find the associated ANIBND and offer a choice of animations from inside it to import.

FromSoft animations are 30 FPS for all games, but will be converted to 60 FPS in Blender by interpolating every second frame as long as To 60 FPS is enabled. Make sure the Frame Rate is set to 60 FPS in the Scene Properties Panel to view these animations properly:

anim_frame_rate.png

Of course, you could disable To 60 FPS and set the Scene frame rate to 30 as well, but the animations will look like they're playing (unsurprisingly) at 30 FPS, even though their speed is correct.

There isn't much more to say about animations. Some miscellaneous points:

Map Placement Files (MSB)

Soulstruct now supports full MSB import and export for Demon's Souls and Dark Souls 1 (either version).

All Parts, Regions, and Events are imported. Part models can be imported as desired by type (and/or glob pattern), as FLVER import in particular is quite slow (especially for a high number of unique Map Pieces) and you may not need to edit or even see all models. Any models that aren't imported (whether it's because they were disabled or the file was missing) will be represented by a low-poly icosphere in a Collection called Placeholder Models. Character and Object models are kept in a Collection called Game Models, as they are game-wide, and Map Piece, Collision, and Navmesh models are kept in sub-Collections in a parent Collection called {MapStem} Models. You may wish to turn off visibility for the Model Collections after import if you only care about the MSB.

Parts are instantiated by sharing the mesh data of their Model (FLVER, Collision, or Navmesh). Parts are a separate Soulstruct types to their models, and only expose their MSB properties. You can edit base Part properties in the MSB Part Properties Panel, and the Part subtype properties in the MSB {Subtype} Properties Panel below it in the Object Properties window:

msb_character.png

Note that Draw Groups and other bit groups are individual bools hidden in sub-panels, and some settings that you are unlikely to touch (according to me, generally because they don't work) are hidden under Advanced Settings sub-panels. Aside from these settings, the only data that will be exported to the MSB is the Object's transform (location, rotation, and scale). (Note that in Dark Souls 1, MSB scale does not apply to Havok physics or animations, so it's only useful for Map Pieces and certain static Objects.)

Regions and Events are more straightforward, and are both kept in the same collection called {MapStem} Regions/Events.

msb_regions.png

The MSB Tools Panel under the MSB tab contains useful operators:

You must select the MSB parent Collection to export it.

Other miscellaneous notes/tips:

Known Issues

Bug Reporting

If you come across any problems or bugs, please file a Git bug report to help me improve the add-on.

Version 2.0 was a signifificant overhaul, so bare with me if any new bugs have appeared.