korman icon indicating copy to clipboard operation
korman copied to clipboard

Armatures and skinned objects

Open Jrius opened this issue 11 months ago • 1 comments

Alright, this is a big one. I probably won't have a lot of time to implement suggestions until the RAD is over, so feel free to take your time reviewing. I also didn't check how optimized the code is (especially regarding Python generators), suggestions are welcome.

The first thing that needs to be mentioned: I decided to let Korman generate a LOT of temporary Blender objects during export. This may feel messy, but I've rewritten the code several times and AFAICT is still the best solution. Temporary objects should all get cleaned up nicely whatever happens.

Second, there are still two small problems, that I'll get around to later:

  • Warning messages about "Animation generated no applicators" - harmless.
  • Exported skinned objects don't automatically get runtime lighting. This can be forced using a Lighting Info modifier, but it might be worth making it automatic just like other animated objects.

Armatures

  • Armature objects are exported as regular SceneObjects.
  • Each bone of the armature is exported as two (!) new SceneObjects. Bone hierarchy is respected.
  • The two SceneObjects are: the rest position of the bone, and the actual deform bone. For instance, the following bone hierarchy:
    • Armature:
      • Bone1
        • Bone2
      • Bone3
  • ...Will be exported as:
    • Armature:
      • Bone1_REST
        • Bone1
          • Bone2_REST
            • Bone2
      • Bone3_REST
        • Bone3
  • Exporting two SceneObjects per bone avoids a whole slew of problems when exporting animations. Otherwise we'd be running in the same problem as an object having a matrix_parent_inverse.
  • For various reasons, those two bone objects are actually temporary Blender Empty objects that are created at export-time. (I rewrote this several times, but in the end this felt like the best solution.) (On cleanup: those empties are deleted.)

Animations

  • Armatures with an Animation modifier automatically get their Animation Group modifier toggled on during export. (On cleanup: modifier gets re-disabled if necessary.)
  • Animated bones generate two Empty objects as previously mentioned - one of those empties gets to be animated:
    • The bone's animations are copied to a temporary Action assigned to the empty object. (Cleanup: the Action is deleted.)
    • An Animation modifier that matches the armature's own is added to the empty object. This Animation modifier is referenced in the armature's own Animation Group modifier. (On cleanup: the reference is removed.)
  • This means one can easily play specific armature animations from nodes/responders, as Korman will reroute those messages to the armature's Animation Group / plMsgForwarder.
  • Note that just like Cyan, we generate one plATCAnim per bone, per animation. Ideally we would group all bones in a single plATCAnim, but in my tests this doesn't work - seems it's only available to special objects like avatars.
  • Animation modifiers now have two extra properties to bake animations.
    • Baking is required to get bone inverse kinematic (IK) to export.
    • It also helps fix some occasional animations issues: wrong tangents, missing keyframes on armature bones, etc. For this reason, it's also available to regular animations.
    • Baking is neither a silver bullet (can worsen animations), nor cheap (takes a long time to compute), so it is disabled by default. It's up to the user to know when to enable it.

Rigged/deformed meshes

  • If the armature itself is not exported, the modifier/pose will be baked in the mesh and no expensive runtime deformation happens. (This is useful to make variations of the same mesh. For instance: trees with different branch shapes and sizes.)
  • Otherwise, the armature modifier is disabled (so it doesn't get baked into the mesh), and weight/indices are exported in the mesh's vertices. (On cleanup: modifier is reenabled.)
    • Vertices that are not deformed by any bone get assigned to a special "null" bone that never moves. This is very commonly used in Kemo for trees, since their roots don't move.
    • If possible, less than 3 skin indices will be used per vertex for better performances.
  • When generating the Drawable Spans from the collection of Geometry Spans, a few things need to happen.
    • Bone transforms get added to the DSpan, and bones get a Draw Interface referencing said bone.
    • Icicles get adjusted matrix indices so they know which bones they are using.
  • Worth noting that Blender objects can have multiple Armature modifiers. This is accepted by Korman, but results are completely untested.
  • Rigged meshes do NOT get a CoordinateInterface, ever. Since people usually parent the rigged mesh to the armature itself, Korman will simply ignore that relationship on export.
    • The reason for this is armature sharing. Armatures can be shared between rigs in Blender, but the way DrawableSpans work, this would require duplicating the bones for each object, so screw that.
    • There is rarely a good reason for the object to have its own coordinate system since it's supposed to move with the armature anyway... (except maybe floating-point precision ?)

Other

  • Regular (non deformable) objects can now be parented to armature bones. This provides an easy way to use IK for machines and the like, without the overhead of deforming the vertices.

Backwards compatibility: completely new feature so no problem expected unless I messed up. It does fix a bug with TemporaryCollectionItem though.

And here is a test file so you can see it in action.

Jrius avatar Feb 08 '25 16:02 Jrius

Thanks for the extensive feedback ! Yeah, the priority was to make the PR before the start of the contest, I expected a lot would require improvements. I'll clean this all up once the contest is out of the way...

Jrius avatar Feb 24 '25 17:02 Jrius