Optimized Texture Scripts futher
This commit is contained in:
@@ -2,6 +2,8 @@ import os
|
||||
import sys
|
||||
from PIL import Image # type: ignore
|
||||
import time
|
||||
import concurrent.futures
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
# Define suffix lists for BaseColor, Normal, RMA/ORM
|
||||
BASECOLOR_SUFFIXES = ['_alb.', '_albedo.', '_bc.', '_basecolor.', '_b.']
|
||||
@@ -44,6 +46,25 @@ def get_material_name(filename):
|
||||
# Return the base_name without the suffix for output naming
|
||||
return base_name.rsplit('_', 1)[0] # Split only at the last underscore
|
||||
|
||||
def convert_single_material(material_data: Tuple[str, Dict[str, str]], output_folder: str) -> Tuple[bool, str]:
|
||||
"""Convert a single material to BCR/NMO format"""
|
||||
material, files = material_data
|
||||
basecolor_file = files.get('BaseColor')
|
||||
normal_file = files.get('Normal')
|
||||
rma_file = files.get('RMA')
|
||||
orm_file = files.get('ORM')
|
||||
emissive_file = files.get('Emissive')
|
||||
opacity_file = files.get('Opacity')
|
||||
mask_file = files.get('Mask')
|
||||
|
||||
try:
|
||||
if convert_to_bcr_nmo(material, basecolor_file, normal_file, rma_file, orm_file, emissive_file, opacity_file, mask_file, output_folder):
|
||||
return True, f"{material}: Successfully converted."
|
||||
else:
|
||||
return False, f"Skipping {material}: input file sizes do not match."
|
||||
except Exception as e:
|
||||
return False, f"Error processing {material}: {str(e)}"
|
||||
|
||||
def process_textures(input_files):
|
||||
""" Main function to process all textures in a folder and convert to BCR/NMO """
|
||||
textures = {}
|
||||
@@ -62,46 +83,53 @@ def process_textures(input_files):
|
||||
base_path = os.path.dirname(input_files[0])
|
||||
output_folder = os.path.join(base_path, 'merged')
|
||||
os.makedirs(output_folder, exist_ok=True)
|
||||
|
||||
|
||||
material_count = len(textures)
|
||||
print(f"Detected {material_count} Materials to process.")
|
||||
|
||||
# Check for required textures and filter out incomplete materials
|
||||
valid_materials = {}
|
||||
failed_converts = 0
|
||||
|
||||
# Process each material group
|
||||
for index, (material, files) in enumerate(textures.items()):
|
||||
basecolor_file = files.get('BaseColor')
|
||||
normal_file = files.get('Normal')
|
||||
rma_file = files.get('RMA')
|
||||
orm_file = files.get('ORM')
|
||||
emissive_file = files.get('Emissive')
|
||||
opacity_file = files.get('Opacity')
|
||||
mask_file = files.get('Mask')
|
||||
|
||||
|
||||
for material, files in textures.items():
|
||||
missing_files = []
|
||||
|
||||
# Check for required textures
|
||||
if not basecolor_file:
|
||||
if not files.get('BaseColor'):
|
||||
missing_files.append('BaseColor')
|
||||
if not normal_file:
|
||||
if not files.get('Normal'):
|
||||
missing_files.append('Normal')
|
||||
if not (rma_file or orm_file):
|
||||
if not (files.get('RMA') or files.get('ORM')):
|
||||
missing_files.append('RMA or ORM')
|
||||
|
||||
# Report missing files if any
|
||||
if missing_files:
|
||||
print(f"({index + 1}/{material_count}) Skipping {material}: missing {', '.join(missing_files)}")
|
||||
print(f"Skipping {material}: missing {', '.join(missing_files)}")
|
||||
failed_converts += 1
|
||||
else:
|
||||
# Convert to BCR/NMO format and track success or failure
|
||||
|
||||
if convert_to_bcr_nmo(material, basecolor_file, normal_file, rma_file, orm_file, emissive_file, opacity_file, mask_file, output_folder):
|
||||
print(f"({index + 1}/{material_count}) {material}: Successfully converted.")
|
||||
else:
|
||||
failed_converts += 1 # Increment counter here if conversion fails
|
||||
print(f"({index + 1}/{material_count}) Skipping {material}: input file sizes do not match.")
|
||||
|
||||
print(f"+++{material_count - failed_converts} of {material_count} materials successfully converted+++")
|
||||
valid_materials[material] = files
|
||||
|
||||
# Process materials in parallel
|
||||
success_count = 0
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
# Submit all materials for processing
|
||||
future_to_material = {
|
||||
executor.submit(convert_single_material, (material, files), output_folder): material
|
||||
for material, files in valid_materials.items()
|
||||
}
|
||||
|
||||
# Process results as they complete
|
||||
for future in concurrent.futures.as_completed(future_to_material):
|
||||
material = future_to_material[future]
|
||||
try:
|
||||
success, message = future.result()
|
||||
if success:
|
||||
success_count += 1
|
||||
else:
|
||||
failed_converts += 1
|
||||
print(message)
|
||||
except Exception as e:
|
||||
failed_converts += 1
|
||||
print(f"Error processing {material}: {str(e)}")
|
||||
|
||||
print(f"+++{success_count} of {material_count} materials successfully converted+++")
|
||||
time.sleep(3)
|
||||
|
||||
def convert_to_bcr_nmo(material, basecolor_file, normal_file, rma_file, orm_file, emissive_file, opacity_file, mask_file, output_folder):
|
||||
@@ -115,32 +143,41 @@ def convert_to_bcr_nmo(material, basecolor_file, normal_file, rma_file, orm_file
|
||||
return False
|
||||
# BCR conversion
|
||||
bcr_img = Image.merge('RGBA', (basecolor_img.split()[0], basecolor_img.split()[1], basecolor_img.split()[2], rma_img.split()[0])) # Use Roughness (Alpha from RMA/ORM)
|
||||
bcr_img.save(os.path.join(output_folder, f"{material}_BCR.png"))
|
||||
bcr_img.save(os.path.join(output_folder, f"{material}_BCR.tga"))
|
||||
# NMO conversion
|
||||
nmo_img = Image.merge('RGBA', (normal_img.split()[0], normal_img.split()[1], rma_img.split()[1], rma_img.split()[2])) # Use Metallic, AO from RMA/ORM
|
||||
nmo_img.save(os.path.join(output_folder, f"{material}_NMO.png"))
|
||||
nmo_img.save(os.path.join(output_folder, f"{material}_NMO.tga"))
|
||||
elif orm_file:
|
||||
rma_img = Image.open(orm_file).convert('RGBA')
|
||||
if not (basecolor_img.size == normal_img.size == rma_img.size):
|
||||
return False
|
||||
# BCR conversion
|
||||
bcr_img = Image.merge('RGBA', (basecolor_img.split()[0], basecolor_img.split()[1], basecolor_img.split()[2], rma_img.split()[1])) # Use Roughness (Alpha from RMA/ORM)
|
||||
bcr_img.save(os.path.join(output_folder, f"{material}_BCR.png"))
|
||||
bcr_img.save(os.path.join(output_folder, f"{material}_BCR.tga"))
|
||||
# NMO conversion
|
||||
nmo_img = Image.merge('RGBA', (normal_img.split()[0], normal_img.split()[1], rma_img.split()[2], rma_img.split()[0])) # Use Metallic, AO from RMA/ORM
|
||||
nmo_img.save(os.path.join(output_folder, f"{material}_NMO.png"))
|
||||
nmo_img.save(os.path.join(output_folder, f"{material}_NMO.tga"))
|
||||
# Optionally handle emissive and opacity maps
|
||||
if emissive_file:
|
||||
emissive_img = Image.open(emissive_file).convert('RGB')
|
||||
emissive_img.save(os.path.join(output_folder, f"{material}_EM.png"))
|
||||
emissive_img = Image.open(emissive_file)
|
||||
# Preserve original color mode instead of forcing RGB
|
||||
if emissive_img.mode != 'RGBA':
|
||||
emissive_img = emissive_img.convert('RGBA')
|
||||
emissive_img.save(os.path.join(output_folder, f"{material}_EM.tga"))
|
||||
|
||||
if opacity_file:
|
||||
opacity_img = Image.open(opacity_file).convert('L')
|
||||
opacity_img.save(os.path.join(output_folder, f"{material}_OP.png"))
|
||||
opacity_img = Image.open(opacity_file)
|
||||
# Preserve original color mode instead of forcing grayscale
|
||||
if opacity_img.mode != 'RGBA':
|
||||
opacity_img = opacity_img.convert('RGBA')
|
||||
opacity_img.save(os.path.join(output_folder, f"{material}_OP.tga"))
|
||||
|
||||
if mask_file:
|
||||
mask_img = Image.open(mask_file).convert('L')
|
||||
mask_img.save(os.path.join(output_folder, f"{material}_MASK.png"))
|
||||
mask_img = Image.open(mask_file)
|
||||
# Preserve original color mode instead of forcing grayscale
|
||||
if mask_img.mode != 'RGBA':
|
||||
mask_img = mask_img.convert('RGBA')
|
||||
mask_img.save(os.path.join(output_folder, f"{material}_MASK.tga"))
|
||||
|
||||
return True
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user