def obj_orientation(obj, alpha, beta, gamma): '''Set obj orientation, angle in degrees''' alpha = alpha * pi / 180 beta = beta * pi / 180 gamma = gamma * pi / 180 rot_in_euler = Euler([alpha, beta, gamma]) obj.worldOrientation = rot_in_euler.to_matrix()
def createSceneFromXML(scene_file): # parse xml sceneTree = ET.parse(scene_file) root = sceneTree.getroot() # traverse scene xml materialStack.append(createDefaultMaterial()) transformStack.append(Matrix.Identity(4)) rootObject = createObjectFromXML(root, root[0], './sceneRoot', None, True) # create coordinate conversion root sceneObject = bpy.data.objects.new('JReality Scene', None) jrealityToBlender = Euler((math.pi / 2, 0.0, math.pi / 2), 'XYZ') sceneObject.matrix_local = jrealityToBlender.to_matrix().to_4x4() bpy.context.scene.objects.link(sceneObject) rootObject.parent = sceneObject # find active camera cameraPath = root.find("scenePaths/path[@name='cameraPath']") if cameraPath != None: cameraPathXpath = resolveReferencePath( root, cameraPath, "./scenePaths/path[@name='cameraPath']") cameraPath = resolveReference(root, cameraPath, "./scenePaths/path[@name='cameraPath']") node = cameraPath.find('node[last()]') camTag = resolveReference(root, node, cameraPathXpath + "/node[last()]") bpy.context.scene.camera = tagToObject[camTag] else: print('WARNING: no camera path set')
def create_armature(mdl: Mdl, collection): model_name = Path(mdl.header.name).stem armature = bpy.data.armatures.new(f"{model_name}_ARM_DATA") armature_obj = bpy.data.objects.new(f"{model_name}_ARM", armature) armature_obj.show_in_front = True collection.objects.link(armature_obj) armature_obj.select_set(True) bpy.context.view_layer.objects.active = armature_obj bpy.ops.object.mode_set(mode='EDIT') bl_bones = [] for bone in mdl.bones: bl_bone = armature.edit_bones.new(bone.name) bl_bones.append(bl_bone) for bl_bone, s_bone in zip(bl_bones, mdl.bones): if s_bone.parent_bone_index != -1: bl_parent = bl_bones[s_bone.parent_bone_index] bl_bone.parent = bl_parent bl_bone.tail = Vector([0, 0, 1]) + bl_bone.head bpy.ops.object.mode_set(mode='POSE') for se_bone in mdl.bones: bl_bone = armature_obj.pose.bones.get(se_bone.name) pos = Vector(se_bone.position) rot = Euler(se_bone.rotation) mat = Matrix.Translation(pos) @ rot.to_matrix().to_4x4() bl_bone.matrix_basis.identity() bl_bone.matrix = bl_bone.parent.matrix @ mat if bl_bone.parent else mat bpy.ops.pose.armature_apply() bpy.ops.object.mode_set(mode='OBJECT') return armature_obj
def cek(cont): thisTime = time.time() #debugging #thisTime = lastNewMoonRecord + (7.3825 * 24 * 60 * 60)#first quarter #thisTime = lastNewMoonRecord + (14.765 * 24 * 60 * 60)#full moon #thisTime = lastNewMoonRecord + (22.1475 * 24 * 60 * 60)#third quarter x = thisTime - lastNewMoonRecord moonPhase = (x%mc) / 60 / 60 / 24 / 29.53 #cont.owner["pos"] = moonPhase #print(moonPhase)#for debugging own = cont.owner if "moon" in own: moon = own.scene.objects[own['moon']] #rot = 45 rot = 360 * -moonPhase r = radians(rot) el = Euler((0, 0, r)) #print(el) moon.worldOrientation = el.to_matrix()
def euler_matrices(params, euler_order, angle_units): mat_num = max(map(len, params)) params2 = make_repeaters(params) matrices = [] for i, location, angleX, angleY, angleZ, scale in zip( range(mat_num), *params2): # translation mat_t[0][3] = location[0] mat_t[1][3] = location[1] mat_t[2][3] = location[2] # rotation angles = (angleX * angle_units, angleY * angle_units, angleZ * angle_units) euler = Euler(angles, euler_order) # mat_r = euler.to_quaternion().to_matrix().to_4x4() mat_r = euler.to_matrix().to_4x4() # scale mat_s[0][0] = scale[0] mat_s[1][1] = scale[1] mat_s[2][2] = scale[2] # composite matrix m = mat_t @ mat_r @ mat_s matrices.append(m) return matrices
def __getAxisAngleBasedRotation(self, rotate, translate): euler = Euler(rotate) self.logger.debug("Injecting rotation: '%s'", str(euler)) vector_translate = Vector((translate[0], translate[1], translate[2])) # actually the translation is also needed to be passed here rotate_mtx = Matrix.to_4x4(euler.to_matrix()) translate_mtx = Matrix.Translation(vector_translate) cameraMatrix = translate_mtx * rotate_mtx # global matrix rotate (guess it is for world coordinate system rotating) mtx = Matrix.Rotation(-(math.pi / 2.0), 4, 'X') mtx = mtx * cameraMatrix (loc, quat, _) = mtx.decompose() # get the values the way that in x3d exporter does quat = quat.normalized() # some weird stuff axises = list(quat.axis.to_tuple()) angle = quat.angle orientation = self.__getStringRepresentation(axises) + " " + str(angle) translation = self.__getStringRepresentation(loc) return translation, orientation
def get_matrix_world_at_frame(obj, frame_id): rotation_mode = get_rotation_mode_at_frame(obj, frame_id) if rotation_mode == 'AXIS_ANGLE': axis_angle = get_vector4_at_frame(obj, "rotation_axis_angle", frame_id) angle = axis_angle[0] axis = Vector(axis_angle[1], axis_angle[2], axis_angle[3]) rotation_matrix = Matrix.Rotation(angle, 4, axis) elif rotation_mode == 'QUATERNION': rotation_quat = get_vector4_at_frame(obj, "rotation_quaternion", frame_id) quat = Quaternion(rotation_quat) rotation_matrix = quat.to_matrix().to_4x4() else: rotation = get_vector3_at_frame(obj, "rotation_euler", frame_id) e = Euler(rotation, rotation_mode) rotation_matrix = e.to_matrix().to_4x4() location = get_vector3_at_frame(obj, "location", frame_id) location_matrix = Matrix.Translation(location).to_4x4() scale = get_vector3_at_frame(obj, "scale", frame_id) scale_matrix = Matrix.Identity(4) scale_matrix[0][0] = scale[0] scale_matrix[1][1] = scale[1] scale_matrix[2][2] = scale[2] return vcu.element_multiply( vcu.element_multiply(location_matrix, rotation_matrix), scale_matrix)
def execute(self, context): from . import import_ac3d keywords = self.as_keywords(ignore=("axis_forward", "axis_up", "filter_glob", "rotation", "translation", "hide_props_region")) eul = Euler((radians(self.rotation[0]), radians(self.rotation[1]), radians(self.rotation[2])), 'XYZ') global_matrix = eul.to_matrix().to_4x4() @ \ axis_conversion(from_forward=self.axis_forward, from_up=self.axis_up).to_4x4() keywords["global_matrix"] = global_matrix t = time.mktime(datetime.datetime.now().timetuple()) import_ac3d.AC3D_OT_Import(self, context, **keywords) t = time.mktime(datetime.datetime.now().timetuple()) - t print('Finished importing in', t, 'seconds') return {'FINISHED'}
def obj_orientation(obj, alpha, beta, gamma): '''Set obj orientation, angle in degrees''' alpha = alpha*pi/180 beta = beta*pi/180 gamma = gamma*pi/180 rot_in_euler = Euler([alpha, beta, gamma]) obj.worldOrientation = rot_in_euler.to_matrix()
def draw_arc12(x, y, radius, start_angle, end_angle, subdivide): # いずれ削除 # 十二時から時計回りに描画 v = Vector([0, 1, 0]) e = Euler((0, 0, -start_angle)) m = e.to_matrix() v = m * v if end_angle >= start_angle: a = (end_angle - start_angle) / (subdivide + 1) else: a = (end_angle + math.pi * 2 - start_angle) / (subdivide + 1) e = Euler((0, 0, -a)) m = e.to_matrix() bgl.glBegin(bgl.GL_LINE_STRIP) for i in range(subdivide + 2): v1 = v * radius bgl.glVertex2f(x + v1[0], y + v1[1]) v = m * v bgl.glEnd()
def draw_arc12(x, y, radius, start_angle, end_angle, subdivide): # いずれ削除 # 十二時から時計回りに描画 v = Vector([0, 1, 0]) e = Euler((0, 0, -start_angle)) m = e.to_matrix() v = v * m if end_angle >= start_angle: a = (end_angle - start_angle) / (subdivide + 1) else: a = (end_angle + math.pi * 2 - start_angle) / (subdivide + 1) e = Euler((0, 0, -a)) m = e.to_matrix() bgl.glBegin(bgl.GL_LINE_STRIP) for i in range(subdivide + 2): v1 = v * radius bgl.glVertex2f(x + v1[0], y + v1[1]) v = v * m bgl.glEnd()
def compute_offset(xml_file): e = xml_file.parent_eulerXYZ eleur = Euler((e.x, e.y, e.z)) mat4 = eleur.to_matrix().to_4x4() pos = mat4 * xml_file.offset #tr = xml_file.offset - pos xml_file.offset = xml_file.parent_offset + pos xml_file.eulerXYZ = xml_file.eulerXYZ + xml_file.parent_eulerXYZ
def compute_offset_text(text): e = text.xml_eulerXYZ eleur = Euler((e.x, e.y, e.z)) mat4 = eleur.to_matrix().to_4x4() pos = mat4 * text.offset #tr = xml_file.offset - pos text.offset = text.xml_offset + pos text.eulerXYZ = text.eulerXYZ + text.xml_eulerXYZ
def main(_self, entity_object, plugin_data): # Restore Euler structure new_orientation = [0, 0, 0] for value in plugin_data: new_orientation[value[1]] = value[0] euler_orientation = Euler(new_orientation) # Interpolate between data and use for extrapolation interpolator = setdefaultdict(entity_object, "interpolate_orientation", interpolate([entity_object.worldOrientation.to_quaternion(), 0.0])) orientation = [euler_orientation.to_quaternion(), time.time()] interpolator.update(orientation) entity_object.worldOrientation = euler_orientation.to_matrix()
def test_loc_rot_scale(self): euler = Euler((math.radians(90), 0, math.radians(90)), 'ZYX') expected = Matrix( ((0, -5, 0, 1), (0, 0, -6, 2), (4, 0, 0, 3), (0, 0, 0, 1))) result = Matrix.LocRotScale((1, 2, 3), euler, (4, 5, 6)) self.assertAlmostEqualMatrix(result, expected, 4) result = Matrix.LocRotScale((1, 2, 3), euler.to_quaternion(), (4, 5, 6)) self.assertAlmostEqualMatrix(result, expected, 4) result = Matrix.LocRotScale((1, 2, 3), euler.to_matrix(), (4, 5, 6)) self.assertAlmostEqualMatrix(result, expected, 4)
def save_md3(settings): from mathutils import Euler, Matrix, Vector from math import radians starttime = time.clock() # start timer fullpath = splitext(settings.savepath)[0] modelname = basename(fullpath) logname = modelname + ".log" logfpath = fullpath + ".log" if settings.name == "": settings.name = modelname dumpall = settings.dumpall if settings.logtype == "append": log = open(logfpath,"a") elif settings.logtype == "overwrite": log = open(logfpath,"w") elif settings.logtype == "blender": log = bpy.data.texts.new(logname) log.clear() else: log = None ref_frame = settings.refframe if settings.refframe == -1: ref_frame = bpy.context.scene.frame_current message(log, "###################### BEGIN ######################") model = BlenderModelManager(settings.gzdoom, ref_frame) # Set up fix transformation matrix model.fix_transform *= Matrix.Scale(settings.scale, 4) model.fix_transform *= Matrix.Translation(Vector(( settings.offsetx, settings.offsety, settings.offsetz))) rotation_fix = Euler() rotation_fix.z = radians(90) model.fix_transform *= rotation_fix.to_matrix().to_4x4() model.md3.name = settings.name # Add objects to model manager if len(bpy.context.selected_objects) == 0: message(log, "Select an object to export!") else: # If multiple objects are selected, they are joined together for bobject in bpy.context.selected_objects: if bobject.type == 'MESH': model.add_mesh(bobject) elif bobject.type == 'EMPTY': model.add_tag(bobject) model.setup_frames() model.md3.GetSize() print_md3(log, model.md3, dumpall) model.save(settings.savepath) endtime = time.clock() - starttime message(log, "Export took {:.3f} seconds".format(endtime))
def draw_cloud(bm, prefs, translation=(0, 0, 0)): mat = Matrix() mat.translation = translation smin = prefs.lp_Cloud_Scale_Min smax = prefs.lp_Cloud_Scale_Max sx = uniform(smin[0], smax[0]) sy = uniform(smin[1], smax[1]) sz = uniform(smin[2], smax[2]) scale = (sx, sy, sz) mat[0][0], mat[1][1], mat[2][2] = scale[0], scale[1], scale[2] e = Euler((uniform(0, 3.14), uniform(0, 3.14), uniform(0, 3.14)), 'XYZ') mat = mat * e.to_matrix().to_4x4() bmesh.ops.create_icosphere(bm, subdivisions=prefs.lp_Cloud_Subdivisions, diameter=1.0, matrix=mat) return scale
def rotate_eye(obj, x_angle, z_angle): obj.rotation_mode = 'XYZ' deg_to_rad = np.pi * 2 / 360 outer_eye = bpy.data.collections["Collection 1"].objects['eye-outer'] x_rot = -x_angle * deg_to_rad z_rot = z_angle * deg_to_rad euler_rotation = Euler((x_rot, 0, z_rot), 'XYZ') obj.rotation_euler = euler_rotation outer_eye.rotation_euler = Euler((-x_rot - np.pi / 2, 0, z_rot), 'XYZ') obj_rot_mat = euler_rotation.to_matrix() #obj_rot_mat = initPoseMat if obj.parent: P = obj.parent.matrix.decompose()[1].to_matrix() obj_rot_mat = P * obj_rot_mat * P.inverted()
def compute_extra_transforme(obj, translate, rotate): if translate: obj.delta_location = Vector((0.0, 0.0, 0.0)) + translate if rotate: e = rotate eleur = Euler((e.x, e.y, e.z)) mat4 = eleur.to_matrix().to_4x4() w = Vector((0.0, 0.0, 0.0)) + obj.location pos = mat4 * w tr = Vector((0.0, 0.0, 0.0)) + pos - w w = Vector((0.0, 0.0, 0.0)) + obj.delta_location obj.delta_location = Vector((0.0, 0.0, 0.0)) + w + tr obj.delta_rotation_euler = Euler((rotate.x, rotate.y, rotate.z))
def _get_global_vertices(self, obj, bm): # Get world rotation matrix. eular = Euler(obj.rotation_euler) rotation_mat = eular.to_matrix() # Get center location of all vertices. center_location = Vector((0.0, 0.0, 0.0)) for v in bm.verts: center_location += v.co center_location /= len(bm.verts) # Move to local to global. transformed = {} for v in bm.verts: transformed[v] = compat.matmul(rotation_mat, v.co) transformed[v] -= center_location return transformed
def find_fcurve_matrix(self, id_data, bone_name, sourceaction, frame): # anim_data = id_data.animation_data location = Vector([0.0, 0.0, 0.0]) quat_rotation = Quaternion() # print("Rot mode: ", id_data.pose.bones[bone_name].rotation_mode) pose_bone = id_data.pose.bones[bone_name] rot_mode = pose_bone.rotation_mode if len(rot_mode) > 3: rot_mode = "XYZ" euler_rotation = Euler((0, 0, 0), rot_mode) rotmat = None rotmat_e = None for fcurve in sourceaction.fcurves: # print(fcurve.data_path) if '["' + bone_name + '"]' in fcurve.data_path: if ".location" in fcurve.data_path: location[fcurve.array_index] = fcurve.evaluate(frame) if "_quaternion" in fcurve.data_path: quat_rotation[fcurve.array_index] = fcurve.evaluate(frame) rotmat = quat_rotation.to_matrix() if "_euler" in fcurve.data_path: euler_rotation[fcurve.array_index] = fcurve.evaluate(frame) rotmat_e = euler_rotation.to_matrix() # print("Frame, Euler: ", frame, fcurve.evaluate(frame), euler_rotation) # print("Rotmat: ", rotmat_e) mat = Matrix.Translation(location) # print("Reading loc: ", bone_name, frame, location) if rotmat is not None: rotmat.resize_4x4() mat = mat @ rotmat if rotmat_e is not None: rotmat_e.resize_4x4() mat = mat @ rotmat_e posemat = pose_bone.id_data.convert_space(matrix=mat, pose_bone=pose_bone, from_space='LOCAL', to_space='POSE') if bone_name == "foot_ik.L": print("foundrotmat: ", frame) print(mat) print(posemat) return posemat
def compute_box_3d_euler_angel(location, box3d_dimensions, angles): ''' compute_box_3d based on location, box3d_dimensions, Euler angles https://docs.blender.org/api/blender_python_api_current/mathutils.html#mathutils.Matrix input: box3d_dimensions:3 dimensions 3D object dimensions: height, width, length (in meters) location: 3 location 3D object location x,y,z in camera coordinates (in meters) angles:3 euler angles in order='XYZ' (3d vector) – Three angles, in radians. qs: (8,3) array of vertices for the 3d box in following order: 7 -------- 6 /| /| 4 -------- 5 . | | | | . 3 -------- 2 |/ |/ 0 -------- 1 Returns: corners_3d: (8,3) array in rect camera coord. ''' eul = Euler(angles) # 3d bounding box dimensions w, h, l = box3d_dimensions # 3d bounding box corners x_corners = [-w / 2, w / 2, w / 2, -w / 2, -w / 2, w / 2, w / 2, -w / 2] y_corners = [h / 2, h / 2, h / 2, h / 2, -h / 2, -h / 2, -h / 2, -h / 2] z_corners = [-l / 2, -l / 2, l / 2, l / 2, -l / 2, -l / 2, l / 2, l / 2] R = eul.to_matrix() # rotate and translate 3d bounding box corners_3d = np.dot(R, np.vstack([x_corners, y_corners, z_corners])) # print(corners_3d.shape) corners_3d[0, :] = corners_3d[0, :] + location[0] corners_3d[1, :] = corners_3d[1, :] + location[1] corners_3d[2, :] = corners_3d[2, :] + location[2] # print('cornsers_3d: ', corners_3d) # only draw 3d bounding box for objs in front of the camera return np.transpose(corners_3d)
def rotation(self, xyz): if len(xyz) != 3: utils.debug("Rotation assignment failed on " + self.obj.name + " object. xyz size != 3.") if isinstance(xyz, (list, tuple)) or len(xyz) == 3: xyz = Euler(xyz, 'XYZ') srt = self.obj.localOrientation.copy() xyz = xyz.to_matrix() for obj in self.transformable: if obj.__class__.__name__ == "KX_GameObject": if obj == self.obj: obj.localOrientation = xyz else: srr = obj.worldOrientation.copy() srr.rotate(xyz) srr = srr.to_euler() obj.localOrientation = srr else: srr = obj.rotation.copy() srr.rotate(xyz) obj.localOrientation = srr obj.rotation = srr self._rotation = self.ProxyRotation()
def compute_box_3d_euler_angel_batch(inputs): location = inputs[:3] box3d_dimensions = inputs[3:6] angles = inputs[6:9] eul = Euler(angles) # 3d bounding box dimensions w, h, l = box3d_dimensions # 3d bounding box corners x_corners = [-w / 2, -w / 2, w / 2, w / 2, -w / 2, -w / 2, w / 2, w / 2] y_corners = [h / 2, h / 2, h / 2, h / 2, -h / 2, -h / 2, -h / 2, -h / 2] z_corners = [-l / 2, l / 2, l / 2, -l / 2, -l / 2, l / 2, l / 2, -l / 2] R = eul.to_matrix() corners_3d = np.dot(R, np.vstack([x_corners, y_corners, z_corners])) corners_3d[0, :] = corners_3d[0, :] + location[0] corners_3d[1, :] = corners_3d[1, :] + location[1] corners_3d[2, :] = corners_3d[2, :] + location[2] return np.transpose(corners_3d)
def transform_data_to_world_matrix(transform): mat_loc = Matrix.Translation(transform['location']).to_4x4() if transform['rotation_mode'] == "AXIS_ANGLE": angle = transform['rotation'][0] axis = Vector(transform['rotation'][1], transform['rotation'][2], transform['rotation'][3]) mat_rot = Matrix.Rotation(angle, 4, axis) elif transform['rotation_mode'] == "QUATERNION": q = Quaternion(transform['rotation']) mat_rot = q.to_matrix().to_4x4() else: e = Euler(transform['rotation'], transform['rotation_mode']) mat_rot = e.to_matrix().to_4x4() mat_scale = Matrix.Identity(4) mat_scale[0][0] = transform['scale'][0] mat_scale[1][1] = transform['scale'][1] mat_scale[2][2] = transform['scale'][2] return mat_loc * mat_rot * mat_scale
def random_scale_and_rotation(obj, normal, NM_SCN, self_data): loc, rot, scale = obj.matrix_world.decompose() loc = Matrix.Translation(loc) rot = rot.to_euler().to_matrix().to_4x4() rot_add = Euler(Vector((0, 0, math.radians(self_data.rotate_angle)))) rot_add = rot_add.to_matrix().to_4x4() if NM_SCN.use_random_scale: new_scale = uniform(NM_SCN.random_scale_from, NM_SCN.random_scale_to) scale = Matrix.Scale(new_scale, 4) else: scale = Matrix.Scale(self_data.scale_model, 4) # apply rotation by normal if checked "align_by_normal" if NM_SCN.align_by_normal: rot_by_normal = normal.rotation_difference(Vector((0, 0, 1))) rot_by_normal.invert() rot_by_normal = rot_by_normal.to_euler().to_matrix().to_4x4() rot = rot_by_normal @ rot_add else: rot = Euler((0, 0, 0)).to_matrix().to_4x4() rot = rot @ rot_add if NM_SCN.use_random_rotation: x_angle = math.radians(uniform(0, NM_SCN.random_rotation_x)) y_angle = math.radians(uniform(0, NM_SCN.random_rotation_y)) z_angle = math.radians(uniform(0, NM_SCN.random_rotation_z)) rot_rand = Euler(Vector( (x_angle, y_angle, z_angle))).to_matrix().to_4x4() rot = rot @ rot_rand mat_w = loc @ rot @ scale obj.matrix_world = mat_w
def createSceneFromXML(scene_file): # parse xml sceneTree = ET.parse(scene_file) root = sceneTree.getroot() # traverse scene xml materialStack.append(createDefaultMaterial()) transformStack.append(Matrix.Identity(4)) rootObject = createObjectFromXML(root, root[0], './sceneRoot', None, True) # create coordinate conversion root sceneObject = bpy.data.objects.new('JReality Scene', None) jrealityToBlender = Euler((math.pi/2, 0.0, math.pi/2), 'XYZ') sceneObject.matrix_local = jrealityToBlender.to_matrix().to_4x4() bpy.context.scene.objects.link(sceneObject) rootObject.parent = sceneObject; # find active camera cameraPath = root.find("scenePaths/path[@name='cameraPath']") if cameraPath != None: cameraPathXpath = resolveReferencePath(root, cameraPath, "./scenePaths/path[@name='cameraPath']") cameraPath = resolveReference(root, cameraPath, "./scenePaths/path[@name='cameraPath']") node = cameraPath.find('node[last()]') camTag = resolveReference(root, node, cameraPathXpath + "/node[last()]") bpy.context.scene.camera = tagToObject[camTag] else: print('WARNING: no camera path set')
def joueur_clavier(gl): '''Un joueur joue au clavier et avec la souris Avec la souris: Haut bas pour avancer reculer donc y Gauche droite pour le déplacement latéral donc x Molette pour régler l'élévation du tir Q pour sauter Espace pour ajouter un livre donc accx Le joueur au clavier est toujours le 0 Si clavier, ajout de la flèche de tir ''' # Récupération des entrées clavier et de la position de la souris # Space donne accx = -6 accx = gl.clavier["accx"] # Repasse à 0 gl.clavier["accx"] = 0 # Saut accz = gl.clavier["accz"] # Souris x = gl.mouse_x y = gl.mouse_y accy = 2 - gl.clavier["wheel"] # Définir la direction de la flèche alpha = 0.3 + accy / 9 # élévation beta = 0 gamma = 0 # direction mais définit par x, y # set objects orientation with alpha, beta, gamma in degrees rot_en_euler = Euler([alpha, beta, gamma]) # Orientation de la flèche gl.fleche.worldOrientation = rot_en_euler.to_matrix() data = ["clavier", accx, accy, accz, x, y] return data
def bvh_node_dict2armature(context, bvh_name, bvh_nodes, bvh_frame_time, rotate_mode='XYZ', frame_start=1, IMPORT_LOOP=False, global_matrix=None, use_fps_scale=False, use_frame_step=False, only_rootbone_location=True, rig_only=False, ): ZERO_AREA_BONES = [] scene = context.scene def add_armature(): # Add the new armature, for obj in scene.objects: obj.select = False arm_data = bpy.data.armatures.new(bvh_name) arm_ob = bpy.data.objects.new(bvh_name, arm_data) scene.objects.link(arm_ob) arm_ob.select = True scene.objects.active = arm_ob bpy.ops.object.mode_set(mode='OBJECT', toggle=False) bpy.ops.object.mode_set(mode='EDIT', toggle=False) bvh_nodes_list = sorted_nodes(bvh_nodes) # Get the average bone length for zero length bones, we may not use this. average_bone_length = 0.0 nonzero_count = 0 for bvh_node in bvh_nodes_list: l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length if l: average_bone_length += l nonzero_count += 1 # Very rare cases all bones could be zero length??? if not average_bone_length: average_bone_length = 0.1 else: # Normal operation average_bone_length = average_bone_length / nonzero_count # XXX, annoying, remove bone. while arm_data.edit_bones: arm_ob.edit_bones.remove(arm_data.edit_bones[-1]) #ZERO_AREA_BONES = [] for bvh_node in bvh_nodes_list: if bvh_node.zero_length: print("ZZZZZZZZZZZZZZZZZZZZZZ", bvh_node) # New editbone bone = bvh_node.temp = arm_data.edit_bones.new(bvh_node.name) bone.head = bvh_node.rest_head_world bone.tail = bvh_node.rest_tail_world # Zero Length Bones! (an exceptional case) if (bone.head - bone.tail).length < 0.001: print("\tzero length bone found:", bone.name) if bvh_node.parent: ofs = bvh_node.parent.rest_head_local - bvh_node.parent.rest_tail_local if ofs.length: # is our parent zero length also?? unlikely bone.tail = bone.tail - ofs else: bone.tail.y = bone.tail.y + average_bone_length else: # HANDLE ZERO LENGTH BONES bone.tail += average_bone_length * Vector((0,1,0)) #bone.tail.y = bone.tail.y + average_bone_length ZERO_AREA_BONES.append(bone.name) for bvh_node in bvh_nodes_list: if bvh_node.zero_length: pass if bvh_node.parent: # bvh_node.temp is the Editbone # Set the bone parent bvh_node.temp.parent = bvh_node.parent.temp # Set the connection state if((not bvh_node.has_loc) and (bvh_node.parent.temp.name not in ZERO_AREA_BONES) and (bvh_node.parent.rest_tail_local == bvh_node.rest_head_local)): bvh_node.temp.use_connect = True # Replace the editbone with the editbone name, # to avoid memory errors accessing the editbone outside editmode for bvh_node in bvh_nodes_list: bvh_node.temp = bvh_node.temp.name return arm_ob, bvh_nodes_list if frame_start < 1: frame_start = 1 arm_ob, bvh_nodes_list = add_armature() # zero length nodes X = [n for n in bvh_nodes_list if n.zero_length] print("ZEROOOOOOO", X) # bone taken out no longer needed #bone = None arm_data = arm_ob.data # Now Apply the animation to the armature # Get armature animation data bpy.ops.object.mode_set(mode='OBJECT', toggle=False) pose = arm_ob.pose pose_bones = pose.bones if rotate_mode == 'NATIVE': for bvh_node in bvh_nodes_list: bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] if bone_name in ZERO_AREA_BONES: print("ZLB", bone_name) pose_bone["zero"] = True pose_bone.rotation_mode = bvh_node.rot_order_str elif rotate_mode != 'QUATERNION': for pose_bone in pose_bones: pose_bone.rotation_mode = rotate_mode else: # Quats default pass context.scene.update() if rig_only: # fix this to have action part too. arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(rotation=True) return arm_ob arm_ob.animation_data_create() action = bpy.data.actions.new(name=bvh_name) arm_ob.animation_data.action = action # Replace the bvh_node.temp (currently an editbone) # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) num_frame = 0 for bvh_node in bvh_nodes_list: bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] rest_bone = arm_data.bones[bone_name] bone_rest_matrix = rest_bone.matrix_local.to_3x3() bone_rest_matrix_inv = Matrix(bone_rest_matrix) bone_rest_matrix_inv.invert() bone_rest_matrix_inv.resize_4x4() bone_rest_matrix.resize_4x4() #XXXX bone removed from bvh_node.temp bvh_node.temp = (pose_bone, bone_rest_matrix, bone_rest_matrix_inv) if 0 == num_frame: num_frame = len(bvh_node.anim_data) # Choose to skip some frames at the beginning. Frame 0 is the rest pose # used internally by this importer. Frame 1, by convention, is also often # the rest pose of the skeleton exported by the motion capture system. bt = 1.0 / context.scene.render.fps print("FT, BT", bvh_frame_time, bt, floor(bt / bvh_frame_time)) sub_frame_step = 1 if use_frame_step: sub_frame_step = floor(bt / bvh_frame_time) if sub_frame_step == 0: sub_frame_step = 1 skip_frame = 1 if num_frame > skip_frame: num_frame = num_frame - skip_frame # Create a shared time axis for all animation curves. time = [float(frame_start)] * num_frame dt = 0.0 if use_fps_scale: dt = scene.render.fps * bvh_frame_time for frame_i in range(1, num_frame): time[frame_i] += float(frame_i) * dt else: sub_frame_step = 1 for frame_i in range(1, num_frame): time[frame_i] += float(frame_i) frange = range(0, num_frame, sub_frame_step) print("bvh_frame_time = %f, dt = %f, num_frame = %d" % (bvh_frame_time, dt, num_frame)) for i, bvh_node in enumerate(bvh_nodes_list): pose_bone, bone_rest_matrix, bone_rest_matrix_inv = bvh_node.temp #print("FRANGE:", frange) if bvh_node.has_loc: # Not sure if there is a way to query this or access it in the # PoseBone structure. if (pose_bone.parent is None and only_rootbone_location) or not only_rootbone_location: data_path = 'pose.bones["%s"].location' % pose_bone.name location = [(0.0, 0.0, 0.0)] * num_frame for frame_i in range(0, num_frame): bvh_loc = bvh_node.anim_data[frame_i + skip_frame][:3] bone_translate_matrix = Matrix.Translation( Vector(bvh_loc) - bvh_node.rest_head_local) location[frame_i] = (bone_rest_matrix_inv * bone_translate_matrix).to_translation() # For each location x, y, z. for axis_i in range(3): curve = action.fcurves.new(data_path=data_path, index=axis_i) keyframe_points = curve.keyframe_points keyframe_points.add(len(frange)) for i, frame_i in enumerate(frange): keyframe_points[i].co = \ (time[frame_i], location[frame_i][axis_i]) if bvh_node.has_rot: data_path = None rotate = None if 'QUATERNION' == rotate_mode: rotate = [(1.0, 0.0, 0.0, 0.0)] * num_frame data_path = ('pose.bones["%s"].rotation_quaternion' % pose_bone.name) else: rotate = [(0.0, 0.0, 0.0)] * num_frame data_path = ('pose.bones["%s"].rotation_euler' % pose_bone.name) prev_euler = Euler((0.0, 0.0, 0.0)) for frame_i in range(0, num_frame): bvh_rot = bvh_node.anim_data[frame_i + skip_frame][3:] # apply rotation order and convert to XYZ # note that the rot_order_str is reversed. euler = Euler(bvh_rot, bvh_node.rot_order_str[::-1]) bone_rotation_matrix = euler.to_matrix().to_4x4() bone_rotation_matrix = (bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix) if 4 == len(rotate[frame_i]): rotate[frame_i] = bone_rotation_matrix.to_quaternion() else: rotate[frame_i] = bone_rotation_matrix.to_euler( pose_bone.rotation_mode, prev_euler) prev_euler = rotate[frame_i] # For each Euler angle x, y, z (or Quaternion w, x, y, z). for axis_i in range(len(rotate[0])): curve = action.fcurves.new(data_path=data_path, index=axis_i) keyframe_points = curve.keyframe_points keyframe_points.add(len(frange)) for i, frame_i in enumerate(frange): keyframe_points[i].co = \ (time[frame_i], rotate[frame_i][axis_i]) for cu in action.fcurves: if IMPORT_LOOP: pass # 2.5 doenst have cyclic now? for bez in cu.keyframe_points: bez.interpolation = 'LINEAR' # finally apply matrix arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(rotation=True) return arm_ob
def read_chan(context, filepath, z_up, rot_ord, sensor_width, sensor_height): # get the active object scene = context.scene obj = context.active_object camera = obj.data if obj.type == 'CAMERA' else None # prepare the correcting matrix rot_mat = Matrix.Rotation(radians(90.0), 4, 'X').to_4x4() # read the file filehandle = open(filepath, 'r') # iterate through the files lines for line in filehandle: # reset the target objects matrix # (the one from which one we'll extract the final transforms) m_trans_mat = Matrix() # strip the line data = line.split() # test if the line is not commented out if data and not data[0].startswith("#"): # set the frame number basing on the chan file scene.frame_set(int(data[0])) # read the translation values from the first three columns of line v_transl = Vector((float(data[1]), float(data[2]), float(data[3]))) translation_mat = Matrix.Translation(v_transl) translation_mat.to_4x4() # read the rotations, and set the rotation order basing on the # order set during the export (it's not being saved in the chan # file you have to keep it noted somewhere # the actual objects rotation order doesn't matter since the # rotations are being extracted from the matrix afterwards e_rot = Euler((radians(float(data[4])), radians(float(data[5])), radians(float(data[6])))) e_rot.order = rot_ord mrot_mat = e_rot.to_matrix() mrot_mat.resize_4x4() # merge the rotation and translation m_trans_mat = translation_mat * mrot_mat # correct the world space # (nuke's and blenders scene spaces are different) if z_up: m_trans_mat = rot_mat * m_trans_mat # break the matrix into a set of the coordinates trns = m_trans_mat.decompose() # set the location and the location's keyframe obj.location = trns[0] obj.keyframe_insert("location") # convert the rotation to euler angles (or not) # basing on the objects rotation mode if obj.rotation_mode == 'QUATERNION': obj.rotation_quaternion = trns[1] obj.keyframe_insert("rotation_quaternion") elif obj.rotation_mode == 'AXIS_ANGLE': tmp_rot = trns[1].to_axis_angle() obj.rotation_axis_angle = (tmp_rot[1], *tmp_rot[0]) obj.keyframe_insert("rotation_axis_angle") del tmp_rot else: obj.rotation_euler = trns[1].to_euler(obj.rotation_mode) obj.keyframe_insert("rotation_euler") # check if the object is camera and fov data is present if camera and len(data) > 7: camera.sensor_fit = 'HORIZONTAL' camera.sensor_width = sensor_width camera.sensor_height = sensor_height camera.angle_y = radians(float(data[7])) camera.keyframe_insert("lens") filehandle.close() return {'FINISHED'}
def read_chan(context, filepath, z_up, rot_ord, sensor_width, sensor_height): # get the active object scene = context.scene obj = context.active_object camera = obj.data if obj.type == 'CAMERA' else None # prepare the correcting matrix rot_mat = Matrix.Rotation(radians(90.0), 4, 'X').to_4x4() # read the file filehandle = open(filepath, 'r') # iterate throug the files lines for line in filehandle: # reset the target objects matrix # (the one from whitch one we'll extract the final transforms) m_trans_mat = Matrix() # strip the line data = line.split() # test if the line is not commented out if data and not data[0].startswith("#"): # set the frame number basing on the chan file scene.frame_set(int(data[0])) # read the translation values from the first three columns of line v_transl = Vector((float(data[1]), float(data[2]), float(data[3]))) translation_mat = Matrix.Translation(v_transl) translation_mat.to_4x4() # read the rotations, and set the rotation order basing on the # order set during the export (it's not being saved in the chan # file you have to keep it noted somewhere # the actual objects rotation order doesn't matter since the # rotations are being extracted from the matrix afterwards e_rot = Euler((radians(float(data[4])), radians(float(data[5])), radians(float(data[6])))) e_rot.order = rot_ord mrot_mat = e_rot.to_matrix() mrot_mat.resize_4x4() # merge the rotation and translation m_trans_mat = translation_mat * mrot_mat # correct the world space # (nuke's and blenders scene spaces are different) if z_up: m_trans_mat = rot_mat * m_trans_mat # break the matrix into a set of the coordinates trns = m_trans_mat.decompose() # set the location and the location's keyframe obj.location = trns[0] obj.keyframe_insert("location") # convert the rotation to euler angles (or not) # basing on the objects rotation mode if obj.rotation_mode == 'QUATERNION': obj.rotation_quaternion = trns[1] obj.keyframe_insert("rotation_quaternion") elif obj.rotation_mode == 'AXIS_ANGLE': tmp_rot = trns[1].to_axis_angle() obj.rotation_axis_angle = (tmp_rot[1], *tmp_rot[0]) obj.keyframe_insert("rotation_axis_angle") del tmp_rot else: obj.rotation_euler = trns[1].to_euler(obj.rotation_mode) obj.keyframe_insert("rotation_euler") # check if the object is camera and fov data is present if camera and len(data) > 7: camera.sensor_fit = 'HORIZONTAL' camera.sensor_width = sensor_width camera.sensor_height = sensor_height camera.angle_y = radians(float(data[7])) camera.keyframe_insert("lens") filehandle.close() return {'FINISHED'}
def _get_bone_channels(bone_list, action, export_scale): """Takes a bone list and action and returns bone channels. bone_channels structure example: [("Bone", [("_TIME", [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]), ("_MATRIX", [])])]""" bone_channels = [] frame_start = action.frame_range[0] frame_end = action.frame_range[1] total_time = action.scs_props.action_length anim_export_step = action.scs_props.anim_export_step total_frames = (frame_end - frame_start) / anim_export_step # print(' -- action: %r' % str(action)) for bone in bone_list: # print(' oo bone: %r' % str(bone)) if bone: # print(' -- bone_name: %r' % bone.name) bone_name = bone.name bone_rest_mat = bone.matrix_local if bone.parent: parent_bone_rest_mat = Matrix.Scale(export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * bone.parent.matrix_local else: parent_bone_rest_mat = Matrix() for group in action.groups: if group.name == bone_name: # print(' -- group: %r' % str(group)) # GET CHANELS' CURVES loc_curves = {} euler_rot_curves = {} quat_rot_curves = {} sca_curves = {} rot_mode = '' for channel in group.channels: data_path = channel.data_path array_index = channel.array_index # channel_start = channel.range()[0] # channel_end = channel.range()[1] # print(' channel: %r (%s) [%s - %s]' % (data_path, array_index, channel_start, channel_end)) if data_path.endswith("location"): loc_curves[array_index] = channel elif data_path.endswith("rotation_euler"): euler_rot_curves[array_index] = channel rot_mode = 'euler' elif data_path.endswith("rotation_quaternion"): quat_rot_curves[array_index] = channel rot_mode = 'quat' elif data_path.endswith("scale"): sca_curves[array_index] = channel # GO THOUGH FRAMES actual_frame = frame_start timings_stream = [] matrices_stream = [] while actual_frame <= frame_end: mat_loc = Matrix() mat_rot = Matrix() mat_sca = Matrix() # LOCATION MATRIX if len(loc_curves) > 0: location = Vector() for index in range(3): if index in loc_curves: location[index] = loc_curves[index].evaluate(actual_frame) mat_loc = Matrix.Translation(location) # ROTATION MATRIX if rot_mode == 'euler' and len(euler_rot_curves) > 0: rotation = Euler() for index in range(3): if index in euler_rot_curves: rotation[index] = euler_rot_curves[index].evaluate(actual_frame) mat_rot = Euler(rotation, 'XYZ').to_matrix().to_4x4() # TODO: Solve the other rotation modes. if rot_mode == 'quat' and len(quat_rot_curves) > 0: rotation = Quaternion() for index in range(4): if index in quat_rot_curves: rotation[index] = quat_rot_curves[index].evaluate(actual_frame) mat_rot = rotation.to_matrix().to_4x4() # SCALE MATRIX if len(sca_curves) > 0: scale = Vector((1.0, 1.0, 1.0)) for index in range(3): if index in sca_curves: scale[index] = sca_curves[index].evaluate(actual_frame) mat_sca = Matrix() mat_sca[0] = (scale[0], 0, 0, 0) mat_sca[1] = (0, scale[2], 0, 0) mat_sca[2] = (0, 0, scale[1], 0) mat_sca[3] = (0, 0, 0, 1) # BLENDER FRAME MATRIX mat = mat_loc * mat_rot * mat_sca # SCALE REMOVAL MATRIX rest_location, rest_rotation, rest_scale = bone_rest_mat.decompose() # print(' BONES rest_scale: %s' % str(rest_scale)) rest_scale = rest_scale * export_scale scale_removal_matrix = Matrix() scale_removal_matrix[0] = (1.0 / rest_scale[0], 0, 0, 0) scale_removal_matrix[1] = (0, 1.0 / rest_scale[1], 0, 0) scale_removal_matrix[2] = (0, 0, 1.0 / rest_scale[2], 0) scale_removal_matrix[3] = (0, 0, 0, 1) # SCALE MATRIX scale_matrix = Matrix.Scale(export_scale, 4) # COMPUTE SCS FRAME MATRIX frame_matrix = (parent_bone_rest_mat.inverted() * _convert_utils.scs_to_blend_matrix().inverted() * scale_matrix.inverted() * bone_rest_mat * mat * scale_removal_matrix.inverted()) # print(' actual_frame: %s - value: %s' % (actual_frame, frame_matrix)) timings_stream.append(("__time__", total_time / total_frames), ) matrices_stream.append(("__matrix__", frame_matrix.transposed()), ) actual_frame += anim_export_step anim_timing = ("_TIME", timings_stream) anim_matrices = ("_MATRIX", matrices_stream) bone_anim = (anim_timing, anim_matrices) bone_data = (bone_name, bone_anim) bone_channels.append(bone_data) else: lprint('W bone %r is not part of the actual Armature!', bone.name) # print(' -- bone.name: %r' % (bone.name)) return bone_channels
def modal(self, context, event): context.area.tag_redraw() nexus_model_SCN = context.scene.nexus_model_manager mod = None if event.shift: mod = "SHIFT" elif event.ctrl: mod = "CTRL" # if event.alt: # mod.append("Alt") # if event.ctrl: # mod.append("Ctrl") tip_text = "LMB - Add Model | G - Move, R - Rotate, MOUSEWHEEL +ctrl 0.1, +shift 0.01 - Scale | N - Align by normal | RMB / ESC - Cancel" context.area.header_text_set(tip_text) if event.type == "MOUSEMOVE": if self.transform_mode == "MOVE": # new origin and normal origin, direction = self.get_origin_and_direction( event, context) bHit = None pos_hit = None normal_hit = None face_index_hit = None obj_hit = None matrix_world = None # hide mesh self.current_model.hide_set(True) canvas = nexus_model_SCN.canvas_object if canvas == None: # trace bHit, pos_hit, normal_hit, face_index_hit, obj_hit, matrix_world = context.scene.ray_cast( view_layer=context.view_layer, origin=origin, direction=direction) else: # trace bHit, pos_hit, normal_hit, face_index_hit = canvas.ray_cast( origin=origin, direction=direction) # show mesh self.current_model.hide_set(False) if bHit: self.normal = normal_hit.normalized() self.mouse_path[0] = pos_hit self.mouse_path[1] = pos_hit + (self.normal * 2.0) loc, rot, scale = self.current_model.matrix_world.decompose( ) loc = Matrix.Translation(self.mouse_path[0]) rot_add = Euler( Vector((0, 0, math.radians(self.rotate_angle)))) rot_add = rot_add.to_matrix().to_4x4() scale = Matrix.Scale(self.scale_model, 4) # apply rotation by normal if checked "align_by_normal" if nexus_model_SCN.align_by_normal: # rot = self.normal.to_track_quat("Z","Y").to_euler() rot = self.normal.rotation_difference(Vector( (0, 0, 1))) rot.invert() rot = rot.to_euler().to_matrix().to_4x4() else: rot = Euler((0, 0, 0)).to_matrix().to_4x4() rot = rot @ rot_add mat_w = loc @ rot @ scale self.current_model.matrix_world = mat_w # draw assets self.draw_asset(context, event) elif self.transform_mode == "ROTATE": self.calculate_angle(event, context) delta_angle = self.rotate_angle - self.rotate_angle_old self.current_model.rotation_euler.rotate_axis( "Z", math.radians(delta_angle)) self.rotate_angle_old = self.rotate_angle # elif self.transform_mode == "SCALE": # self.model_2d_point = self.get_2d_point_from_3d(event, context) # x = self.model_2d_point.x - event.mouse_region_x # y = self.model_2d_point.y - event.mouse_region_y # self.current_distance_scale = math.hypot(x, y) # delta_scale = self.current_distance_scale - self.start_distance_scale # self.scale_model = self.scale_model + delta_scale * 0.1 # self.current_model.scale = Vector((self.scale_model, self.scale_model, self.scale_model)) if event.type == "WHEELUPMOUSE": if mod == "CTRL": self.scale_model += 0.1 elif mod == "SHIFT": self.scale_model += 0.01 self.change_scale_current_model(context, event) elif event.type == "WHEELDOWNMOUSE": if mod == "CTRL": self.scale_model -= 0.1 elif mod == "SHIFT": self.scale_model -= 0.01 self.change_scale_current_model(context, event) if event.value == "PRESS": if event.type == "LEFTMOUSE": self.transform_mode = "MOVE" self.LMB_PRESS = True # self.draw_mouse_path.append((event.mouse_region_x, event.mouse_region_y)) # 2d path screen space random_scale_and_rotation(self.current_model, self.normal, nexus_model_SCN, self) self.prev_location = self.current_model.location # 3d path world path self.current_model = add_model(context, self.mouse_path[0], self.normal, self.scale_model) return {"RUNNING_MODAL"} elif event.type == "R": self.transform_mode = "ROTATE" return {"RUNNING_MODAL"} elif event.type == "G": self.transform_mode = "MOVE" return {"RUNNING_MODAL"} # elif event.type == "S": # self.transform_mode = "SCALE" # self.model_2d_point = self.get_2d_point_from_3d(event, context) # x = self.model_2d_point.x - event.mouse_region_x # y = self.model_2d_point.y - event.mouse_region_y # self.start_distance_scale = math.hypot(x, y) # return {"RUNNING_MODAL"} elif event.type == "N": nexus_model_SCN.align_by_normal = not nexus_model_SCN.align_by_normal return {"RUNNING_MODAL"} elif event.type in {"RIGHTMOUSE", "ESC"}: bpy.ops.object.select_all(action="DESELECT") self.current_model.select_set(True) bpy.ops.object.delete() bpy.types.SpaceView3D.draw_handler_remove( self._handle_3d, "WINDOW") bpy.types.SpaceView3D.draw_handler_remove( self._handle_2d, "WINDOW") context.area.header_text_set( text=None) # return header text to default return {"CANCELLED"} if event.value == "RELEASE": if event.type == "LEFTMOUSE": self.LMB_PRESS = False # self.draw_mouse_path = [] # 2d path screen space return {"RUNNING_MODAL"}
def bvh_node_dict2armature( context, bvh_name, bvh_nodes, bvh_frame_time, rotate_mode='XYZ', frame_start=1, IMPORT_LOOP=False, global_matrix=None, use_fps_scale=False, ): if frame_start < 1: frame_start = 1 # Add the new armature, scene = context.scene for obj in scene.objects: obj.select_set(False) arm_data = bpy.data.armatures.new(bvh_name) arm_ob = bpy.data.objects.new(bvh_name, arm_data) context.collection.objects.link(arm_ob) arm_ob.select_set(True) context.view_layer.objects.active = arm_ob bpy.ops.object.mode_set(mode='OBJECT', toggle=False) bpy.ops.object.mode_set(mode='EDIT', toggle=False) bvh_nodes_list = sorted_nodes(bvh_nodes) # Get the average bone length for zero length bones, we may not use this. average_bone_length = 0.0 nonzero_count = 0 for bvh_node in bvh_nodes_list: l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length if l: average_bone_length += l nonzero_count += 1 # Very rare cases all bones could be zero length??? if not average_bone_length: average_bone_length = 0.1 else: # Normal operation average_bone_length = average_bone_length / nonzero_count # XXX, annoying, remove bone. while arm_data.edit_bones: arm_ob.edit_bones.remove(arm_data.edit_bones[-1]) ZERO_AREA_BONES = [] for bvh_node in bvh_nodes_list: # New editbone bone = bvh_node.temp = arm_data.edit_bones.new(bvh_node.name) bone.head = bvh_node.rest_head_world bone.tail = bvh_node.rest_tail_world # Zero Length Bones! (an exceptional case) if (bone.head - bone.tail).length < 0.001: print("\tzero length bone found:", bone.name) if bvh_node.parent: ofs = bvh_node.parent.rest_head_local - bvh_node.parent.rest_tail_local if ofs.length: # is our parent zero length also?? unlikely bone.tail = bone.tail - ofs else: bone.tail.y = bone.tail.y + average_bone_length else: bone.tail.y = bone.tail.y + average_bone_length ZERO_AREA_BONES.append(bone.name) for bvh_node in bvh_nodes_list: if bvh_node.parent: # bvh_node.temp is the Editbone # Set the bone parent bvh_node.temp.parent = bvh_node.parent.temp # Set the connection state if ((not bvh_node.has_loc) and (bvh_node.parent.temp.name not in ZERO_AREA_BONES) and (bvh_node.parent.rest_tail_local == bvh_node.rest_head_local)): bvh_node.temp.use_connect = True # Replace the editbone with the editbone name, # to avoid memory errors accessing the editbone outside editmode for bvh_node in bvh_nodes_list: bvh_node.temp = bvh_node.temp.name # Now Apply the animation to the armature # Get armature animation data bpy.ops.object.mode_set(mode='OBJECT', toggle=False) pose = arm_ob.pose pose_bones = pose.bones if rotate_mode == 'NATIVE': for bvh_node in bvh_nodes_list: bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] pose_bone.rotation_mode = bvh_node.rot_order_str elif rotate_mode != 'QUATERNION': for pose_bone in pose_bones: pose_bone.rotation_mode = rotate_mode else: # Quats default pass context.view_layer.update() arm_ob.animation_data_create() action = bpy.data.actions.new(name=bvh_name) arm_ob.animation_data.action = action # Replace the bvh_node.temp (currently an editbone) # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) num_frame = 0 for bvh_node in bvh_nodes_list: bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] rest_bone = arm_data.bones[bone_name] bone_rest_matrix = rest_bone.matrix_local.to_3x3() bone_rest_matrix_inv = Matrix(bone_rest_matrix) bone_rest_matrix_inv.invert() bone_rest_matrix_inv.resize_4x4() bone_rest_matrix.resize_4x4() bvh_node.temp = (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) if 0 == num_frame: num_frame = len(bvh_node.anim_data) # Choose to skip some frames at the beginning. Frame 0 is the rest pose # used internally by this importer. Frame 1, by convention, is also often # the rest pose of the skeleton exported by the motion capture system. skip_frame = 1 if num_frame > skip_frame: num_frame = num_frame - skip_frame # Create a shared time axis for all animation curves. time = [float(frame_start)] * num_frame if use_fps_scale: dt = scene.render.fps * bvh_frame_time for frame_i in range(1, num_frame): time[frame_i] += float(frame_i) * dt else: for frame_i in range(1, num_frame): time[frame_i] += float(frame_i) # print("bvh_frame_time = %f, dt = %f, num_frame = %d" # % (bvh_frame_time, dt, num_frame])) for i, bvh_node in enumerate(bvh_nodes_list): pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv = bvh_node.temp if bvh_node.has_loc: # Not sure if there is a way to query this or access it in the # PoseBone structure. data_path = 'pose.bones["%s"].location' % pose_bone.name location = [(0.0, 0.0, 0.0)] * num_frame for frame_i in range(num_frame): bvh_loc = bvh_node.anim_data[frame_i + skip_frame][:3] bone_translate_matrix = Matrix.Translation( Vector(bvh_loc) - bvh_node.rest_head_local) location[frame_i] = (bone_rest_matrix_inv @ bone_translate_matrix).to_translation() # For each location x, y, z. for axis_i in range(3): curve = action.fcurves.new(data_path=data_path, index=axis_i) keyframe_points = curve.keyframe_points keyframe_points.add(num_frame) for frame_i in range(num_frame): keyframe_points[frame_i].co = ( time[frame_i], location[frame_i][axis_i], ) if bvh_node.has_rot: data_path = None rotate = None if 'QUATERNION' == rotate_mode: rotate = [(1.0, 0.0, 0.0, 0.0)] * num_frame data_path = ('pose.bones["%s"].rotation_quaternion' % pose_bone.name) else: rotate = [(0.0, 0.0, 0.0)] * num_frame data_path = ('pose.bones["%s"].rotation_euler' % pose_bone.name) prev_euler = Euler((0.0, 0.0, 0.0)) for frame_i in range(num_frame): bvh_rot = bvh_node.anim_data[frame_i + skip_frame][3:] # apply rotation order and convert to XYZ # note that the rot_order_str is reversed. euler = Euler(bvh_rot, bvh_node.rot_order_str[::-1]) bone_rotation_matrix = euler.to_matrix().to_4x4() bone_rotation_matrix = ( bone_rest_matrix_inv @ bone_rotation_matrix @ bone_rest_matrix) if len(rotate[frame_i]) == 4: rotate[frame_i] = bone_rotation_matrix.to_quaternion() else: rotate[frame_i] = bone_rotation_matrix.to_euler( pose_bone.rotation_mode, prev_euler) prev_euler = rotate[frame_i] # For each euler angle x, y, z (or quaternion w, x, y, z). for axis_i in range(len(rotate[0])): curve = action.fcurves.new(data_path=data_path, index=axis_i) keyframe_points = curve.keyframe_points keyframe_points.add(num_frame) for frame_i in range(num_frame): keyframe_points[frame_i].co = ( time[frame_i], rotate[frame_i][axis_i], ) for cu in action.fcurves: if IMPORT_LOOP: pass # 2.5 doenst have cyclic now? for bez in cu.keyframe_points: bez.interpolation = 'LINEAR' # finally apply matrix arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) return arm_ob
def draw_ig(obj, draw_collision_grid): if "collisionStartX" not in obj.keys(): return startX = obj["collisionStartX"] startY = -obj["collisionStartY"] stepX = obj["collisionStepX"] stepY = -obj["collisionStepY"] stepCountX = obj["collisionStepCountX"] stepCountY = obj["collisionStepCountY"] conveyorEndPos = (obj["conveyorX"] * 40, obj["conveyorZ"] * -40, obj["conveyorY"] * 40) # Draw collision grid gpu.matrix.push() if obj.animation_data is not None and obj.animation_data.action is not None: action = obj.animation_data.action start_frame = bpy.context.scene.frame_start current_frame = bpy.context.scene.frame_current pos_delta = Vector((0, 0, 0)) rot_mode = obj.rotation_mode rot_delta = Euler((0, 0, 0), rot_mode) for i in range(3): if action.fcurves.find("location", index=i): c = action.fcurves.find("location", index=i) delta = c.evaluate(current_frame) - c.evaluate(start_frame) pos_delta[i] = delta if action.fcurves.find("rotation_euler", index=i): c = action.fcurves.find("rotation_euler", index=i) delta = c.evaluate(current_frame) - c.evaluate(start_frame) rot_delta[i] = delta grid_mtx_rot = rot_delta.to_matrix().to_4x4() grid_mtx_pos = Matrix.Translation(pos_delta) grid_mtx = grid_mtx_pos @ grid_mtx_rot gpu.matrix.multiply_matrix(grid_mtx) bgl.glLineWidth(2) if draw_collision_grid: draw_grid(startX, startY, stepX, stepY, stepCountX, stepCountY, 0, COLOR_GREEN_FAINT) gpu.matrix.pop() # Draw conveyor arrow conveyorObjects = [ child for child in obj.children if child.data is not None ] if obj.data is not None: conveyorObjects.append(obj) for conveyorObject in conveyorObjects: gpu.matrix.push() gpu.matrix.multiply_matrix(conveyorObject.matrix_world) if 0 not in conveyorObject.scale: gpu.matrix.scale( (1 / conveyorObject.scale.x, 1 / conveyorObject.scale.y, 1 / conveyorObject.scale.z)) # No scaling lineWidth = [(6, COLOR_BLACK), (2, COLOR_GREEN)] for (width, color) in lineWidth: coords = [ZERO_VEC, conveyorEndPos] bgl.glLineWidth(width) draw_batch(coords, color, 'LINES') gpu.matrix.pop()
def _get_bone_channels(scs_root_obj, armature, scs_animation, action, export_scale): """Takes armature and action and returns bone channels. bone_channels structure example: [("Bone", [("_TIME", [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]), ("_MATRIX", [])])]""" bone_channels = [] frame_start = scs_animation.anim_start frame_end = scs_animation.anim_end anim_export_step = action.scs_props.anim_export_step total_frames = (frame_end - frame_start) / anim_export_step # armature matrix stores transformation of armature object against scs root # and has to be added to all bones as they only armature space transformations armature_mat = scs_root_obj.matrix_world.inverted() * armature.matrix_world invalid_data = False # flag to indicate invalid data state curves_per_bone = OrderedDict( ) # store all the curves we are interested in per bone names for bone in armature.data.bones: for fcurve in action.fcurves: # check if curve belongs to bone if '["' + bone.name + '"]' in fcurve.data_path: data_path = fcurve.data_path array_index = fcurve.array_index if data_path.endswith("location"): curve_type = "location" elif data_path.endswith("rotation_euler"): curve_type = "euler_rotation" elif data_path.endswith("rotation_quaternion"): curve_type = "quat_rotation" elif data_path.endswith("scale"): curve_type = "scale" else: curve_type = None # write only recognized curves if curve_type is not None: if bone.name not in curves_per_bone: curves_per_bone[bone.name] = { "location": {}, "euler_rotation": {}, "quat_rotation": {}, "scale": {} } curves_per_bone[ bone.name][curve_type][array_index] = fcurve for bone_name, bone_curves in curves_per_bone.items(): bone = armature.data.bones[bone_name] pose_bone = armature.pose.bones[bone_name] loc_curves = bone_curves["location"] euler_rot_curves = bone_curves["euler_rotation"] quat_rot_curves = bone_curves["quat_rotation"] sca_curves = bone_curves["scale"] bone_rest_mat = armature_mat * bone.matrix_local if bone.parent: parent_bone_rest_mat = ( Matrix.Scale(export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * armature_mat * bone.parent.matrix_local) else: parent_bone_rest_mat = Matrix() # GO THOUGH FRAMES actual_frame = frame_start timings_stream = [] matrices_stream = [] while actual_frame <= frame_end: mat_loc = Matrix() mat_rot = Matrix() mat_sca = Matrix() # LOCATION MATRIX if len(loc_curves) > 0: location = Vector() for index in range(3): if index in loc_curves: location[index] = loc_curves[index].evaluate( actual_frame) mat_loc = Matrix.Translation(location) # ROTATION MATRIX if len(euler_rot_curves) > 0: rotation = Euler() for index in range(3): if index in euler_rot_curves: rotation[index] = euler_rot_curves[index].evaluate( actual_frame) mat_rot = Euler(rotation, pose_bone.rotation_mode).to_matrix( ).to_4x4() # calc rotation by pose rotation mode elif len(quat_rot_curves) > 0: rotation = Quaternion() for index in range(4): if index in quat_rot_curves: rotation[index] = quat_rot_curves[index].evaluate( actual_frame) mat_rot = rotation.to_matrix().to_4x4() # SCALE MATRIX if len(sca_curves) > 0: scale = Vector((1.0, 1.0, 1.0)) for index in range(3): if index in sca_curves: scale[index] = sca_curves[index].evaluate(actual_frame) if scale[index] < 0: lprint( str("E Negative scale detected on bone %r:\n\t " "(Action: %r, keyframe no.: %s, SCS Animation: %r)." ), (bone_name, action.name, actual_frame, scs_animation.name)) invalid_data = True mat_sca = Matrix() mat_sca[0] = (scale[0], 0, 0, 0) mat_sca[1] = (0, scale[2], 0, 0) mat_sca[2] = (0, 0, scale[1], 0) mat_sca[3] = (0, 0, 0, 1) # BLENDER FRAME MATRIX mat = mat_loc * mat_rot * mat_sca # SCALE REMOVAL MATRIX rest_location, rest_rotation, rest_scale = bone_rest_mat.decompose( ) # print(' BONES rest_scale: %s' % str(rest_scale)) rest_scale = rest_scale * export_scale scale_removal_matrix = Matrix() scale_removal_matrix[0] = (1.0 / rest_scale[0], 0, 0, 0) scale_removal_matrix[1] = (0, 1.0 / rest_scale[1], 0, 0) scale_removal_matrix[2] = (0, 0, 1.0 / rest_scale[2], 0) scale_removal_matrix[3] = (0, 0, 0, 1) # SCALE MATRIX scale_matrix = Matrix.Scale(export_scale, 4) # COMPUTE SCS FRAME MATRIX frame_matrix = (parent_bone_rest_mat.inverted() * _convert_utils.scs_to_blend_matrix().inverted() * scale_matrix.inverted() * bone_rest_mat * mat * scale_removal_matrix.inverted()) # print(' actual_frame: %s - value: %s' % (actual_frame, frame_matrix)) timings_stream.append( ("__time__", scs_animation.length / total_frames), ) matrices_stream.append(("__matrix__", frame_matrix.transposed()), ) actual_frame += anim_export_step anim_timing = ("_TIME", timings_stream) anim_matrices = ("_MATRIX", matrices_stream) bone_anim = (anim_timing, anim_matrices) bone_data = (bone_name, bone_anim) bone_channels.append(bone_data) # return empty bone channels if data are invalid if invalid_data: return [] return bone_channels
def import_animations(mdl: MdlV44, armature, scale): bpy.ops.object.select_all(action="DESELECT") armature.select_set(True) bpy.context.view_layer.objects.active = armature bpy.ops.object.mode_set(mode='POSE') if not armature.animation_data: armature.animation_data_create() # for var_pos in ['XYZ', 'YXZ', ]: # for var_rot in ['XYZ', 'XZY', 'YZX', 'ZYX', 'YXZ', 'ZXY', ]: for var_pos in ['XYZ']: for var_rot in ['XYZ']: for anim_desc in mdl.anim_descs: anim_name = f'pos_{var_pos}_rot_{var_rot}_{anim_desc.name}' action = bpy.data.actions.new(anim_name) armature.animation_data.action = action curve_per_bone = {} for bone in anim_desc.anim_bones: if bone.bone_id == -1: continue bone_name = mdl.bones[bone.bone_id].name bone_string = f'pose.bones["{bone_name}"].' group = action.groups.new(name=bone_name) pos_curves = [] rot_curves = [] for i in range(3): pos_curve = action.fcurves.new(data_path=bone_string + "location", index=i) pos_curve.keyframe_points.add(anim_desc.frame_count) pos_curves.append(pos_curve) pos_curve.group = group for i in range(3): # rot_curve = action.fcurves.new(data_path=bone_string + "rotation_quaternion", index=i) rot_curve = action.fcurves.new(data_path=bone_string + "rotation_euler", index=i) rot_curve.keyframe_points.add(anim_desc.frame_count) rot_curves.append(rot_curve) rot_curve.group = group curve_per_bone[bone_name] = pos_curves, rot_curves for bone in anim_desc.anim_bones: if bone.bone_id == -1: continue mdl_bone = mdl.bones[bone.bone_id] bl_bone = armature.pose.bones.get(mdl_bone.name) bl_bone.rotation_mode = 'XYZ' pos_scale = mdl_bone.position_scale rot_scale = mdl_bone.rotation_scale if bone.is_raw_pos: pos_frames = [ Vector( np.multiply(np.multiply(bone.pos, pos_scale), scale)) ] elif bone.is_anim_pos: pos_frames = [ Vector( np.multiply(np.multiply(pos, pos_scale), scale)) for pos in bone.pos_anim ] else: pos_frames = [] if bone.is_raw_rot: rot_frames = [ Euler( np.multiply( Quaternion(bone.quat).to_euler('XYZ'), rot_scale)) ] elif bone.is_anim_rot: rot_frames = [ Euler(np.multiply(rot, rot_scale)) for rot in bone.vec_rot_anim ] else: rot_frames = [] pos_curves, rot_curves = curve_per_bone[mdl_bone.name] for n, pos_frame in enumerate(pos_frames): pos = __swap_components(pos_frame, var_pos) for i in range(3): pos_curves[i].keyframe_points.add(1) pos_curves[i].keyframe_points[-1].co = (n, pos[i]) for n, rot_frame in enumerate(rot_frames): fixed_rot = rot_frame if mdl_bone.parent_bone_index == -1: fixed_rot.x += math.radians(-90) fixed_rot.y += math.radians(180) fixed_rot.z += math.radians(-90) fixed_rot = Euler(__swap_components( fixed_rot, var_rot)) # qx = Quaternion([1, 0, 0], fixed_rot[0]) # qy = Quaternion([0, 1, 0], -fixed_rot[1]) # qz = Quaternion([0, 0, 1], -fixed_rot[2]) # fixed_rot: Euler = (qx @ qy @ qz).to_euler() # fixed_rot.x += mdl_bone.rotation[0] # fixed_rot.y += mdl_bone.rotation[1] # fixed_rot.z += mdl_bone.rotation[2] fixed_rot.rotate( Euler([ math.radians(90), math.radians(0), math.radians(0) ])) fixed_rot.rotate( Euler([ math.radians(0), math.radians(0), math.radians(90) ])) fixed_rot = ( fixed_rot.to_matrix().to_4x4() @ bl_bone.rotation_euler.to_matrix().to_4x4() ).to_euler() for i in range(3): rot_curves[i].keyframe_points.add(1) rot_curves[i].keyframe_points[-1].co = ( n, fixed_rot[i]) bpy.ops.object.mode_set(mode='OBJECT')
def get_top_mesh(context, prefs): me = context.blend_data.meshes.new("temp_mesh") bm = bmesh.new() bm.from_mesh(me) mat = Matrix() tt = prefs.lp_Tree_Type if tt == "lp_Tree_Oak": mat.translation = (0, 0, prefs.trunk_depth) tsmin = prefs.lp_Tree_Top_Scale_Min tsmax = prefs.lp_Tree_Top_Scale_Max mat[0][0], mat[1][1], mat[2][2] = ( uniform(tsmin[0], tsmax[0]), uniform(tsmin[1], tsmax[1]), uniform(tsmin[2], tsmax[2]), ) bmesh.ops.create_icosphere(bm, subdivisions=prefs.lp_Tree_Top_Subdivisions, diameter=1.0, matrix=mat) elif tt == "lp_Tree_Pine": segments = get_random(prefs.lp_Tree_Top_Stage_Segments_Min, prefs.lp_Tree_Top_Stage_Segments_Max) stages = get_random(prefs.lp_Tree_Top_Stages_Min, prefs.lp_Tree_Top_Stages_Max) td = prefs.trunk_depth - 0.7 sstep = uniform(prefs.lp_Tree_Top_Stage_Step_Min, prefs.lp_Tree_Top_Stage_Step_Max) ssmin = prefs.lp_Tree_Top_Stage_Size_Min ssmax = prefs.lp_Tree_Top_Stage_Size_Max ssize = (uniform(ssmin[0], ssmax[0]), uniform(ssmin[1], ssmax[1]), uniform(ssmin[2], ssmax[2])) for i in range(0, stages): mult = prefs.lp_Tree_Top_Stage_Shrink_Multiplier * (i / 4) sc = (1 - i * prefs.lp_Tree_Top_Stage_Shrink * mult) * 0.9 if sc < 0.01: sc = 0.01 mat[0][0], mat[1][1], mat[2][2] = (sc * ssize[0], sc * ssize[1], sc * ssize[2]) mat.translation = (0, 0, (td + ((ssize[2] - 1) / 2) + i * sstep) * 0.85) if prefs.lp_Tree_Top_Rotate_Stages: e = Euler((0, 0, uniform(0, 3.14)), "XYZ") mat = mat * e.to_matrix().to_4x4() bmesh.ops.create_cone( bm, cap_ends=True, cap_tris=True, segments=segments, diameter1=(prefs.lp_Tree_Top_Stage_Diameter), diameter2=0, depth=(0.85), matrix=mat, ) mat = Matrix() elif tt == "lp_Tree_Palm": trunk_length = prefs.palm_stage_length * prefs.palm_stages leaf_length = get_random(prefs.lp_Tree_Palm_Top_Leaf_Length_Min, prefs.lp_Tree_Palm_Top_Leaf_Length_Max) leaf_size = uniform(prefs.lp_Tree_Palm_Top_Leaf_Size_Min, prefs.lp_Tree_Palm_Top_Leaf_Size_Max) mat.translation = (0, 0, trunk_length) leaves = get_random(prefs.lp_Tree_Palm_Top_Leaves_Min, prefs.lp_Tree_Palm_Top_Leaves_Max) bmesh.ops.create_cone( bm, cap_ends=True, cap_tris=True, segments=leaves, diameter1=leaf_size, diameter2=leaf_size, depth=0.1, matrix=mat, ) faces = bm.faces[:] for face in faces: nor = face.normal # Asume normalized normal dir = (nor.x * 0.3, nor.y * 0.3, -0.12) if nor.z == 0: for i in range(0, leaf_length): r = bmesh.ops.extrude_discrete_faces(bm, faces=[face]) bmesh.ops.translate(bm, vec=dir, verts=r["faces"][0].verts) face = r["faces"][0] dir = (dir[0], dir[1], dir[2] - 0.08) # Align last face verts mid = [0, 0, 0] for v in face.verts: mid[0] += v.co.x mid[1] += v.co.y mid[2] += v.co.z mid[0] /= len(face.verts) mid[1] /= len(face.verts) mid[2] /= len(face.verts) for v in face.verts: v.co.x, v.co.y, v.co.z = mid[0], mid[1], mid[2] bm.to_mesh(me) return me
def __init__(self, name, root, length, chord, incidence, twist, taper, sweep, dihedral): # transform angles to rad sweep *= DEG2RAD twist *= DEG2RAD dihedral *= DEG2RAD incidence *=DEG2RAD # find out if it's a symetric element self.is_symetric = not name.startswith("YASim_vstab") # create the wing mesh object # the wing is first created at ORIGIN w/o incidence/dihedral base = ORIGIN basefore = ORIGIN + 0.5 * chord * X baseaft = ORIGIN - 0.5 * chord * X tip = ORIGIN + (math.cos(sweep) * length * Y) - (math.sin(sweep) * length * X) tipfore = tip + (0.5 * taper * chord * math.cos(twist) * X) + (0.5 * taper * chord * math.sin(twist) * Z) tipaft = tip + tip - tipfore # <1--0--2 # \ | / # 4-3-5 wing_obj = mesh_create(name, ORIGIN, [base, basefore, baseaft, tip, tipfore, tipaft], [], [(0, 1, 4, 3), (2, 0, 3, 5)]) # now transform the mesh # set the created object active !!!!!!! bpy.context.scene.objects.active = wing_obj # get the active mesh mesh = bpy.context.object.data # create a rotation matrix, for dihedral and incidence rotation e = Euler((dihedral, -incidence, 0)) m1 = e.to_matrix() m = m1.to_4x4() # rotate it mesh.transform(m) mesh.update() # position the object #wing_obj.location = root # use the matrix to position it wing_obj.matrix_world = Matrix.Translation(root) # assign materials if self.is_symetric: Item.set_material('tgreen-1', (0.0,0.5,0.0), 0.5) Symetric.list_append(wing_obj) else: Item.set_material('tred-1', (0.5,0.0,0.0), 0.5) # write out the vars for the flaps self.baseaft = baseaft self.tipaft = tipaft self.base = base self.wing_obj = wing_obj self.mesh_matrix = m
def _get_bone_channels(scs_root_obj, armature, scs_animation, action, export_scale): """Takes armature and action and returns bone channels. bone_channels structure example: [("Bone", [("_TIME", [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]), ("_MATRIX", [])])]""" bone_channels = [] frame_start = scs_animation.anim_start frame_end = scs_animation.anim_end anim_export_step = action.scs_props.anim_export_step total_frames = (frame_end - frame_start) / anim_export_step # armature matrix stores transformation of armature object against scs root # and has to be added to all bones as they only armature space transformations armature_mat = scs_root_obj.matrix_world.inverted() * armature.matrix_world invalid_data = False # flag to indicate invalid data state curves_per_bone = {} # store all the curves we are interested in per bone names for bone in armature.data.bones: for fcurve in action.fcurves: # check if curve belongs to bone if '["' + bone.name + '"]' in fcurve.data_path: data_path = fcurve.data_path array_index = fcurve.array_index if data_path.endswith("location"): curve_type = "location" elif data_path.endswith("rotation_euler"): curve_type = "euler_rotation" elif data_path.endswith("rotation_quaternion"): curve_type = "quat_rotation" elif data_path.endswith("scale"): curve_type = "scale" else: curve_type = None # write only recognized curves if curve_type is not None: if bone.name not in curves_per_bone: curves_per_bone[bone.name] = { "location": {}, "euler_rotation": {}, "quat_rotation": {}, "scale": {} } curves_per_bone[bone.name][curve_type][array_index] = fcurve for bone_name, bone_curves in curves_per_bone.items(): bone = armature.data.bones[bone_name] pose_bone = armature.pose.bones[bone_name] loc_curves = bone_curves["location"] euler_rot_curves = bone_curves["euler_rotation"] quat_rot_curves = bone_curves["quat_rotation"] sca_curves = bone_curves["scale"] bone_rest_mat = armature_mat * bone.matrix_local if bone.parent: parent_bone_rest_mat = (Matrix.Scale(export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * armature_mat * bone.parent.matrix_local) else: parent_bone_rest_mat = Matrix() # GO THOUGH FRAMES actual_frame = frame_start timings_stream = [] matrices_stream = [] while actual_frame <= frame_end: mat_loc = Matrix() mat_rot = Matrix() mat_sca = Matrix() # LOCATION MATRIX if len(loc_curves) > 0: location = Vector() for index in range(3): if index in loc_curves: location[index] = loc_curves[index].evaluate(actual_frame) mat_loc = Matrix.Translation(location) # ROTATION MATRIX if len(euler_rot_curves) > 0: rotation = Euler() for index in range(3): if index in euler_rot_curves: rotation[index] = euler_rot_curves[index].evaluate(actual_frame) mat_rot = Euler(rotation, pose_bone.rotation_mode).to_matrix().to_4x4() # calc rotation by pose rotation mode elif len(quat_rot_curves) > 0: rotation = Quaternion() for index in range(4): if index in quat_rot_curves: rotation[index] = quat_rot_curves[index].evaluate(actual_frame) mat_rot = rotation.to_matrix().to_4x4() # SCALE MATRIX if len(sca_curves) > 0: scale = Vector((1.0, 1.0, 1.0)) for index in range(3): if index in sca_curves: scale[index] = sca_curves[index].evaluate(actual_frame) if scale[index] < 0: lprint(str("E Negative scale detected on bone %r:\n\t " "(Action: %r, keyframe no.: %s, SCS Animation: %r)."), (bone_name, action.name, actual_frame, scs_animation.name)) invalid_data = True mat_sca = Matrix() mat_sca[0] = (scale[0], 0, 0, 0) mat_sca[1] = (0, scale[2], 0, 0) mat_sca[2] = (0, 0, scale[1], 0) mat_sca[3] = (0, 0, 0, 1) # BLENDER FRAME MATRIX mat = mat_loc * mat_rot * mat_sca # SCALE REMOVAL MATRIX rest_location, rest_rotation, rest_scale = bone_rest_mat.decompose() # print(' BONES rest_scale: %s' % str(rest_scale)) rest_scale = rest_scale * export_scale scale_removal_matrix = Matrix() scale_removal_matrix[0] = (1.0 / rest_scale[0], 0, 0, 0) scale_removal_matrix[1] = (0, 1.0 / rest_scale[1], 0, 0) scale_removal_matrix[2] = (0, 0, 1.0 / rest_scale[2], 0) scale_removal_matrix[3] = (0, 0, 0, 1) # SCALE MATRIX scale_matrix = Matrix.Scale(export_scale, 4) # COMPUTE SCS FRAME MATRIX frame_matrix = (parent_bone_rest_mat.inverted() * _convert_utils.scs_to_blend_matrix().inverted() * scale_matrix.inverted() * bone_rest_mat * mat * scale_removal_matrix.inverted()) # print(' actual_frame: %s - value: %s' % (actual_frame, frame_matrix)) timings_stream.append(("__time__", scs_animation.length / total_frames), ) matrices_stream.append(("__matrix__", frame_matrix.transposed()), ) actual_frame += anim_export_step anim_timing = ("_TIME", timings_stream) anim_matrices = ("_MATRIX", matrices_stream) bone_anim = (anim_timing, anim_matrices) bone_data = (bone_name, bone_anim) bone_channels.append(bone_data) # return empty bone channels if data are invalid if invalid_data: return [] return bone_channels