def import_material_uv_controller(self, b_material, n_geom): """Import UV controller data.""" # search for the block n_ctrl = nif_utils.find_controller(n_geom, NifFormat.NiUVController) if not (n_ctrl and n_ctrl.data): return NifLog.info("Importing UV controller") b_mat_action = self.nif_import.animationhelper.create_action( b_material, "MaterialAction") dtypes = ("offset", 0), ("offset", 1), ("scale", 0), ("scale", 1) for n_uvgroup, (data_path, array_ind) in zip(n_ctrl.data.uv_groups, dtypes): if n_uvgroup.keys: interp = self.nif_import.animationhelper.get_b_interp_from_n_interp( n_uvgroup.interpolation) #in blender, UV offset is stored per texture slot #so we have to repeat the import for each used tex slot for i, texture_slot in enumerate(b_material.texture_slots): if texture_slot: fcurves = create_fcurves( b_mat_action, "texture_slots[" + str(i) + "]." + data_path, (array_ind, )) for key in n_uvgroup.keys: if "offset" in data_path: self.nif_import.animationhelper.add_key( fcurves, key.time, (-key.value, ), interp) else: self.nif_import.animationhelper.add_key( fcurves, key.time, (key.value, ), interp) self.nif_import.animationhelper.set_extrapolation( n_ctrl.flags, fcurves)
def import_bone_animation(self, n_block, b_armature_obj, bone_name): """ Imports an animation contained in the NIF itself. """ if NifOp.props.animation: NifLog.debug('Importing animation for bone %s'.format(bone_name)) bone_bm = nif_utils.import_matrix(n_block) # base pose niBone_bind_scale, niBone_bind_rot, niBone_bind_trans = nif_utils.decompose_srt( bone_bm) niBone_bind_rot_inv = niBone_bind_rot.to_4x4().inverted() kfc = nif_utils.find_controller(n_block, NifFormat.NiKeyframeController) self.import_keyframe_controller(kfc, b_armature_obj, bone_name, niBone_bind_scale, niBone_bind_rot_inv, niBone_bind_trans)
def import_object_vis_controller(self, n_node, b_obj): """Import vis controller for blender object.""" n_vis_ctrl = nif_utils.find_controller(n_node, NifFormat.NiVisController) if not (n_vis_ctrl and n_vis_ctrl.data): return NifLog.info("Importing vis controller") b_obj_action = self.nif_import.animationhelper.create_action( b_obj, b_obj.name + "-Anim") fcurves = create_fcurves(b_obj_action, "hide", (0, )) for key in n_vis_ctrl.data.keys: self.nif_import.animationhelper.add_key(fcurves, key.time, (key.value, ), "CONSTANT") #get extrapolation from flags and set it to fcurves self.nif_import.animationhelper.set_extrapolation( n_vis_ctrl.flags, fcurves)
def import_material_alpha_controller(self, b_material, n_geom): # find alpha controller n_matprop = nif_utils.find_property(n_geom, NifFormat.NiMaterialProperty) if not n_matprop: return n_alphactrl = nif_utils.find_controller(n_matprop, NifFormat.NiAlphaController) if not (n_alphactrl and n_alphactrl.data): return NifLog.info("Importing alpha controller") b_mat_action = self.nif_import.animationhelper.create_action( b_material, "MaterialAction") fcurves = create_fcurves(b_mat_action, "alpha", (0, )) interp = self.nif_import.animationhelper.get_b_interp_from_n_interp( n_alphactrl.data.data.interpolation) self.nif_import.animationhelper.set_extrapolation( n_alphactrl.flags, fcurves) for key in n_alphactrl.data.data.keys: self.nif_import.animationhelper.add_key(fcurves, key.time, (key.value, ), interp)
def import_mesh_controllers(self, n_node, b_obj): """Import mesh controller for blender object.""" morphCtrl = nif_utils.find_controller( n_node, NifFormat.NiGeomMorpherController) if morphCtrl: b_mesh = b_obj.data morphData = morphCtrl.data if morphData.num_morphs: fps = bpy.context.scene.render.fps # insert base key at frame 1, using relative keys b_mesh.insertKey(1, 'relative') # get name for base key keyname = morphData.morphs[0].frame_name if not keyname: keyname = 'Base' # set name for base key b_mesh.key.blocks[0].name = keyname # get base vectors and import all morphs baseverts = morphData.morphs[0].vectors b_ipo = Blender.Ipo.New('Key', 'KeyIpo') b_mesh.key.ipo = b_ipo for idxMorph in range(1, morphData.num_morphs): # get name for key keyname = morphData.morphs[idxMorph].frame_name if not keyname: keyname = 'Key %i' % idxMorph NifLog.info("Inserting key '{0}'".format(keyname)) # get vectors morphverts = morphData.morphs[idxMorph].vectors # for each vertex calculate the key position from base # pos + delta offset assert (len(baseverts) == len(morphverts) == len(v_map)) for bv, mv, b_v_index in zip(baseverts, morphverts, v_map): base = mathutils.Vector(bv.x, bv.y, bv.z) delta = mathutils.Vector(mv.x, mv.y, mv.z) v = base + delta if applytransform: v *= transform b_mesh.vertices[b_v_index].co[0] = v.x b_mesh.vertices[b_v_index].co[1] = v.y b_mesh.vertices[b_v_index].co[2] = v.z # update the mesh and insert key b_mesh.insertKey(idxMorph, 'relative') # set name for key b_mesh.key.blocks[idxMorph].name = keyname # set up the ipo key curve try: b_curve = b_ipo.addCurve(keyname) except ValueError: # this happens when two keys have the same name # an instance of this is in fallout 3 # meshes/characters/_male/skeleton.nif HeadAnims:0 NifLog.warn( "Skipped duplicate of key '{0}'".format(keyname)) # no idea how to set up the bezier triples -> switching # to linear instead b_curve.interpolation = Blender.IpoCurve.InterpTypes.LINEAR # select extrapolation b_curve.extend = self.get_extend_from_flags( morphCtrl.flags) # set up the curve's control points # first find the keys # older versions store keys in the morphData morphkeys = morphData.morphs[idxMorph].keys # newer versions store keys in the controller if (not morphkeys) and morphCtrl.interpolators: morphkeys = morphCtrl.interpolators[ idxMorph].data.data.keys for key in morphkeys: x = key.value frame = 1 + int(key.time * fps + 0.5) b_curve.addBezier((frame, x)) # finally: return to base position for bv, b_v_index in zip(baseverts, v_map): base = mathutils.Vector(bv.x, bv.y, bv.z) if applytransform: base *= transform b_mesh.vertices[b_v_index].co[0] = base.x b_mesh.vertices[b_v_index].co[1] = base.y b_mesh.vertices[b_v_index].co[2] = base.z
def import_object_animation(self, niBlock, b_obj): """ Load animation attached to (Scene Root) object. Becomes the object level animation of the object. """ # TODO: remove code duplication with import_keyframe_controller kfc = nif_utils.find_controller(niBlock, NifFormat.NiKeyframeController) if not kfc: # no animation data: do nothing return if kfc.interpolator: if isinstance(kfc.interpolator, NifFormat.NiBSplineInterpolator): kfd = None # not supported yet so avoids fatal error - should be kfc.interpolator.spline_data when spline data is figured out. else: kfd = kfc.interpolator.data else: kfd = kfc.data if not kfd: # no animation data: do nothing return # denote progress NifLog.info("Animation") NifLog.info("Importing animation data for {0}".format(b_obj.name)) assert (isinstance(kfd, NifFormat.NiKeyframeData)) #get the interpolation modes interp_rot = get_interp_mode(kfd) interp_loc = get_interp_mode(kfd.translations) interp_scale = get_interp_mode(kfd.scales) b_obj_action = self.create_action(b_obj, b_obj.name + "-Anim") if kfd.scales.keys: NifLog.debug('Scale keys...') fcurves = create_fcurves(b_obj_action, "scale", range(3)) for key in kfd.scales.keys: v = (key.value, key.value, key.value) self.add_key(fcurves, key.time, v, interp_scale) # detect the type of rotation keys if kfd.rotation_type == 4: NifLog.debug('Rotation keys...(eulers)') b_obj.rotation_mode = "XYZ" #Eulers are a bit different here, we can import them regardless of their timing #because they need no correction math in object space fcurves = create_fcurves(b_obj_action, "rotation_euler", range(3)) keys = (kfd.xyz_rotations[0].keys, kfd.xyz_rotations[1].keys, kfd.xyz_rotations[2].keys) for fcu, keys_dim in zip(fcurves, keys): for key in keys_dim: self.add_key((fcu, ), key.time, (key.value, ), interp_rot) # uses quaternions elif kfd.quaternion_keys: NifLog.debug('Rotation keys...(quaternions)') b_obj.rotation_mode = "QUATERNION" fcurves = create_fcurves(b_obj_action, "rotation_quaternion", range(4)) for key in kfd.quaternion_keys: v = (key.value.w, key.value.x, key.value.y, key.value.z) self.add_key(fcurves, key.time, v, interp_rot) if kfd.translations.keys: NifLog.debug('Translation keys...') fcurves = create_fcurves(b_obj_action, "location", range(3)) for key in kfd.translations.keys: v = (key.value.x, key.value.y, key.value.z) self.add_key(fcurves, key.time, v, interp_rot)