Open hansmbakker opened 5 years ago
I debugged the code; it turns out that LSLib correctly reads the skeleton properties, but
ExportSkeleton(...)
Also, when forcing to call ExportSkeleton(...)
by changing https://github.com/Norbyte/lslib/blob/aa7be33f6d5ef111c712d67a3d21ee5cd2e42b2c/LSLib/Granny/Model/ColladaExporter.cs#L460 to
if (model.Skeleton != null)
it turns out that desc.HasBoneWeights
is false
at https://github.com/Norbyte/lslib/blob/aa7be33f6d5ef111c712d67a3d21ee5cd2e42b2c/LSLib/Granny/Model/Mesh.cs#L636
This prevents the skeletons / bones to be exported. I'm not sure though why the BoneWeights are not found correctly; in GrannyViewer the model and animations work correctly.
Could you provide any guidance here?
I found https://github.com/Norbyte/lslib/issues/13 and https://github.com/Norbyte/lslib/issues/15. You mention that older Granny files are not supported.
The GR2 version that Anno1404 uses shows as 7
in the header
property (this sounds like it is the same as Divinity?) and lists Granny Standard Exporter, SDK version 2.8.12.0
as exporter info.
Can you provide a copy of the mesh and model GR2? There are many possibilities for what goes wrong. It is quite hard to tell without a sample, because most games customize their GR2 format in some way. Some use special vertex attribute formats, some skip encoding the skeleton entirely in animation files, etc.
@Norbyte (files removed for copyright reasons)
I've checked the mesh and animations.
a) n_repair_crane_goods_lod0.gr2: This file contains 5 different meshes with 5 different skeletons; all of these skeletons have one single bone with the same name as the model & skeleton. Although the meshes have bone bindings, the vertices themselves are not skinned, i.e. they don't carry bone indices or weights in the vertex data. Because of this, the skeletons are marked as 'dummy' and are not exported.
I find this quite strange, as the usual way these animations are done is by creating a single-part or multipart mesh, binding all submeshes to different bones of the same skeleton and adding a dummy root bone or multiple separate roots.
Nevertheless, a quick workaround would be suppressing the dummy skeleton checks for your model, i.e. keeping the change you mentioned in ExportSkeleton
(i.e. if (model.Skeleton != null)
), and forcing the exporter to emit a skin and mesh binding, i.e. changing the line at https://github.com/Norbyte/lslib/blob/master/LSLib/Granny/Model/ColladaExporter.cs#L260 to bool hasSkin = skelRef != null;
.
b) repair_crane_work01.gr2: This contains animations for both mesh files. The bone data was stripped from the gr2 file, so exporting the animation itself to Collada will not result in a useful result, as no importer tool will be able to associate the animation frames with the bones they should be animating. (Blender will just say removed 96 unused curves
and discard the entire animation).
You could copy&paste the library_animations
and library_animation_clips
nodes from the animation Collada, and paste it into the export of n_repair_crane_goods_lod0.gr2
; this way it'll be able to bind on import.
Another issue is the lack of bone weights. Because there are none, the animation will show up in Blender, but it'll just animate the bones, the vertices themselves won't be moving because there is no association between bones and vertices. One thing that can be done here is forcing each bone to have an 1.0 influence from the parent bone. i.e.: add this before https://github.com/Norbyte/lslib/blob/master/LSLib/Granny/Model/ColladaExporter.cs#L260
meshBinding.Mesh.VertexFormat.HasBoneWeights = true;
var skinnedVerts = meshBinding.Mesh.PrimaryVertexData.Deduplicator.Vertices.Uniques;
for (var i = 0; i < skinnedVerts.Count; i++)
{
var v = skinnedVerts[i];
v.Indices.A = 0;
v.Weights.A = 0xff;
skinnedVerts[i] = v;
}
That's great, thank you for looking into this! I'll try it!
I tried it, but it didn't seem to work - in 3ds max the Skin modifier is shown when importing the resulting dae file, but the animation doesn't seem to have effect on the bones?
Strange indeed that they modelled/ exported it this way.
It turns out that for characters (people as opposed to objects), there are Bone Indices included in the vertices, but not Bone Weights.
Also the bone index field has uint32
in the granny file rather than uint8
which LSLib expects. I suppose this requires the VertexStructure
to be modified for it not to load the wrong data?
I'm wondering how Granny handles this itself, since in grannyviewer all looks fine..
I haven't seen uint32
bone indices before, usually there is a bone index array of N elements, and a bone weights array of N elements. I think this may be an older version of the GR2 format where bone weights were not yet supported, and each vertex was bound to exactly one bone with a weight of 1.0.
Alternatively, it could be an optimization as the game doesn't need sophisticated models that bind vertices to multiple bones, and instead they padded the bone index to a multiple of 4. (GPUs generally don't handle data that is not 4 byte aligned data very well, so vertex buffers are usually padded to a multiple of 4 bytes).
A special case could be added to vertex processing that autofills the first element in BoneWeights
to 0xff
if there is no bone weight array, only a bone index array.
Granny supports quite a few vertex formats, I think the list of builtin formats is over 40-50, so they probably have a special case in their library for this.
Ok, thank you! I’ll look further into it.
I tried exporting some Anno1404 files using the converter. I added granny2.dll from the game. I used the master branch of lslib, updated today.
The animations and meshes are stored in separate .gr2 files.
Probably because the bones are not exported, the animation does not work when it is imported in 3ds max. Is there something I'm doing wrong? I can provide sample files upon request.