Research - Bannerlord Models

Users who are viewing this thread

Thanks to szszss and her TpacTool, we have access to elements of Bannerlord's asset packages. I thought it might be interesting to share some of our insights in advance of TW publishing their modding tools, documentation and workflow guides. I'll kick off with the following observations:

1. Poly-count vs optimisation
Given larger scale battles and extensive use of LODs, I expected tight budgetary ranges for poly-counts. Umit Singil's Dev blog suggested 8,000-12,000 polys for most armours. So, I was surprised by some extreme differences in poly-count such as these two Vlandian body armours:
92Ag7.jpg
veteran_mercenary_armor, on the left, weighs in at 19,694 polys vs templar_a_red, on the right, at 2,652 polys. In fact, this mercenary armour uses more polys at LOD3 than the templar armour does at LOD0. At LOD5 the mercenary armour still uses 933 polys vs a mere 113 polys for the templar armour.
Clearly, modders catering only for players with hi-spec pcs can include higher poly meshes than I suspected.

2. Feminization of Armours
In Warband, feminized armours were held in a separate vertex frame. In Bannerlord, each male body armour is accompanied by a feminized version called armourname_converted. Clearly these are automatically generated by some tool as: a) they have identical poly-counts despite differing chest bulges and b) female dresses and armours which don't need to be feminized are still accompanied by an auto-produced and redundant _converted version.

3. Eliminating glove clipping
Every male or converted (feminized) body armour is accompanied by a _slim version. The following shows both versions of Vlandian crossbow_armor with the slim version on the right:
_bPTs.jpg
Only the wrists are slimmed to avoid clipping between armour sleeves and a gauntlet's forearm guards. The next image shows both armours again with crossbow_armor_hand added:
YOAV7.jpg
No prizes for guessing, which one's the _slim version. This slimming approach to gloves explains the high break point between the underlying body's hand/wrist component and torso/arm component.:
Z3iT-.jpg

4. Scales
vlandia_leather_scale_armour has two components an underlying armour (3,814 polys) and a collection of planes for the scales (2,186 polys) using an alpha material (vlandia_leather_scale_armor_alpha). The following image is only the mesh for the alpha material:
BsBKd.jpg

5. Ears
The Bannerlord head has big ears that stick out:
f42j8.jpg
I had hoped that some clever code flattened them against the skull or removed them (like the flag that removes hair to avoid helmet clipping), allowing slimmer helmets. Unfortunately, it appears that helmet meshes must be wide enough to engulf and hide them:
He8Qc.jpg
Um0tO.jpg
This matters little for Bannerlord where helmets all seem to ride above the ears with hair or coifs covering them. However, for later medieval plate helmets this will force a fatter and uglier mesh than I'd hoped. IMO some full conversion modder will need to pin back those ears.



I'll add more insights as I come across them and would appreciate contributed insights to pool our knowledge.
 
Last edited:
Interesting analysis so far but I can't say I've explored any of the models myself. Feminization of armors reminds me of the body sliders from Skyrim and it definitely looks like head, hand, and foot dismemberment will be possible with this setup. Pinning the ears is easy to control with shape keys. I guess there was no need for it like you pointed out. I imagine a modder could include ear pinning in some sort of API for other modders.
 
To add to some of that, here's some stuff that developer gkx said on the discord:

> The preferred way to create materials is using metallic workflow. Standard shader for it named "pbr_metallic" in game. It uses Lambertian Diffuse and GGX Specular. The texture maps for that Albedo(RGB/A), NormalMap, Metallic(R)+Gloss(G)+AmbientOcclusion(B), also there is optional tiling DetailNormalmap, and Heightmap for POM/Tesselation. There is special shaders and BRDFs for different material types, for example: For floras we support transclucency and subsurface scattering driven by transclucency map packed into A channel of metal/gloss/ao texture. For hair we are using Kaija-Kay two-lobed specular. For skin we are using Kelemen/Szirmay-Kalos specular with SpecularIntensity(R)/Gloss(G)/AO(B) map and with a screen space subsurface scattering method correctly applying to only diffuse lighting. For horses, we are using anisotropic GGX with two lobes driven with a flow map.

> you shouldnt use alpha if it possible for performance reasons

> yes you can make helmets with alpha testing, but its not matter its a tiny area or not, if you add alpha all helmet will be drawn with no early depth stencil test, so if our helmets has a fur etc we are seperating it to 2 materials one with alpha one with not.
 
To add to some of that, here's some stuff that developer gkx said on the discord:
Thanks for that reminder, I’d spotted the use of different materials for alphas but had forgotten gkx’s comments that separation was necessary for optimisation. :smile:

