def get_3x4_RT_matrix_from_blender(cam): from mathutils import Matrix #Todo: additional dependency! not listed in readme # bcam stands for blender camera R_bcam2cv = Matrix(((1, 0, 0), (0, -1, 0), (0, 0, -1))) # Transpose since the rotation is object rotation, # and we want coordinate rotation # R_world2bcam = cam.rotation_euler.to_matrix().transposed() # T_world2bcam = -1*R_world2bcam * location # # Use matrix_world instead to account for all constraints cam = Matrix(cam) location, rotation = cam.decompose()[0:2] R_world2bcam = rotation.to_matrix().transposed() # Convert camera location to translation vector used in coordinate changes # T_world2bcam = -1*R_world2bcam*cam.location # Use location from matrix_world to account for constraints: T_world2bcam = -1 * np.dot(R_world2bcam, location) # Build the coordinate transform matrix from world to computer vision camera R_world2cv = np.dot(R_bcam2cv, R_world2bcam) T_world2cv = np.dot(R_bcam2cv, T_world2bcam) # put into 3x4 matrix RT = np.concatenate( (np.array(R_world2cv), np.array(T_world2cv).reshape(3, 1)), axis=1) return RT
def matrix(mat_input): mat_input = Matrix([mat_input[0:4], mat_input[4:8], mat_input[8:12], mat_input[12:16]]) mat_input.transpose() # Use decompose() here since to_quaternion() for some reasons return a different result for rotation in the tricky case of a negative scale location, rotation, scale = mat_input.decompose() return Conversion.matrix_from_trs(Conversion.location(location), Conversion.matrix_quaternion(rotation), Conversion.scale(scale))
def load_world_node(self, node): content_manager = ContentManager() node_path = node['m_worldNodePrefix'] + '.vwnod_c' full_node_path = content_manager.find_file(node_path) world_node_file = ValveCompiledFile(full_node_path) world_node_file.read_block_info() world_node_file.check_external_resources() world_data: DataBlock = world_node_file.get_data_block( block_name="DATA")[0] collection = get_or_create_collection( f"static_props_{Path(node_path).stem}", self.master_collection) for n, static_object in enumerate(world_data.data['m_sceneObjects']): model_path = static_object['m_renderableModel'] proper_path = world_node_file.available_resources.get(model_path) self.logger.info( f"Loading ({n}/{len(world_data.data['m_sceneObjects'])}){model_path} mesh" ) mat_rows: List = static_object['m_vTransform'] transform_mat = Matrix( [mat_rows[0], mat_rows[1], mat_rows[2], [0, 0, 0, 1]]) loc, rot, sca = transform_mat.decompose() custom_data = { 'prop_path': str(proper_path), 'type': 'static_prop', 'scale': self.scale, 'entity': static_object, 'skin': static_object.get('skin', 'default') or 'default' } self.create_empty(proper_path.stem, loc, rot.to_euler(), sca, parent_collection=collection, custom_data=custom_data)
def get_keyframes(armature): '''Get each bone location and rotation for each frame.''' location_list = [] rotation_list = [] for frame in range(bpy.context.scene.frame_start, bpy.context.scene.frame_end + 1): bpy.context.scene.frame_set(frame) locations = {} rotations = {} for bone in armature.pose.bones: bone_matrix = transform_animation_matrix(bone.matrix) if bone.parent and bone.parent.parent: parent_matrix = transform_animation_matrix(bone.parent.matrix) bone_matrix = parent_matrix.inverted() * bone_matrix elif not bone.parent: bone_matrix = Matrix() loc, rot, scl = bone_matrix.decompose() locations[bone.name] = loc rotations[bone.name] = rot.to_euler() location_list.append(locations.copy()) rotation_list.append(rotations.copy()) del locations del rotations bcPrint("Keyframes have been appended to lists.") return location_list, rotation_list
def draw_decomposed_matrix(self, label: str, matrix: Matrix) -> None: (trans, rot, scale) = matrix.decompose() col = self.layout.column(align=False) col.label(text=label) def nicenum(num: float) -> str: if abs(num) < 1e-3: return "-" return f"{num:.3f}" def nicescale(num: float) -> str: if abs(1.0 - num) < 1e-3: return "-" return f"{num:.3f}" grid = col.grid_flow(row_major=True, columns=4, align=True) grid.label(text="T") grid.label(text=nicenum(trans.x)) grid.label(text=nicenum(trans.y)) grid.label(text=nicenum(trans.z)) grid.label(text="R") grid.label(text=nicenum(rot.x)) grid.label(text=nicenum(rot.y)) grid.label(text=nicenum(rot.z)) grid.label(text="S") grid.label(text=nicescale(scale.x)) grid.label(text=nicescale(scale.y)) grid.label(text=nicescale(scale.z))
def swap_coordinate_system(matrix_world: mathutils.Matrix, mesh: Union[bpy.types.Mesh, bmesh.types.BMesh], is_swap: bool) -> None: swap_mat = mathutils.Matrix.Identity(4) if is_swap: swap_mat[0][0], swap_mat[0][1], swap_mat[0][2], swap_mat[0][ 3] = 1, 0, 0, 0 swap_mat[1][0], swap_mat[1][1], swap_mat[1][2], swap_mat[1][ 3] = 0, 0, 1, 0 swap_mat[2][0], swap_mat[2][1], swap_mat[2][2], swap_mat[2][ 3] = 0, 1, 0, 0 swap_mat[3][0], swap_mat[3][1], swap_mat[3][2], swap_mat[3][ 3] = 0, 0, 0, 1 trans, rot, scale = matrix_world.decompose() if type(mesh) is bpy.types.Mesh: for vertex in mesh.vertices: vertex.co = swap_mat * matrix_world * vertex.co vertex.normal = ( swap_mat * matrix_world).to_3x3().normalized() * vertex.normal if is_swap: mesh.flip_normals() if type(mesh) is bmesh.types.BMesh: for vertex in mesh.verts: vertex.co = swap_mat * matrix_world * vertex.co vertex.normal = ( swap_mat * matrix_world).to_3x3().normalized() * vertex.normal if is_swap: for face in mesh.faces: face.normal_flip()
def baby_from_blender(mat: Matrix) -> Matrix: t, qr, s = mat.decompose() out = ( Matrix.Translation(swizzle_yup_location(t) * Vector([-1, 1, 1])) @ # swizzle_yup_rotation(qr).to_matrix().to_4x4() @ # any_scale(swizzle_yup_scale(s))) out.transpose() return out
def getTranslationOrientation(ob, file): if isinstance(ob, bpy.types.Bone): ob_matrix_local = ob.matrix_local.copy() ob_matrix_local.transpose() t = ob_matrix_local ob_matrix_local = Matrix([[-t[2][0], -t[2][1], -t[2][2], -t[2][3]], [t[1][0], t[1][1], t[1][2], t[1][3]], [t[0][0], t[0][1], t[0][2], t[0][3]], [t[3][0], t[3][1], t[3][2], t[3][3]]]) rotMatrix_z90_4x4 = Matrix.Rotation(math.radians(90.0), 4, 'Z') rotMatrix_z90_4x4.transpose() file.write('Name:%s\n' % ob.name) t = rotMatrix_z90_4x4 * ob_matrix_local matrix = Matrix([[t[0][0], t[0][1], t[0][2], t[0][3]], [t[1][0], t[1][1], t[1][2], t[1][3]], [t[2][0], t[2][1], t[2][2], t[2][3]], [t[3][0], t[3][1], t[3][2], t[3][3]]]) parent = ob.parent if parent: parent_matrix_local = parent.matrix_local.copy() parent_matrix_local.transpose() t = parent_matrix_local parent_matrix_local = Matrix([[-t[2][0], -t[2][1], -t[2][2], -t[2][3]], [t[1][0], t[1][1], t[1][2], t[1][3]], [t[0][0], t[0][1], t[0][2], t[0][3]], [t[3][0], t[3][1], t[3][2], t[3][3]]]) par_matrix = rotMatrix_z90_4x4 * parent_matrix_local par_matrix_cpy = par_matrix.copy() par_matrix_cpy.invert() matrix = matrix * par_matrix_cpy matrix.transpose() loc, rot, sca = matrix.decompose() else: matrix = ob.matrix_world if matrix: loc, rot, sca = matrix.decompose() else: raise "error: this should never happen!" return loc, rot
def getTranslationOrientation(ob): if isinstance(ob, bpy.types.Bone): ob_matrix_local = ob.matrix_local.copy() ob_matrix_local.transpose() t = ob_matrix_local ob_matrix_local = Matrix([[-t[2][0], -t[2][1], -t[2][2], -t[2][3]], [t[1][0], t[1][1], t[1][2], t[1][3]], [t[0][0], t[0][1], t[0][2], t[0][3]], [t[3][0], t[3][1], t[3][2], t[3][3]]]) rotMatrix_z90_4x4 = Matrix.Rotation(math.radians(90.0), 4, 'Z') rotMatrix_z90_4x4.transpose() t = rotMatrix_z90_4x4 * ob_matrix_local matrix = Matrix([[t[0][0], t[0][1], t[0][2], t[0][3]], [t[1][0], t[1][1], t[1][2], t[1][3]], [t[2][0], t[2][1], t[2][2], t[2][3]], [t[3][0], t[3][1], t[3][2], t[3][3]]]) parent = ob.parent if parent: parent_matrix_local = parent.matrix_local.copy() parent_matrix_local.transpose() t = parent_matrix_local parent_matrix_local = Matrix( [[-t[2][0], -t[2][1], -t[2][2], -t[2][3]], [t[1][0], t[1][1], t[1][2], t[1][3]], [t[0][0], t[0][1], t[0][2], t[0][3]], [t[3][0], t[3][1], t[3][2], t[3][3]]]) par_matrix = rotMatrix_z90_4x4 * parent_matrix_local par_matrix_cpy = par_matrix.copy() par_matrix_cpy.invert() matrix = matrix * par_matrix_cpy matrix.transpose() loc, rot, sca = matrix.decompose() else: matrix = ob.matrix_world if matrix: loc, rot, sca = matrix.decompose() else: raise "error: this should never happen!" return loc, rot
def get_trs(node): if 'matrix' in node: m = node['matrix'] # column-major to row-major m = Matrix([m[0:4], m[4:8], m[8:12], m[12:16]]) m.transpose() (loc, rot, sca) = m.decompose() else: sca = node.get('scale', [1.0, 1.0, 1.0]) rot = node.get('rotation', [0.0, 0.0, 0.0, 1.0]) rot = [rot[3], rot[0], rot[1], rot[2]] # xyzw -> wxyz loc = node.get('translation', [0.0, 0.0, 0.0]) # Switch glTF coordinates to Blender coordinates sca = [sca[0], sca[2], sca[1]] rot = [rot[0], rot[1], -rot[3], rot[2]] loc = [loc[0], -loc[2], loc[1]] return (Vector(loc), Quaternion(rot), Vector(sca))
def draw_decomposed_matrix(self, label: str, matrix: Matrix) -> None: (trans, rot, scale) = matrix.decompose() col = self.layout.column(align=False) col.label(text=label) grid = col.grid_flow(row_major=True, columns=4, align=True) grid.label(text="T") grid.label(text=self.nicenum(trans.x)) grid.label(text=self.nicenum(trans.y)) grid.label(text=self.nicenum(trans.z)) grid.label(text="R") grid.label(text=self.nicenum(rot.x)) grid.label(text=self.nicenum(rot.y)) grid.label(text=self.nicenum(rot.z)) grid.label(text="S") grid.label(text=self.nicescale(scale.x)) grid.label(text=self.nicescale(scale.y)) grid.label(text=self.nicescale(scale.z))
def assignFrame(self, armature, frameNum, excludeFingers): # this is REQUIRED to get something to actually get recorded other than just before assignment bpy.context.scene.update() for name in KINECT_BONES: if excludeFingers and self.isFinger(name): continue if name not in armature.data.bones: continue bone = armature.pose.bones[name] objectSpace = bone.matrix localSpace = Matrix(armature.convert_space(bone, objectSpace, 'POSE', 'LOCAL')) loc, rot, scale = localSpace.decompose() if name == ROOT_BONE: bone.location = self.relativeRootLoc(frameNum) bone.keyframe_insert('location', frame = frameNum, group = name) bone.rotation_quaternion = rot bone.keyframe_insert('rotation_quaternion', frame = frameNum, group = name)
def get_node_trs(op, node): """Gets the TRS proerties from a glTF node JSON object.""" if 'matrix' in node: m = node['matrix'] # column-major to row-major m = Matrix([m[0:4], m[4:8], m[8:12], m[12:16]]) m.transpose() loc, rot, sca = m.decompose() # wxyz -> xyzw # convert_rotation will switch back rot = [rot[1], rot[2], rot[3], rot[0]] else: sca = node.get('scale', [1.0, 1.0, 1.0]) rot = node.get('rotation', [0.0, 0.0, 0.0, 1.0]) loc = node.get('translation', [0.0, 0.0, 0.0]) # Switch glTF coordinates to Blender coordinates sca = op.convert_scale(sca) rot = op.convert_rotation(rot) loc = op.convert_translation(loc) return [Vector(loc), Quaternion(rot), Vector(sca)]
def assignFrame(self, armature, frameNum, excludeFingers): # this is REQUIRED to get something to actually get recorded other than just before assignment bpy.context.scene.update() for name in KINECT_BONES: if excludeFingers and self.isFinger(name): continue if name not in armature.data.bones: continue bone = armature.pose.bones[name] objectSpace = bone.matrix localSpace = Matrix( armature.convert_space(bone, objectSpace, 'POSE', 'LOCAL')) loc, rot, scale = localSpace.decompose() if name == ROOT_BONE: bone.location = self.relativeRootLoc(frameNum) bone.keyframe_insert('location', frame=frameNum, group=name) bone.rotation_quaternion = rot bone.keyframe_insert('rotation_quaternion', frame=frameNum, group=name)
def se3_get_skeleton_from_file(operator, context): filepath = operator.filepath current_bone = "" bone_data = OrderedDict() is_in_limits = False is_in_pose = False with open(filepath, "r") as file: for line in file: if "SE_SKELETON" in line or "BONES" in line: continue if "NAME" in line: name = line name = name.replace('NAME ', "") name = name.replace('"', "") current_bone = sanitize_name(name) bone_data[current_bone] = { "name": current_bone, "parent": "", "root_bone": False, "matrix": [], "length": 0.0 } if "PARENT" in line: parent = line parent = parent.replace('PARENT ', "") parent = parent.replace('"', "") parent = sanitize_name(parent) if parent is "": bone_data[current_bone]["root_bone"] = True continue else: bone_data[current_bone]["parent"] = parent if "LENGTH" in line: length = line length = length.replace("LENGTH ", "") length = length.replace('"', "") length = sanitize_name(length) bone_data[current_bone]["length"] = float(length) if "LIMITS" in line: is_in_limits = True continue if is_in_limits and "DEFAULT_POSE" not in line: continue if "DEFAULT_POSE" in line: is_in_limits = False is_in_pose = True continue if is_in_pose and "}" not in line: matrix = line bone_data[current_bone]["matrix"] = gen_matrix(matrix) if is_in_pose and "}" in line: is_in_pose = False continue armature_da = bpy.data.armatures.new("Armature") armature_ob = bpy.data.objects.new("Armature", armature_da) armature_ob.show_x_ray = True bpy.context.scene.objects.link(armature_ob) bpy.context.scene.objects.active = armature_ob bpy.ops.object.mode_set(mode='EDIT') ob = bpy.context.object for name, bone in bone_data.items(): print(name) if bone["root_bone"]: m = Matrix() constraints = bone["matrix"] m[0][0:2] = -constraints[0], constraints[2], -constraints[1] m[1][0:2] = constraints[8], -constraints[10], constraints[9] m[2][0:2] = constraints[4], -constraints[6], constraints[5] v = Vector((-constraints[3], constraints[11], constraints[7])) else: m = Matrix() constraints = bone["matrix"] m[0][0:2] = constraints[0], -constraints[2], constraints[1] m[1][0:2] = -constraints[8], constraints[10], -constraints[9] m[2][0:2] = constraints[4], -constraints[6], constraints[5] v = Vector( (constraints[3], -(constraints[11] - bone_data[bone["parent"]]["length"]), constraints[7])) edit_bone = armature_ob.data.edit_bones.new(bone["name"]) edit_bone.matrix = m print(m.decompose()) print(v) print("-------------------") edit_bone.head = v edit_bone.length = bone["length"] if not bone["root_bone"]: edit_bone.parent = armature_ob.data.edit_bones[bone["parent"]] 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 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 add_neutral_bones(self): for n in [ n for n in self.nodes.values() if n.armature is not None and n.blender_type == VExportNode. OBJECT and hasattr(self.nodes[n.armature], "need_neutral_bone") ]: #all skin meshes objects where neutral bone is needed # First add a new node axis_basis_change = Matrix.Identity(4) if self.export_settings[gltf2_blender_export_keys.YUP]: axis_basis_change = Matrix( ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0))) trans, rot, sca = axis_basis_change.decompose() translation, rotation, scale = (None, None, None) if trans[0] != 0.0 or trans[1] != 0.0 or trans[2] != 0.0: translation = [trans[0], trans[1], trans[2]] if rot[0] != 1.0 or rot[1] != 0.0 or rot[2] != 0.0 or rot[3] != 0.0: rotation = [rot[1], rot[2], rot[3], rot[0]] if sca[0] != 1.0 or sca[1] != 1.0 or sca[2] != 1.0: scale = [sca[0], sca[1], sca[2]] neutral_bone = gltf2_io.Node(camera=None, children=None, extensions=None, extras=None, matrix=None, mesh=None, name='neutral_bone', rotation=rotation, scale=scale, skin=None, translation=translation, weights=None) # Add it to child list of armature self.nodes[n.armature].node.children.append(neutral_bone) # Add it to joint list n.node.skin.joints.append(neutral_bone) # Need to add an InverseBindMatrix array = BinaryData.decode_accessor_internal( n.node.skin.inverse_bind_matrices) axis_basis_change = Matrix.Identity(4) if self.export_settings[gltf2_blender_export_keys.YUP]: axis_basis_change = Matrix( ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0))) inverse_bind_matrix = (axis_basis_change @ self.nodes[ n.armature].matrix_world_armature).inverted_safe() matrix = [] for column in range(0, 4): for row in range(0, 4): matrix.append(inverse_bind_matrix[row][column]) array = np.append(array, np.array([matrix]), axis=0) binary_data = gltf2_io_binary_data.BinaryData.from_list( array.flatten(), gltf2_io_constants.ComponentType.Float) n.node.skin.inverse_bind_matrices = gltf2_blender_gather_accessors.gather_accessor( binary_data, gltf2_io_constants.ComponentType.Float, len(array.flatten()) // gltf2_io_constants.DataType.num_elements( gltf2_io_constants.DataType.Mat4), None, None, gltf2_io_constants.DataType.Mat4, self.export_settings)
def create_skeleton(PDX_bone_list): # keep track of bones as we create them bone_list = [None for _ in range(0, len(PDX_bone_list))] # check this skeleton is not already built in the scene matching_rigs = [ get_rig_from_bone_name(clean_imported_name(bone.name)) for bone in PDX_bone_list ] matching_rigs = list(set(rig for rig in matching_rigs if rig)) if len(matching_rigs) == 1: return matching_rigs[0] # temporary name used during creation tmp_rig_name = 'io_pdx_rig' # create the armature datablock armt = bpy.data.armatures.new('armature') armt.name = 'imported_armature' armt.draw_type = 'STICK' # create the object and link to the scene new_rig = bpy.data.objects.new(tmp_rig_name, armt) bpy.context.scene.objects.link(new_rig) bpy.context.scene.objects.active = new_rig new_rig.show_x_ray = True new_rig.select = True bpy.ops.object.mode_set(mode='EDIT') for bone in PDX_bone_list: index = bone.ix[0] transform = bone.tx parent = getattr(bone, 'pa', None) # determine unique bone name # Maya allows non-unique transform names (on leaf nodes) and handles it internally by using | separators unique_name = clean_imported_name(bone.name) # create joint new_bone = armt.edit_bones.new(name=unique_name) new_bone.select = True bone_list[index] = new_bone # connect to parent if parent is not None: parent_bone = bone_list[parent[0]] new_bone.parent = parent_bone new_bone.use_connect = False # determine bone head transform mat = Matrix( ((transform[0], transform[3], transform[6], transform[9]), (transform[1], transform[4], transform[7], transform[10]), (transform[2], transform[5], transform[8], transform[11]), (0.0, 0.0, 0.0, 1.0))) # rescale or recompose matrix so we always import bones at 1.0 scale loc, rot, scale = mat.decompose() try: safemat = Matrix.Scale(1.0 / scale[0], 4) * mat except ZeroDivisionError: # guard against zero scale bones... safemat = Matrix.Translation( loc) * rot.to_matrix().to_4x4() * Matrix.Scale(1.0, 4) # determine avg distance to any children bone_children = [ b for b in PDX_bone_list if getattr(b, 'pa', [None]) == bone.ix ] bone_dists = [] for child in bone_children: child_transform = child.tx c_mat = Matrix( ((child_transform[0], child_transform[3], child_transform[6], child_transform[9]), (child_transform[1], child_transform[4], child_transform[7], child_transform[10]), (child_transform[2], child_transform[5], child_transform[8], child_transform[11]), (0.0, 0.0, 0.0, 1.0))) c_dist = c_mat.to_translation() - safemat.to_translation() bone_dists.append( math.sqrt(c_dist.x**2 + c_dist.y**2 + c_dist.z**2)) avg_dist = 5.0 if bone_children: avg_dist = sum(bone_dists) / len(bone_dists) avg_dist = min(max(1.0, avg_dist), 10.0) # set bone tail offset first new_bone.tail = Vector((0.0, 0.0, 0.1 * avg_dist)) # set matrix directly as this includes bone roll/rotation new_bone.matrix = swap_coord_space( safemat.inverted_safe()) # convert to Blender space # set or correct some bone settings based on hierarchy for bone in bone_list: # Blender culls zero length bones, nudge the tail to ensure we don't create any if bone.length == 0: # FIXME: is this safe? this would affect bone rotation bone.tail += Vector((0, 0, 0.1)) bpy.ops.object.mode_set(mode='OBJECT') bpy.context.scene.update() return new_rig
def iterate_object(export_context: ExportContext, export_dir, out_objects, object: bpy.types.Object, transform: mathutils.Matrix): transform = transform @ object.matrix_basis t, r, s = transform.decompose() transform_attributes = { "position": [t.x, t.y, t.z], "rotation": [r.x, r.y, r.z, r.w], "scale": [s.x, s.y, s.z] } object_attributes = { "transform": transform_attributes, } light_kind_names = { "POINT": "Point", "SUN": "Directional", "SPOT": "Spot", } if object.type == 'LIGHT': print("LIGHT") print(object.data) light = object.data kind = light_kind_names.get(light.type) if not kind: #unsupported print("unsupported light type " + light.type) else: c = light.color object_attributes["light"] = { "color": [c.r, c.g, c.b], "kind": light_kind_names[light.type], "intensity": light.energy, "cutoff_distance": light.cutoff_distance if light.use_custom_distance else -1.0, } if light.type == "SPOT": outer_angle = light.spot_size * 0.5 inner_angle = outer_angle - outer_angle * light.spot_blend object_attributes["light"]["spot"] = { "outer_angle": outer_angle, "inner_angle": inner_angle } if object.instance_collection: library = object.instance_collection.library if not library: raise rafx_errors.RafxPrefabSceneUnsupportedObject("Collection instance {} must be linked from external file".format(object.instance_collection)) # HACK HACK HACK: Assume that the blender file only contains one model, and its scene name matches the filename. # The alternative is linking the blend file, iterating over all scenes and trying to find the one that contains # the given collection. do_export_external_model does this library_export_path = rafx_blender_paths.find_base_export_path_for_data_block(export_context.project_settings, object.instance_collection) library_path = bpy.path.abspath(library.filepath) library_name = os.path.basename(library_path) model_name, ext = os.path.splitext(library_name) model_name = "{}.blender_model".format(model_name) f = os.path.join(library_export_path, model_name) collection_export_path = rafx_blender_paths.make_cross_platform_relative_path(f, export_dir) object_attributes["model"] = { "model": collection_export_path } if object.type == 'MESH': if export_context.export_properties.enable_mesh_export: export_mesh.export(export_context, object) if export_context.export_properties.enable_model_export: export_model.export_model_for_mesh_object(export_context, object) model_path = rafx_blender_paths.find_export_path_for_blender_data_block_with_extension(export_context.project_settings, object, "blender_model") model_path = rafx_blender_paths.make_cross_platform_relative_path(model_path, export_dir) object_attributes["model"] = { "model": model_path } out_objects.append(object_attributes)
def transform_matrix_blender_to_gmd(matrix: Matrix) -> Matrix: pos, rot, scale = matrix.decompose() pos, rot, scale = transform_blender_to_gmd(pos, rot, scale) return transform_to_matrix(pos, rot, scale)
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'}