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 generate_mtl_files(_config, materials=None): print() if materials is None: materials = get_materials(_config.export_selected_nodes) for node in get_material_groups(materials): _doc = Document() parent_material = _doc.createElement('Material') parent_material.setAttribute("MtlFlags", "524544") parent_material.setAttribute("vertModifType", "0") sub_material = _doc.createElement('SubMaterials') parent_material.appendChild(sub_material) set_public_params(_doc, None, parent_material) for material, material_name in materials.items(): if material_name.split('__')[0] != node: continue material_node = _doc.createElement('Material') set_material_attributes(material, material_name, material_node) add_textures(_doc, material, material_node, _config) set_public_params(_doc, material, material_node) sub_material.appendChild(material_node) _doc.appendChild(parent_material) filename = "{!s}.mtl".format(node) filepath = os.path.join(os.path.dirname(_config.filepath), filename) utils.generate_xml(filepath, _doc, True, 1) utils.clear_xml_header(filepath) bcPrint("'{}' material file has been generated.".format(filename))
def __remove_tmp_files(self): for tmp_image in self.__tmp_images: try: bcPrint("Removing tmp image: {!r}".format(tmp_image), 'debug') os.remove(tmp_image) except FileNotFoundError: pass os.removedirs(self.__tmp_dir) self.__tmp_images.clear()
def fix_weights(): for object_ in get_type("skins"): override = get_3d_context(object_) try: bpy.ops.object.vertex_group_normalize_all(override, lock_active=False) except: raise exceptions.BCryException( "Please fix weightless vertices first.") bcPrint("Weights Corrected.")
def _process_bone_weights(self, object_, armature, skin_node): bones = utils.get_bones(armature) group_weights = [] vw = "" vertex_groups_lengths = "" vertex_count = 0 bone_list = {} for bone_id, bone in enumerate(bones): bone_list[bone.name] = bone_id for vertex in object_.data.vertices: vertex_group_count = 0 for group in vertex.groups: group_name = object_.vertex_groups[group.group].name if (group.weight == 0 or group_name not in bone_list): continue if vertex_group_count == 8: bcPrint("Too many bone references in {}:{} vertex group" .format(object_.name, group_name)) continue group_weights.append(group.weight) vw = "{}{} {} ".format(vw, bone_list[group_name], vertex_count) vertex_count += 1 vertex_group_count += 1 vertex_groups_lengths = "{}{} ".format(vertex_groups_lengths, vertex_group_count) id_ = "{!s}_{!s}-weights".format(armature.name, object_.name) source = utils.write_source(id_, "float", group_weights, []) skin_node.appendChild(source) vertex_weights = self._doc.createElement("vertex_weights") vertex_weights.setAttribute("count", str(len(object_.data.vertices))) id_ = "{!s}_{!s}".format(armature.name, object_.name) input = utils.write_input(id_, 0, "joints", "JOINT") vertex_weights.appendChild(input) input = utils.write_input(id_, 1, "weights", "WEIGHT") vertex_weights.appendChild(input) vcount = self._doc.createElement("vcount") vcount_text = self._doc.createTextNode(vertex_groups_lengths) vcount.appendChild(vcount_text) vertex_weights.appendChild(vcount) v = self._doc.createElement("v") v_text = self._doc.createTextNode(vw) v.appendChild(v_text) vertex_weights.appendChild(v) skin_node.appendChild(vertex_weights)
def set_keyframes(armature, location_list, rotation_list): '''Insert each keyframe from lists.''' bpy.context.scene.frame_set(bpy.context.scene.frame_start) for frame in range(bpy.context.scene.frame_start, bpy.context.scene.frame_end + 1): set_keyframe(armature, frame, location_list, rotation_list) bpy.context.scene.frame_set(bpy.context.scene.frame_start) bcPrint("Keyframes have been inserted to armature fakebones.")
def apply_modifiers(just_selected=False): print() for node in get_export_nodes(just_selected): for object_ in node.objects: bpy.context.scene.objects.active = object_ for modifier in object_.modifiers: if modifier.type == 'ARMATURE': continue mod_name = modifier.name bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod_name) bcPrint("Modifiers are applied for {} node.".format(node.name))
def __load(self, current_configuration): new_configuration = {} new_configuration.update(self.__DEFAULT_CONFIGURATION) new_configuration.update(current_configuration) if os.path.isfile(self.__CONFIG_FILEPATH): try: with open(self.__CONFIG_FILEPATH, 'rb') as f: new_configuration.update(pickle.load(f)) bcPrint('Configuration file loaded.') except: bcPrint("[IO] can not read: {}".format(self.__CONFIG_FILEPATH), 'error') return new_configuration
def _write_uvs(self, object_, bmesh_, mesh_node, geometry_name): uv_layer = bmesh_.loops.layers.uv.active if object_.data.uv_layers.active is None: bcPrint( "{} object has no a UV map, creating a default UV...".format( object_.name)) uv_layer = bmesh_.loops.layers.uv.new() float_uvs = [] for face in bmesh_.faces: for loop in face.loops: float_uvs.extend(loop[uv_layer].uv) id_ = "{!s}-uvs".format(geometry_name) source = utils.write_source(id_, "float", float_uvs, "ST") mesh_node.appendChild(source)
def _create_physic_proxy_for_bone(self, object_, bone): extra = None try: bonePhys = object_.pose.bones[bone.name]['phys_proxy'] bcPrint(bone.name + " physic proxy is " + bonePhys) extra = self._doc.createElement("extra") techcry = self._doc.createElement("technique") techcry.setAttribute("profile", "CryEngine") prop2 = self._doc.createElement("properties") cryprops = self._doc.createTextNode(bonePhys) prop2.appendChild(cryprops) techcry.appendChild(prop2) extra.appendChild(techcry) except: pass return extra
def save(self): bcPrint("Saving configuration file.", 'debug') if os.path.isdir(self.__CONFIG_PATH): try: with open(self.__CONFIG_FILEPATH, 'wb') as f: pickle.dump(self.__CONFIG, f, -1) bcPrint("Configuration file saved.") bcPrint('Saved {}'.format(self.__CONFIG_FILEPATH)) except: bcPrint( "[IO] can not write: {}".format(self.__CONFIG_FILEPATH), 'error') else: bcPrint( "Configuration file path is missing {}".format( self.__CONFIG_PATH), 'error')
def trim_path_to(path, trim_to): path_normalized = normalize_path(path) components = path_normalized.split("/") for index, component in enumerate(components): if component == trim_to: bcPrint("FOUND AN INSTANCE") break bcPrint(index) components_trimmed = components[index:] bcPrint(components_trimmed) path_trimmed = build_path(*components_trimmed) bcPrint(path_trimmed) return path_trimmed
def __call__(self): for image in self.__images_to_convert: rc_params = self.__get_rc_params(image.filepath) tiff_image_path = self.__get_temp_tiff_image_path(image) tiff_image_for_rc = utils.get_absolute_path_for_rc(tiff_image_path) bcPrint(tiff_image_for_rc) try: self.__create_normal_texture() except: bcPrint("Failed to invert green channel") rc_process = run_rc(self.__config.texture_rc_path, tiff_image_for_rc, rc_params) # re-save the original image after running the RC to # prevent the original one from getting lost try: if ("_ddn" in image.name): image.save() except: bcPrint("Failed to invert green channel") rc_process.wait() if self.__config.texture_rc_path: self.__save_tiffs() self.__remove_tmp_files()
def __get_temp_tiff_image_path(self, image): # check if the image already is a .tif image_extension = utils.get_extension_from_path(image.filepath) bcPrint(image_extension) if ".tif" == image_extension: bcPrint( "Image {!r} is already a tif, not converting".format( image.name), 'debug') return image.filepath tiff_image_path = utils.get_path_with_new_extension(image.filepath, "tif") tiff_image_absolute_path = utils.get_absolute_path(tiff_image_path) tiff_file_name = os.path.basename(tiff_image_path) tmp_file_path = os.path.join(self.__tmp_dir, tiff_file_name) if tiff_image_path != image.filepath: self.__save_as_tiff(image, tmp_file_path) self.__tmp_images[tmp_file_path] = (tiff_image_absolute_path) return tmp_file_path
def add_textures(_doc, material, material_node, _config): textures_node = _doc.createElement("Textures") diffuse = get_diffuse_texture(material) specular = get_specular_texture(material) normal = get_normal_texture(material) if diffuse: texture_node = _doc.createElement('Texture') texture_node.setAttribute("Map", "Diffuse") path = get_image_path_for_game(diffuse, _config.game_dir) texture_node.setAttribute("File", path) textures_node.appendChild(texture_node) bcPrint("Diffuse Path: {}.".format(path)) else: if "physProxyNoDraw" != get_material_physic(material.name): texture_node = _doc.createElement('Texture') texture_node.setAttribute("Map", "Diffuse") path = "textures/defaults/white.dds" texture_node.setAttribute("File", path) textures_node.appendChild(texture_node) bcPrint("Diffuse Path: {}.".format(path)) if specular: texture_node = _doc.createElement('Texture') texture_node.setAttribute("Map", "Specular") path = get_image_path_for_game(specular, _config.game_dir) texture_node.setAttribute("File", path) textures_node.appendChild(texture_node) bcPrint("Specular Path: {}.".format(path)) if normal: texture_node = _doc.createElement('Texture') texture_node.setAttribute("Map", "Normal") path = get_image_path_for_game(normal, _config.game_dir) texture_node.setAttribute("File", path) textures_node.appendChild(texture_node) bcPrint("Normal Path: {}.".format(path)) if _config.convert_textures: convert_image_to_dds([diffuse, specular, normal], _config) material_node.appendChild(textures_node)
def run_rc(rc_path, files_to_process, params=None): bcPrint("RC Path: {}".format(os.path.abspath(rc_path)), newline=True) process_params = [rc_path] if isinstance(files_to_process, list): process_params.extend(files_to_process) else: process_params.append(files_to_process) process_params.extend(params) bcPrint("RC Parameters: {}".format(params)) bcPrint("Processing File: {}".format(files_to_process)) try: run_object = subprocess.Popen(process_params) except: raise exceptions.NoRcSelectedException print() return run_object
def apply_animation_scale(armature): '''Apply Animation Scale.''' scene = bpy.context.scene remove_unused_meshes() if armature is None or armature.type != "ARMATURE": return skeleton = armature.data empties = [] deselect_all() scene.frame_set(scene.frame_start) for pose_bone in armature.pose.bones: bmatrix = pose_bone.bone.head_local bpy.ops.object.empty_add(type='PLAIN_AXES', radius=0.1) empty = bpy.context.active_object empty.name = pose_bone.name bpy.ops.object.constraint_add(type='CHILD_OF') bpy.data.objects[ empty.name].constraints['Child Of'].use_scale_x = False bpy.data.objects[ empty.name].constraints['Child Of'].use_scale_y = False bpy.data.objects[ empty.name].constraints['Child Of'].use_scale_z = False bpy.data.objects[empty.name].constraints['Child Of'].target = armature bpy.data.objects[ empty.name].constraints['Child Of'].subtarget = pose_bone.name bcPrint("Baking animation on " + empty.name + "...") bpy.ops.nla.bake(frame_start=scene.frame_start, frame_end=scene.frame_end, step=1, only_selected=True, visual_keying=True, clear_constraints=True, clear_parents=False, bake_types={'OBJECT'}) empties.append(empty) for empty in empties: empty.select = True bcPrint("Baked Animation successfully on empties.") deselect_all() set_active(armature) armature.select = True bpy.ops.anim.keyframe_clear_v3d() bpy.ops.object.transform_apply(rotation=True, scale=True) bpy.ops.object.mode_set(mode='POSE') bpy.ops.pose.user_transforms_clear() for pose_bone in armature.pose.bones: pose_bone.constraints.new(type='COPY_LOCATION') pose_bone.constraints.new(type='COPY_ROTATION') for empty in empties: if empty.name == pose_bone.name: pose_bone.constraints['Copy Location'].target = empty pose_bone.constraints['Copy Rotation'].target = empty break pose_bone.bone.select = True bcPrint("Baking Animation on skeleton...") bpy.ops.nla.bake(frame_start=scene.frame_start, frame_end=scene.frame_end, step=1, only_selected=True, visual_keying=True, clear_constraints=True, clear_parents=False, bake_types={'POSE'}) bpy.ops.object.mode_set(mode='OBJECT') deselect_all() bcPrint("Clearing empty data...") for empty in empties: empty.select = True bpy.ops.object.delete() bcPrint("Apply Animation was completed.")
def _export_library_geometries(self, parent_element): libgeo = self._doc.createElement("library_geometries") parent_element.appendChild(libgeo) for group in utils.get_mesh_export_nodes( self._config.export_selected_nodes): for object_ in group.objects: if object_.type != 'MESH': continue bmesh_, layer_state, scene_layer = utils.get_bmesh(object_) geometry_node = self._doc.createElement("geometry") geometry_name = utils.get_geometry_name(group, object_) geometry_node.setAttribute("id", geometry_name) mesh_node = self._doc.createElement("mesh") print() bcPrint('"{}" object is being processed...'.format( object_.name)) start_time = clock() self._write_positions(bmesh_, mesh_node, geometry_name) bcPrint('Positions have been writed {:.4f} seconds.'.format( clock() - start_time)) start_time = clock() self._write_normals(object_, bmesh_, mesh_node, geometry_name) bcPrint('Normals have been writed {:.4f} seconds.'.format( clock() - start_time)) start_time = clock() self._write_uvs(object_, bmesh_, mesh_node, geometry_name) bcPrint( 'UVs have been writed {:.4f} seconds.'.format(clock() - start_time)) start_time = clock() self._write_vertex_colors(object_, bmesh_, mesh_node, geometry_name) bcPrint( 'Vertex colors have been writed {:.4f} seconds.'.format( clock() - start_time)) start_time = clock() self._write_vertices(mesh_node, geometry_name) bcPrint('Vertices have been writed {:.4f} seconds.'.format( clock() - start_time)) start_time = clock() self._write_triangle_list(object_, bmesh_, mesh_node, geometry_name) bcPrint( 'Triangle list have been writed {:.4f} seconds.'.format( clock() - start_time)) extra = self._create_double_sided_extra("MAYA") mesh_node.appendChild(extra) geometry_node.appendChild(mesh_node) libgeo.appendChild(geometry_node) utils.clear_bmesh(object_, layer_state, scene_layer) bcPrint('"{}" object has been processed for "{}" node.'.format( object_.name, group.name))
def export(self): self._prepare_for_export() root_element = self._doc.createElement('collada') root_element.setAttribute( "xmlns", "http://www.collada.org/2005/11/COLLADASchema") root_element.setAttribute("version", "1.4.1") self._doc.appendChild(root_element) self._create_file_header(root_element) libanmcl = self._doc.createElement("library_animation_clips") libanm = self._doc.createElement("library_animations") root_element.appendChild(libanmcl) root_element.appendChild(libanm) lib_visual_scene = self._doc.createElement("library_visual_scenes") visual_scene = self._doc.createElement("visual_scene") visual_scene.setAttribute("id", "scene") visual_scene.setAttribute("name", "scene") lib_visual_scene.appendChild(visual_scene) root_element.appendChild(lib_visual_scene) initial_frame_active = bpy.context.scene.frame_current initial_frame_start = bpy.context.scene.frame_start initial_frame_end = bpy.context.scene.frame_end ALLOWED_NODE_TYPES = ("i_caf", "anm") for group in utils.get_animation_export_nodes(): node_type = utils.get_node_type(group) node_name = utils.get_node_name(group) if node_type in ALLOWED_NODE_TYPES: object_ = None layers = None if node_type == 'i_caf': object_ = utils.get_armature_from_node(group) layers = utils.activate_all_bone_layers(object_) elif node_type == 'anm': object_ = group.objects[0] frame_start, frame_end = utils.get_animation_node_range( object_, node_name, initial_frame_start, initial_frame_end) bpy.context.scene.frame_start = frame_start bpy.context.scene.frame_end = frame_end print('') bcPrint(group.name) bcPrint("Animation is being preparing to process.") bcPrint("Animation frame range are [{} - {}]".format( frame_start, frame_end)) if node_type == 'i_caf': utils.add_fakebones(group) try: self._export_library_animation_clips_and_animations( libanmcl, libanm, group) self._export_library_visual_scenes(visual_scene, group) except RuntimeError: pass finally: if node_type == 'i_caf': utils.remove_fakebones() utils.recover_bone_layers(object_, layers) bcPrint("Animation has been processed.") bpy.context.scene.frame_current = initial_frame_active bpy.context.scene.frame_start = initial_frame_start bpy.context.scene.frame_end = initial_frame_end print('') self._export_scene(root_element) converter = RCInstance(self._config) converter.convert_dae(self._doc)
def write_material_information(material_name): parts = material_name.split('__') bcPrint("Subname: '{}' - Index: '{}' - Physic Type: '{}'".format( parts[2], parts[1], parts[3]))
def __save_tiffs(self): for tmp_image, dest_image in self.__tmp_images.items(): bcPrint("Moving tmp image: {!r} to {!r}".format(tmp_image, dest_image), 'debug') shutil.move(tmp_image, dest_image)