BTW for anyone curious about the gtex file format and the use of tilesets for texturing, you may want to look at these tutorial videos about using Granite SKD 5.0 with the Unreal engine: https://graphinesoftware.com/granite-unreal-video-tutorials Hopefully, TW and Graphine will supply a similar batch texture converter with Bannerlord’s modding tools. Unless I’m mistaken, I think we’ll have to compile all a mod’s textures into a new tile set every time we change a single texture. However, I may be wrong, not having used Graphine’s system with either Unreal or Unity. EDIT: I am wrong. There is another xml file called BannerlordIgnoredResouceFiles.xml right next to Granite.xml. This appears to list all of the textures, which aren't to be reloaded when running the Granite.xml tileset loader. Presumably, we just comment out the texture that changes and run the import.

Just for clarification, not all textures are streamed in tilesets for live action optimisation. The assetpackages include ordinary uncompiled textures for UIs and some static props etc. All the armour textures appear to be optimised into gtex tilesets.
 
Last edited:
For anyone interested in textures, take a look at Granite.xml which can be found in C:\Program Files (x86)\Steam\steamapps\common\Mount & Blade II Bannerlord\Modules\Native\TileSets. It appears to be the texture importer for gtex tilesets. Surprisingly for PBR materials it's still only loading in diffuse, normal and specular textures. The naming convention uses a _d, _n and _s suffix respectively. The _d suffix is not always used, suggesting diffuse is the default (assumed in the absence of _n or _s). EDIT - Kentucky James is probably correct that the texture labelled specular is probably an RGB channel stack of Metallic (Red channel), Gloss (Green channel), and Ambient Occlusion (Blue Channel).
Presumably as gtex is handling optimisation the textures loaded aren't forced to be dds files. A lot of textures were in .psd, .tif and .tga as well as .dds formats. Another surprise for me was the number of 4K textures in use. Mainly for walls, floors or atlases but bizarrely khuzait_lamellar_strap uses a 4K texture. Whereas the khuzait_lord_helmet_a merely gets 512x512 textures. How is a strap more important than a whole helmet? Must be the entire lamellar armour, not just a strap, despite its name.
Bark textures are 1K wide and 4K high, which seems logical for tall trees. Amusingly, every female head with one exception gets 4K textures while all male heads are 2k. :smile:

EDIT: The Granite.xml importer loads the original textures from a SourceAssets subfolder of Native, but that folder and its texture sub-folders haven't been released by TW in our EA files. TW need to release this texture library to allow modders to tweak native textures or we will be forced to retexture entire native armours from scratch in Substance Painter.

EDIT2: The sandbox module also has its own tileset sub-folder, which suggests modders can have their own tileset sub-folders similar to mod Resources vs CommonRes in Warband. Presumably, a later loaded mod Tileset will over-write any earlier loaded Native gtex file with the same 19 digit ID. That would still require a mod to import all the textures of a Native material even if only say the diffuse was changed as they are all compiled under the same ID.
 
Last edited:
I would assume that the _s is just metallic, gloss and AO packed into one texture. Storing the specular as a texture is actually a bit pointless since most objects look perfectly fine with a single value for the whole thing.
That makes infinitely more sense than my speculation even though the file header says:
Code:
<AssetImport>
    <LayerConfig>
        <LayerDescription Name="diffuse" CompressionFormat="BC3" QualityProfile="Default" DataType="R8G8B8A8_LINEAR" DefaultColor="#FFFFFFFF"/>
        <LayerDescription Name="normal" CompressionFormat="BC5" QualityProfile="Default" DataType="X8Y8Z0_TANGENT" DefaultColor="#7F7FFFFF"/>
        <LayerDescription Name="specular" CompressionFormat="BC1" QualityProfile="Default" DataType="R8G8B8_LINEAR" DefaultColor="#0000FFFF"/>
    </LayerConfig>

BTW do you know where the mesh cave_a is used in Bannerlord? I thought TW didn't do caves.
lJqps.jpg
Ym-yt.jpg

Outermeshes to give scenes natural horizons have come a long way since Warband. Outermesh mountains comprises 17 parts (coloured to highlight them) with a total of 32,139 polys:
rL2n8.jpg
I presume the battle scene where all the action takes place just occupies the green centre's inner four chequers.
 
Last edited:
Success! I've finally managed to export a rigged BL mesh into Blender using TpacTool:
X7QoJ.jpg
4Pqdz.jpg
The model needs to be exported as a Collada .dae file. However, we can't import it into Blender without errors because Blender can't find the associated textures etc.
The Collada file needs to be manually edited to remove these references as described in this video. We need to manually edit the Collada .dae file to remove everything between these three tag sets while retaining the tags:
Code:
<library_images>
  </library_images>
  <library_effects>
  
  </library_effects>
  <library_materials>
  
  </library_materials>
