Skip to content
Snippets Groups Projects
Commit ec915346 authored by Candoran2's avatar Candoran2 Committed by neomonkeus
Browse files

Added export of Blender pose.

parent 50dc6cb0
No related branches found
No related tags found
No related merge requests found
...@@ -43,6 +43,7 @@ from io_scene_niftools.modules.nif_export.block_registry import block_store ...@@ -43,6 +43,7 @@ from io_scene_niftools.modules.nif_export.block_registry import block_store
from io_scene_niftools.utils import math from io_scene_niftools.utils import math
from io_scene_niftools.utils.singleton import NifOp from io_scene_niftools.utils.singleton import NifOp
from io_scene_niftools.utils.logging import NifLog from io_scene_niftools.utils.logging import NifLog
from pyffi.formats.nif import NifFormat
def get_bind_data(b_armature): def get_bind_data(b_armature):
...@@ -68,11 +69,14 @@ class Armature: ...@@ -68,11 +69,14 @@ class Armature:
self.b_action = self.transform_anim.get_active_action(b_obj) 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 # the armature b_obj was already exported as a NiNode ("Scene Root") n_root_node
# export the bones as NiNodes, starting from root bones # 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(): for b_bone in b_obj.data.bones.values():
if not b_bone.parent: 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.""" """Exports a bone and all of its children."""
# create a new nif block for this b_bone # create a new nif block for this b_bone
n_node = types.create_ninode(b_bone) n_node = types.create_ninode(b_bone)
...@@ -81,14 +85,18 @@ class Armature: ...@@ -81,14 +85,18 @@ class Armature:
n_parent_node.add_child(n_node) n_parent_node.add_child(n_node)
self.export_bone_flags(b_bone, n_node) self.export_bone_flags(b_bone, n_node)
# rest pose # set the pose on the nodes
math.set_object_matrix(b_bone, n_node) 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 # per-bone animation
self.transform_anim.export_transforms(n_node, b_obj, self.b_action, b_bone) self.transform_anim.export_transforms(n_node, b_obj, self.b_action, b_bone)
# continue down the bone tree # continue down the bone tree
for b_child in b_bone.children: 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): 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""" """Exports or sets the flags according to the custom data in b_bone or the game version if none was set"""
......
...@@ -453,7 +453,7 @@ class Mesh: ...@@ -453,7 +453,7 @@ class Mesh:
# update bind position skinning data # update bind position skinning data
# trishape.update_bind_position() # trishape.update_bind_position()
# override pyffi trishape.update_bind_position with custom one that is relative to the nif root # 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 # calculate center and radius for each skin bone data block
trishape.update_skin_center_radius() trishape.update_skin_center_radius()
...@@ -501,12 +501,12 @@ class Mesh: ...@@ -501,12 +501,12 @@ class Mesh:
self.morph_anim.export_morph(b_mesh, trishape, vertex_map) self.morph_anim.export_morph(b_mesh, trishape, vertex_map)
return trishape return trishape
def update_bind_position(self, n_geom, n_root): def update_bind_position(self, n_geom, n_root, b_obj_armature):
"""Make current position of the bones the bind position for this geometry. """Transfer the Blender bind position to the nif bind position.
Sets the NiSkinData overall transform to the inverse of the geometry transform 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 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 the inverse of the transpose of the bone transform relative to the skeleton root, corrected
transform relative to the skeleton root.""" for the overall transform."""
if not n_geom.is_skin(): if not n_geom.is_skin():
return return
...@@ -516,23 +516,32 @@ class Mesh: ...@@ -516,23 +516,32 @@ class Mesh:
skindata = skininst.data skindata = skininst.data
skelroot = skininst.skeleton_root skelroot = skininst.skeleton_root
# calculate overall offset # calculate overall offset (including the skeleton root transform) and use its inverse
geomtransform = n_geom.get_transform(skelroot) geomtransform = (n_geom.get_transform(skelroot) * skelroot.get_transform()).get_inverse(fast=False)
skindata.set_transform(geomtransform.get_inverse()) skindata.set_transform(geomtransform)
# for some nifs, somehow n_root is not set properly?! # for some nifs, somehow n_root is not set properly?!
if not n_root: if not n_root:
NifLog.warn(f"n_root was not set, bug") NifLog.warn(f"n_root was not set, bug")
n_root = skelroot n_root = skelroot
old_position = b_obj_armature.data.pose_position
b_obj_armature.data.pose_position = 'POSE'
# calculate bone offsets # calculate bone offsets
for i, bone in enumerate(skininst.bones): 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 # todo [armature] figure out the correct transform that works universally
# inverse skin bind in nif armature space, relative to root / geom?? # 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 # 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()) # 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): 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 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(): for n_block, b_obj in block_store.block_to_obj.items():
......
...@@ -89,6 +89,10 @@ def get_bind_matrix(bone): ...@@ -89,6 +89,10 @@ def get_bind_matrix(bone):
return bind 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): def nif_bind_to_blender_bind(nif_armature_space_matrix):
return nif_armature_space_matrix @ correction_inv return nif_armature_space_matrix @ correction_inv
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment