Fusion/UE5_blender_script.py

283 lines
11 KiB
Python
Raw Permalink Normal View History

2023-11-12 15:09:22 +00:00
import bpy
import os
import xml.etree.ElementTree as ET
def custom_print(*args):
message = ' '.join(map(str, args))
for window in bpy.context.window_manager.windows:
screen = window.screen
for area in screen.areas:
if area.type == 'CONSOLE':
override = {'window': window, 'screen': screen, 'area': area}
bpy.ops.console.scrollback_append(override, text=message, type="OUTPUT")
2023-11-12 15:09:22 +00:00
for material in bpy.data.materials:
bpy.data.materials.remove(material, do_unlink=True)
for mesh in bpy.data.meshes:
bpy.data.meshes.remove(mesh, do_unlink=True)
for image in bpy.data.images:
bpy.data.images.remove(image, do_unlink=True)
# Set the input and output directories
wherethefilesare = 'output' # Set where the files are located from PD2ModelParser.exe
wheretosave = 'done' # Where you want to save the fixed files.
wherethetexturesare = 'textures' # Set where all the files are located
# Get the parent directory of the python file
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir = os.path.abspath(os.path.join(dir_path, os.pardir))
# Make valid folder paths using os.path.join
input_directory = os.path.join(parent_dir, wherethefilesare)
output_directory = os.path.join(parent_dir, wheretosave)
texture_directory = os.path.join(parent_dir, wherethetexturesare)
custom_print("Input Directory:", input_directory)
custom_print("Output Directory:", output_directory)
custom_print("Texture Directory:", texture_directory)
2023-11-12 15:09:22 +00:00
def get_object_filepath(file_path):
# Replace the extension with .object
object_file_path = os.path.splitext(file_path)[0] + '.object'
return object_file_path
def set_diffuse_texture_as_base_color(material, texture_path):
# Create an image texture node
texture_node = material.node_tree.nodes.new(type='ShaderNodeTexImage')
texture_node.image = bpy.data.images.load(texture_path)
# Get the principled BSDF shader node
principled_bsdf = material.node_tree.nodes.get("Principled BSDF")
# Connect the texture node to the base color input of the principled BSDF shader node
material.node_tree.links.new(principled_bsdf.inputs["Base Color"], texture_node.outputs["Color"])
def process_xml_file(file_path):
try:
# Open the file and read its contents
with open(file_path, 'r') as file:
file_contents = file.read()
# Parse the XML string
root = ET.fromstring(file_contents)
# Find the value of the 'materials' attribute
materials_value = root.find('.//diesel').get('materials')
# custom_print the result
custom_print(f"The value of 'materials' is: {materials_value}")
2023-11-12 15:09:22 +00:00
# return the materials_value
return materials_value
except Exception as e:
custom_print(f"Error processing XML file: {e}")
2023-11-12 15:09:22 +00:00
return None
def get_diffuse_texture_name(xml_file_path, material_name):
"""
Extracts the name of the texture in <diffuse_texture> for a given material name in an XML file.
Parameters:
- xml_file_path (str): The path to the XML file.
- material_name (str): The name of the material to search for.
Returns:
- str: The name of the texture if the material is found, else None.
"""
try:
# Parse the XML file
tree = ET.parse(xml_file_path)
root = tree.getroot()
# Find the material with the specified name
target_material = root.find(f".//material[@name='{material_name}']")
if target_material is not None:
# Find the 'diffuse_texture' element within the material
diffuse_texture_element = target_material.find("diffuse_texture")
if diffuse_texture_element is not None:
# Get the value of the 'file' attribute in <diffuse_texture> and extract the texture name
diffuse_texture_path = diffuse_texture_element.get("file")
texture_name = diffuse_texture_path.split("/")[-1] # Extracting the texture name from the file path
return f"{texture_name}.dds"
else:
custom_print(f"Diffuse texture not found for material '{material_name}' in the XML file.")
2023-11-12 15:09:22 +00:00
return None
else:
custom_print(f"Material '{material_name}' not found in the XML file.")
2023-11-12 15:09:22 +00:00
return None
except FileNotFoundError:
custom_print(f"File not found: {xml_file_path}")
2023-11-12 15:09:22 +00:00
return None
except Exception as e:
custom_print(f"Error while processing {xml_file_path}: {e}")
2023-11-12 15:09:22 +00:00
return None
# Main function to process the object
def process_gltf(file_path):
# Get the filename without extension
file_name = os.path.splitext(os.path.basename(file_path))[0]
# Clear existing mesh objects in the scene
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# Import the GLTF file
bpy.ops.import_scene.gltf(filepath=file_path)
# Deselect all objects
bpy.ops.object.select_all(action='DESELECT')
# Find the mesh with the highest poly count
max_poly_count = 0
object_with_max_poly_count = None
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and len(obj.data.polygons) > max_poly_count:
max_poly_count = len(obj.data.polygons)
object_with_max_poly_count = obj
# Select the parent (root) object of the object with the highest poly count
if object_with_max_poly_count:
root_object = object_with_max_poly_count.parent
if root_object:
root_object.select_set(True)
# Set the 3D cursor as the pivot point for the transformation
bpy.context.scene.tool_settings.transform_pivot_point = 'CURSOR'
# Set the location of the selected object to the 3D cursor
root_object.location = bpy.context.scene.cursor.location
# Set the transform rotation mode to XYZ Euler
root_object.rotation_mode = 'XYZ'
# Add the specified rotation to the object
root_object.rotation_euler[0] = -1.5708 # X-axis rotation, -90 degrees in radians
root_object.rotation_euler[1] = 0 # Y-axis rotation, 0 degrees in radians
root_object.rotation_euler[2] = 0 # Z-axis rotation, 0 degrees in radians
# Select all objects in the scene
bpy.ops.object.select_all(action='SELECT')
# Apply all transforms to the selected objects
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
# Select meshes that start with the name "g_"
bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.context.scene.objects:
if obj.type == 'MESH' and obj.name.startswith("g_"):
obj.select_set(True)
# Invert the selection and delete the unselected objects
bpy.ops.object.select_all(action='INVERT')
bpy.ops.object.delete()
# Join remaining objects together
bpy.ops.object.select_all(action='DESELECT')
#Mesh objects
MSH_OBJS = [m for m in bpy.context.scene.objects if m.type == 'MESH']
# Check if there are any objects in the list
if MSH_OBJS:
for OBJS in MSH_OBJS:
# Select all mesh objects
OBJS.select_set(state=True)
# Makes one active
bpy.context.view_layer.objects.active = OBJS
# Joins objects
bpy.ops.object.join()
# Rename the object to the filename
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type='MESH')
bpy.context.selected_objects[0].name = file_name
# Get mat config
object_file_path = get_object_filepath(file_path)
material_config = process_xml_file(object_file_path)
# Loop each material slot get the name
for material_slot in bpy.context.selected_objects[0].material_slots:
# Get the material in the current slot
material = material_slot.material
# Get the material name
material_name = material.name
# Initialize the variable with a default value
diffuse_texture_name = None
# Get the diffuse texture name using get_diffuse_texture_name()
# Makes this not hardcoded
if material_config is not None:
get_material_config_path = material_config.replace("units/", f"{input_directory}/") + ".material_config"
2023-11-12 15:09:22 +00:00
diffuse_texture_name = get_diffuse_texture_name(get_material_config_path, material_name)
else:
custom_print("Material config is None. Handle this case accordingly.")
2023-11-12 15:09:22 +00:00
# CRASHES WHEN IT CANT FIND THE FILES TO LAZY TO FIX IT JUST HAVE THE FILES
# Check if the texture exists
if diffuse_texture_name:
# Construct the full path to the texture
texture_path = os.path.join(texture_directory, diffuse_texture_name)
# Check if the texture file exists before trying to load it
if os.path.exists(texture_path):
# Set the diffuse texture as the base color
set_diffuse_texture_as_base_color(material, texture_path)
else:
custom_print(f"Texture not found for material {material_name}: {texture_path}")
2023-11-12 15:09:22 +00:00
else:
custom_print(f"No diffuse texture found for material {material_name}")
2023-11-12 15:09:22 +00:00
# Ensure the output directory exists
output_path = os.path.join(output_directory, os.path.relpath(file_path, start=input_directory))
os.makedirs(os.path.dirname(output_path), exist_ok=True)
# Select all objects in the scene
bpy.ops.object.select_all(action='SELECT')
# Export as .gltf to the output directory
bpy.ops.export_scene.gltf(filepath=output_path, export_format='GLTF_EMBEDDED', use_selection=True)
# Remove materials and meshes
for material in bpy.data.materials:
bpy.data.materials.remove(material, do_unlink=True)
for mesh in bpy.data.meshes:
bpy.data.meshes.remove(mesh, do_unlink=True)
for image in bpy.data.images:
bpy.data.images.remove(image, do_unlink=True)
else:
custom_print("No objects selected.")
2023-11-12 15:09:22 +00:00
for material in bpy.data.materials:
bpy.data.materials.remove(material, do_unlink=True)
for mesh in bpy.data.meshes:
bpy.data.meshes.remove(mesh, do_unlink=True)
for image in bpy.data.images:
bpy.data.images.remove(image, do_unlink=True)
# Recursive function to process all .gltf files in a directory
def process_directory(directory):
for root, dirs, files in os.walk(directory):
for file in files:
if file.lower().endswith('.gltf'):
file_path = os.path.join(root, file)
process_gltf(file_path)
# Start processing from the input directory
process_directory(input_directory)