Then the geometry can be loaded despite our missing images, effects and materials. EDIT: This is no longer necessary since @szszss upgraded TpacTool 0.2.0 [Fixed a Collada (.dae) exporting bug which caused the exported model cannot be imported by Blender 2.83+]
NRsPX.jpg
Weight painting of bone rigging for armor_roman_military_tunic ignoring right side bones and those without influence (head, feet, fingers and toes):
okxP9.jpg
 
Last edited:
Another surprise for me was the number of 4K textures in use. Mainly for walls, floors or atlases but bizarrely khuzait_lamellar_strap uses a 4K texture. Whereas the khuzait_lord_helmet_a merely gets 512x512 textures. How is a strap more important than a whole helmet? Must be the entire lamellar armour, not just a strap, despite its name.

This is quite interesting...
Do you know what's the standard size of a textures used for armours?
2k, I presume? Or 1k but with bits and bobs from other textures as well?
 
This is quite interesting...
Do you know what's the standard size of a textures used for armours?
2k, I presume? Or 1k but with bits and bobs from other textures as well?
Armour textures are held in inaccessible files. However, TpacTool while it can’t open them identifies their names, resolutions etc. Looking at stats for invisible textures is slightly dispiriting, so I haven’t checked enough examples to give you a reliable average. 2k is what TW advised and that seems reasonable.

xgsvn.jpg
 
Last edited:
One more question.
Have you managed to find this armour somewhere among the assets?

I've been looking for it for a while now but I can't seem to find it anywhere.
 
One more question.
Have you managed to find this armour somewhere among the assets?

I've been looking for it for a while now but I can't seem to find it anywhere.
It's spread through various files as follows:
meshes_shared_0.tpac includes hallow_armor_converted_slim
meshes_shared_1.tpac includes hallow_armor_slim & hideous_armor
meshes_shared_3.tpac includes hideous_kafa
meshes_shared_4.tpac includes hallow_armor_shoulder
meshes_shared_5.tpac includes hallow_armor_converted & pistol_crossbow_b
meshes_shared_6.tpac includes pistol_crossbow_a
meshes_shared_7.tpac includes hallow_armor_guantlets
shared_meshes_8.tpac includes hallow_armor & heater_shield_a
shared_meshes_9.tpac includes hallow_armor_helmet

Presumably the pistol_crossbows are a humourous nod to the pistol easter egg in Warband and the use of crossbow animations for firearms in WFaS. :smile:
PS the meshes_shared tpacs also include some of the old warband player/Lord world map icons, which must have been used in the early days of testing.
 
Last edited:
Thanks! :grin:

Also if someone else ends up looking for it in TpackTools it's way easier to find it by switching from package sorting to the alphabetical list sorting by clicking "Group by package" folder icon in the bottom left corner of the window. I wasn't aware of this feature before.
 
I know little about textures, but while exploring the game's DLLs I found several functions related to importing/exprorting textures in a Texture class:

C#:
Texture GetFromResource(string resourceName)
TransformRenderTargetToResource(string name)
Texture CreateTextureFromPath(string path, string fileName)
Texture LoadTextureFromPath(string fileName, string folder)
SaveToFile(string path)

There's also a Material class with functions to get and set textures and shaders and such.

It may be a long shot, but since the main obstacle to texture mods right now is the inability to decode gtex files, maybe it is possible to let the engine do the work for us by using Texture.SaveToFile(string path) on a texture that originates from a gtex file, saving it to DDS or something like that.

Edit: I just tried this but SaveToFile only produced files with what appears to be a PNG header but no data.
 
Last edited:
I know little about textures, but while exploring the game's DLLs I found several functions related to importing/exprorting textures in a Texture class:

C#:
Texture GetFromResource(string resourceName)
TransformRenderTargetToResource(string name)
Texture CreateTextureFromPath(string path, string fileName)
Texture LoadTextureFromPath(string fileName, string folder)
SaveToFile(string path)

There's also a Material class with functions to get and set textures and shaders and such.

It may be a long shot, but since the main obstacle to texture mods right now is the inability to decode gtex files, maybe it is possible to let the engine do the work for us by using Texture.SaveToFile(string path) on a texture that originates from a gtex file, saving it to DDS or something like that.

Edit: I just tried this but SaveToFile only produced files with what appears to be a PNG header but no data.
Thanks for trying. Looks like we just have to wait. :smile:
 
Back
Top Bottom