def import_geometry_object(self, b_armature, n_block): # it's a shape node and we're not importing skeleton only b_obj = self.create_mesh_object(n_block) b_obj.matrix_local = math.import_matrix( n_block) # set transform matrix for the mesh self.mesh.import_mesh(n_block, b_obj) bpy.context.view_layer.objects.active = b_obj # store flags etc self.import_object_flags(n_block, b_obj) # skinning? add armature modifier if n_block.skin_instance: self.append_armature_modifier(b_obj, b_armature) return b_obj
def import_transforms(self, n_block, b_obj, bone_name=None): """Loads an animation attached to a nif block.""" # find keyframe controller n_kfc = math.find_controller(n_block, NifFormat.NiKeyframeController) # try again if not n_kfc: n_kfc = math.find_controller(n_block, NifFormat.NiTransformController) if n_kfc: # skeletal animation if bone_name: bone_bm = math.import_matrix(n_block) # base pose n_bone_bind_scale, n_bone_bind_rot, n_bone_bind_trans = math.decompose_srt( bone_bm) self.import_keyframe_controller(n_kfc, b_obj, bone_name, n_bone_bind_scale, n_bone_bind_rot.inverted(), n_bone_bind_trans) # object-level animation else: self.create_action(b_obj, b_obj.name + "-Anim") self.import_keyframe_controller(n_kfc, b_obj)
def import_branch(self, n_block, b_armature=None, n_armature=None): """Read the content of the current NIF tree branch to Blender recursively. :param n_block: The nif block to import. :param b_armature: The blender armature for the current branch. :param n_armature: The corresponding nif block for the armature for the current branch. """ if not n_block: return None NifLog.info(f"Importing data for block '{n_block.name.decode()}'") if isinstance(n_block, NifFormat.NiTriBasedGeom ) and NifOp.props.process != "SKELETON_ONLY": return self.objecthelper.import_geometry_object( b_armature, n_block) elif isinstance(n_block, NifFormat.NiNode): # import object if self.armaturehelper.is_armature_root(n_block): # all bones in the tree are also imported by import_armature if NifOp.props.process != "GEOMETRY_ONLY": b_obj = self.armaturehelper.import_armature(n_block) else: n_name = block_store.import_name(n_block) b_obj = math.get_armature() NifLog.info( f"Merging nif tree '{n_name}' with armature '{b_obj.name}'" ) if n_name != b_obj.name: NifLog.warn( f"Using Nif block '{n_name}' as armature '{b_obj.name}' but names do not match" ) b_armature = b_obj n_armature = n_block elif self.armaturehelper.is_bone(n_block): # bones have already been imported during import_armature n_name = block_store.import_name(n_block) if n_name in b_armature.data.bones: b_obj = b_armature.data.bones[n_name] else: # this is a fallback for a weird bug, when a node is child of a NiLodNode in a skeletal nif b_obj = self.objecthelper.create_b_obj(n_block, None, name=n_name) b_obj.niftools.flags = n_block.flags else: # import as an empty b_obj = NiTypes.import_empty(n_block) # find children b_children = [] n_children = [child for child in n_block.children] for n_child in n_children: b_child = self.import_branch(n_child, b_armature=b_armature, n_armature=n_armature) if b_child and isinstance(b_child, bpy.types.Object): b_children.append(b_child) # import collision objects & bounding box if NifOp.props.process != "SKELETON_ONLY": b_children.extend(self.import_collision(n_block)) b_children.extend( self.boundhelper.import_bounding_box(n_block)) # set bind pose for children self.objecthelper.set_object_bind(b_obj, b_children, b_armature) # import extra node data, such as node type NiTypes.import_root_collision(n_block, b_obj) NiTypes.import_billboard(n_block, b_obj) NiTypes.import_range_lod_data(n_block, b_obj, b_children) # set object transform, this must be done after all children objects have been parented to b_obj if isinstance(b_obj, bpy.types.Object): # note: bones and this object's children already have their matrix set b_obj.matrix_local = math.import_matrix(n_block) # import object level animations (non-skeletal) if NifOp.props.animation: # self.animationhelper.import_text_keys(n_block) self.transform_anim.import_transforms(n_block, b_obj) self.object_anim.import_visibility(n_block, b_obj) return b_obj # all else is currently discarded return None