Skip to content

Commit

Permalink
Added export of Blender pose.
Browse files Browse the repository at this point in the history
  • Loading branch information
Candoran2 committed Nov 2, 2021
1 parent 497a900 commit 721ad3b
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 14 deletions.
18 changes: 13 additions & 5 deletions io_scene_niftools/modules/nif_export/armature/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from io_scene_niftools.utils import math
from io_scene_niftools.utils.singleton import NifOp
from io_scene_niftools.utils.logging import NifLog
from pyffi.formats.nif import NifFormat


def get_bind_data(b_armature):
Expand All @@ -68,11 +69,14 @@ def export_bones(self, b_obj, n_root_node):
self.b_action = self.transform_anim.get_active_action(b_obj)
# the armature b_obj was already exported as a NiNode ("Scene Root") n_root_node
# export the bones as NiNodes, starting from root bones
old_position = b_obj.data.pose_position
b_obj.data.pose_position = 'POSE'
for b_bone in b_obj.data.bones.values():
if not b_bone.parent:
self.export_bone(b_obj, b_bone, n_root_node)
self.export_bone(b_obj, b_bone, n_root_node, n_root_node)
b_obj.data.pose_position = old_position

def export_bone(self, b_obj, b_bone, n_parent_node):
def export_bone(self, b_obj, b_bone, n_parent_node, n_root_node):
"""Exports a bone and all of its children."""
# create a new nif block for this b_bone
n_node = types.create_ninode(b_bone)
Expand All @@ -81,14 +85,18 @@ def export_bone(self, b_obj, b_bone, n_parent_node):
n_parent_node.add_child(n_node)

self.export_bone_flags(b_bone, n_node)
# rest pose
math.set_object_matrix(b_bone, n_node)
# set the pose on the nodes
nif_matrix = NifFormat.Matrix44()
nif_matrix.set_rows(*math.blender_bind_to_nif_bind(b_obj.pose.bones[b_bone.name].matrix).transposed())
# make the transform relative to the parent, rather than the armature
nif_matrix *= n_parent_node.get_transform(n_root_node).get_inverse(fast=False)
n_node.set_transform(nif_matrix)

# per-bone animation
self.transform_anim.export_transforms(n_node, b_obj, self.b_action, b_bone)
# continue down the bone tree
for b_child in b_bone.children:
self.export_bone(b_obj, b_child, n_node)
self.export_bone(b_obj, b_child, n_node, n_root_node)

def export_bone_flags(self, b_bone, n_node):
"""Exports or sets the flags according to the custom data in b_bone or the game version if none was set"""
Expand Down
27 changes: 18 additions & 9 deletions io_scene_niftools/modules/nif_export/geometry/mesh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ def export_tri_shapes(self, b_obj, n_parent, n_root, trishape_name=None):
# update bind position skinning data
# trishape.update_bind_position()
# override pyffi trishape.update_bind_position with custom one that is relative to the nif root
self.update_bind_position(trishape, n_root)
self.update_bind_position(trishape, n_root, b_obj_armature)

# calculate center and radius for each skin bone data block
trishape.update_skin_center_radius()
Expand Down Expand Up @@ -501,12 +501,12 @@ def export_tri_shapes(self, b_obj, n_parent, n_root, trishape_name=None):
self.morph_anim.export_morph(b_mesh, trishape, vertex_map)
return trishape

def update_bind_position(self, n_geom, n_root):
"""Make current position of the bones the bind position for this geometry.
def update_bind_position(self, n_geom, n_root, b_obj_armature):
"""Transfer the Blender bind position to the nif bind position.
Sets the NiSkinData overall transform to the inverse of the geometry transform
relative to the skeleton root, and sets the NiSkinData of each bone to
the geometry transform relative to the skeleton root times the inverse of the bone
transform relative to the skeleton root."""
the inverse of the transpose of the bone transform relative to the skeleton root, corrected
for the overall transform."""
if not n_geom.is_skin():
return

Expand All @@ -516,23 +516,32 @@ def update_bind_position(self, n_geom, n_root):
skindata = skininst.data
skelroot = skininst.skeleton_root

# calculate overall offset
geomtransform = n_geom.get_transform(skelroot)
skindata.set_transform(geomtransform.get_inverse())
# calculate overall offset (including the skeleton root transform) and use its inverse
geomtransform = (n_geom.get_transform(skelroot) * skelroot.get_transform()).get_inverse(fast=False)
skindata.set_transform(geomtransform)

# for some nifs, somehow n_root is not set properly?!
if not n_root:
NifLog.warn(f"n_root was not set, bug")
n_root = skelroot

old_position = b_obj_armature.data.pose_position
b_obj_armature.data.pose_position = 'POSE'

# calculate bone offsets
for i, bone in enumerate(skininst.bones):
bone_name = block_store.block_to_obj[bone].name
pose_bone = b_obj_armature.pose.bones[bone_name]
n_bind = NifFormat.Matrix44()
n_bind.set_rows(*math.blender_bind_to_nif_bind(pose_bone.matrix).transposed())
# todo [armature] figure out the correct transform that works universally
# inverse skin bind in nif armature space, relative to root / geom??
skindata.bone_list[i].set_transform(geomtransform * bone.get_transform(n_root).get_inverse())
skindata.bone_list[i].set_transform((n_bind * geomtransform).get_inverse(fast=False))
# this seems to be correct for skyrim heads, but breaks stuff like ZT2 elephant
# skindata.bone_list[i].set_transform(bone.get_transform(n_root).get_inverse())

b_obj_armature.data.pose_position = old_position

def get_bone_block(self, b_bone):
"""For a blender bone, return the corresponding nif node from the blocks that have already been exported"""
for n_block, b_obj in block_store.block_to_obj.items():
Expand Down
4 changes: 4 additions & 0 deletions io_scene_niftools/utils/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ def get_bind_matrix(bone):
return bind


def blender_bind_to_nif_bind(blender_armature_space_matrix):
return blender_armature_space_matrix @ correction


def nif_bind_to_blender_bind(nif_armature_space_matrix):
return nif_armature_space_matrix @ correction_inv

Expand Down

0 comments on commit 721ad3b

Please sign in to comment.