Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
OpenSim (O)RM Map Generator
#1
OpenSim (O)RM Map Generator
ORM Materialien spiegeln die eigenschaft eines Materials wieder.
Beispiel: Jeans Stoff kann für mehrere Jeans, Schuhe oder Mobillar genutzt werden egal welche Farbe diese Objekte haben es zählt nur die Grundstruktur.

Funktion: Programm starten - Ordner auswählen der Texturen - von zum Beispiel freepbr enthält - dann generieren - und sie werden alle gespeichert.

Python Beispiel:
PHP-Code:
import os
import tkinter 
as tk
from tkinter import filedialog
, messagebox, ttk
from PIL import Image
import glob
import threading

class ORMGeneratorGUI:
    
def __init__(self, root):
        
self.root = root
        self
.root.title("OpenSim (O)RM Map Generator")
        
self.root.geometry("600x400")
        
        
# Variablen
        
self.input_dir = tk.StringVar()
        
self.output_dir = tk.StringVar()
        
self.progress = tk.DoubleVar()
        
self.status = tk.StringVar(value="Bereit")
        
        
self.setup_ui()
    
    
def setup_ui(self):
        
# Hauptframe
        
main_frame = ttk.Frame(self.root, padding="10")
        
main_frame.grid(row=0, column=0, sticky="nsew")
        
        
# Root-Fenster Grid-Konfiguration
        
self.root.columnconfigure(0, weight=1)
        
self.root.rowconfigure(0, weight=1)
        
        
# Titel
        
title_label = ttk.Label(main_frame, text="OpenSim (O)RM Map Generator", 
                               
font=("Arial", 16, "bold"))
        
title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
        
        
# Eingabe-Verzeichnis Auswahl
        
ttk.Label(main_frame, text="Eingabe-Verzeichnis:").grid(row=1, column=0, sticky=tk.W, pady=5)
        
ttk.Entry(main_frame, textvariable=self.input_dir, width=50).grid(row=1, column=1, padx=5, pady=5)
        
ttk.Button(main_frame, text="Durchsuchen", command=self.browse_input_dir).grid(row=1, column=2, pady=5)
        
        
# Ausgabe-Verzeichnis Auswahl
        
ttk.Label(main_frame, text="Ausgabe-Verzeichnis:").grid(row=2, column=0, sticky=tk.W, pady=5)
        
ttk.Entry(main_frame, textvariable=self.output_dir, width=50).grid(row=2, column=1, padx=5, pady=5)
        
ttk.Button(main_frame, text="Durchsuchen", command=self.browse_output_dir).grid(row=2, column=2, pady=5)
        
        
# Optionen
        
options_frame = ttk.LabelFrame(main_frame, text="Optionen", padding="5")
        
options_frame.grid(row=3, column=0, columnspan=3, sticky="ew", pady=10)
        
        
self.use_height_for_ao = tk.BooleanVar(value=True)
        
ttk.Checkbutton(options_frame, text="Height Map für AO verwenden (falls AO fehlt)", 
                       
variable=self.use_height_for_ao).grid(row=0, column=0, sticky=tk.W)
        
        
self.overwrite_existing = tk.BooleanVar(value=False)
        
ttk.Checkbutton(options_frame, text="Existierende ORM-Maps überschreiben", 
                       
variable=self.overwrite_existing).grid(row=1, column=0, sticky=tk.W)
        
        
# Fortschrittsbalken
        
ttk.Label(main_frame, text="Fortschritt:").grid(row=4, column=0, sticky=tk.W, pady=(10, 0))
        
progress_bar = ttk.Progressbar(main_frame, variable=self.progress, length=500)
        
progress_bar.grid(row=5, column=0, columnspan=3, sticky="ew", pady=5)
        
        
# Status-Anzeige
        
status_label = ttk.Label(main_frame, textvariable=self.status)
        
status_label.grid(row=6, column=0, columnspan=3, pady=5)
        
        
# Buttons
        
button_frame = ttk.Frame(main_frame)
        
button_frame.grid(row=7, column=0, columnspan=3, pady=20)
        
        
ttk.Button(button_frame, text="ORM-Maps generieren", 
                  
command=self.start_generation).pack(side=tk.LEFT, padx=5)
        
ttk.Button(button_frame, text="Beenden", 
                  
command=self.root.quit).pack(side=tk.LEFT, padx=5)
        
        
# Log-Ausgabe
        
log_frame = ttk.LabelFrame(main_frame, text="Log", padding="5")
        
log_frame.grid(row=8, column=0, columnspan=3, sticky="nsew", pady=10)
        
        
self.log_text = tk.Text(log_frame, height=8, width=70)
        
scrollbar = ttk.Scrollbar(log_frame, orient=tk.VERTICAL, command=self.log_text.yview)
        
self.log_text.configure(yscrollcommand=scrollbar.set)
        
        
self.log_text.grid(row=0, column=0, sticky="nsew")
        
scrollbar.grid(row=0, column=1, sticky="ns")
        
        
# Grid-Konfiguration
        
main_frame.columnconfigure(1, weight=1)
        
log_frame.columnconfigure(0, weight=1)
        
log_frame.rowconfigure(0, weight=1)
        
main_frame.rowconfigure(8, weight=1)
    
    
def browse_input_dir(self):
        
directory = filedialog.askdirectory(title="Eingabe-Verzeichnis auswählen")
        if 
directory:
            
self.input_dir.set(directory)
            
# Automatisch Output-Verzeichnis vorschlagen
            
if not self.output_dir.get():
                
self.output_dir.set(os.path.join(directory, "ORM_Maps"))
    
    
def browse_output_dir(self):
        
directory = filedialog.askdirectory(title="Ausgabe-Verzeichnis auswählen")
        if 
directory:
            
self.output_dir.set(directory)
    
    
def log(self, message):
        
self.log_text.insert(tk.END, message + "\n")
        
self.log_text.see(tk.END)
        
self.root.update_idletasks()
    
    
def start_generation(self):
        if 
not self.input_dir.get() or not self.output_dir.get():
            
messagebox.showerror("Fehler", "Bitte Eingabe- und Ausgabe-Verzeichnis auswählen!")
            return
        
        
# In separatem Thread ausführen, um GUI nicht zu blockieren
        
thread = threading.Thread(target=self.generate_orm_maps)
        
thread.daemon = True
        thread
.start()
    
    
def generate_orm_maps(self):
        try:
            
input_dir = self.input_dir.get()
            
output_dir = self.output_dir.get()
            
            
self.status.set("Suche Texturen...")
            
self.progress.set(0)
            
self.log_text.delete(1.0, tk.END)
            
            
# Alle Albedo-Texturen finden (case-insensitive und mit Unterordnern)
            
albedo_files = []
            for 
pattern in ["*_albedo.png", "*_Albedo.png", "*_ALBEDO.png"]:
                
albedo_files.extend(glob.glob(os.path.join(input_dir, pattern)))
                
albedo_files.extend(glob.glob(os.path.join(input_dir, "**", pattern), recursive=True))
            
            
# Duplikate entfernen
            
albedo_files = list(set(albedo_files))
            
            if 
not albedo_files:
                
self.log("Keine _albedo.png Dateien gefunden!")
                
self.log(f"Durchsuchtes Verzeichnis: {input_dir}")
                
                
# Zeige verfügbare PNG-Dateien zur Diagnose
                
all_pngs = glob.glob(os.path.join(input_dir, "*.png"))
                if 
all_pngs:
                    
self.log(f"\nGefundene PNG-Dateien ({len(all_pngs)}):")
                    for 
png in all_pngs[:5]:  # Zeige erste 5
                        
self.log(f"  - {os.path.basename(png)}")
                    if 
len(all_pngs) > 5:
                        
self.log(f"  ... und {len(all_pngs) - 5} weitere")
                
                
self.status.set("Fehler: Keine Texturen gefunden")
                return
            
            
self.log(f"Gefunden: {len(albedo_files)} Textur-Sets")
            
self.log("=" * 50)
            
            
processed = 0
            errors 
= 0
            
            
for i, albedo_file in enumerate(albedo_files):
                
base_name = os.path.basename(albedo_file).replace("_albedo.png", "")
                
                
# Fortschritt aktualisieren
                
progress_percent = (i / len(albedo_files)) * 100
                self
.progress.set(progress_percent)
                
self.status.set(f"Verarbeite: {base_name}")
                
                
# ORM-Map generieren
                
success = self.create_single_orm_map(input_dir, output_dir, base_name)
                
                if 
success:
                    
processed += 1
                
else:
                    
errors += 1
            
            
# Abschluss
            
self.progress.set(100)
            
self.status.set("Fertig!")
            
self.log("=" * 50)
            
self.log(f"Erfolgreich verarbeitet: {processed}")
            
self.log(f"Fehler: {errors}")
            
self.log(f"ORM-Maps gespeichert in: {output_dir}")
            
            
messagebox.showinfo("Fertig", f"Verarbeitung abgeschlossen!\nErfolgreich: {processed}\nFehler: {errors}")
            
        
except Exception as e:
            
self.log(f"FEHLER: {str(e)}")
            
self.status.set("Fehler aufgetreten")
            
messagebox.showerror("Fehler", f"Ein Fehler ist aufgetreten:\n{str(e)}")
    
    
def create_single_orm_map(self, input_dir, output_dir, base_name):
        try:
            
# Datei-Pfade
            
ao_file = os.path.join(input_dir, f"{base_name}_ao.png")
            
roughness_file = os.path.join(input_dir, f"{base_name}_roughness.png")
            
metallic_file = os.path.join(input_dir, f"{base_name}_metallic.png")
            
height_file = os.path.join(input_dir, f"{base_name}_height.png")
            
            
# Output-Pfad
            
output_file = os.path.join(output_dir, f"{base_name}_ORM.png")
            
            
# Überspringen falls bereits existiert
            
if os.path.exists(output_file) and not self.overwrite_existing.get():
                
self.log(f"Übersprungen (existiert): {base_name}")
                return 
True
            
            
# Falls AO fehlt und Height Map verwendet werden soll
            
if self.use_height_for_ao.get() and not os.path.exists(ao_file) and os.path.exists(height_file):
                
self.log(f"  Verwende Height Map für AO: {base_name}")
                
ao_file = height_file
            
            
# Überprüfen ob alle benötigten Dateien existieren
            
missing_files = []
            for 
file_path in [ao_file, roughness_file, metallic_file]:
                if 
not os.path.exists(file_path):
                    
missing_files.append(os.path.basename(file_path))
            
            if 
missing_files:
                
self.log(f"FEHLER {base_name}: Fehlende Dateien - {', '.join(missing_files)}")
                return 
False
            
            
# Bilder laden und verarbeiten
            
ao_img = Image.open(ao_file).convert("L")
            
roughness_img = Image.open(roughness_file).convert("L")
            
metallic_img = Image.open(metallic_file).convert("L")
            
            
# Auf gemeinsame Größe bringen
            
sizes = [img.size for img in [ao_img, roughness_img, metallic_img]]
            
target_size = max(sizes, key=lambda x: x[0] * x[1])
            
            if 
ao_img.size != target_size:
                
ao_img = ao_img.resize(target_size, Image.Resampling.LANCZOS)
            if 
roughness_img.size != target_size:
                
roughness_img = roughness_img.resize(target_size, Image.Resampling.LANCZOS)
            if 
metallic_img.size != target_size:
                
metallic_img = metallic_img.resize(target_size, Image.Resampling.LANCZOS)
            
            
# (O)RM Map kombinieren
            
orm_map = Image.merge("RGB", (ao_img, roughness_img, metallic_img))
            
            
# Speichern
            
os.makedirs(output_dir, exist_ok=True)
            
orm_map.save(output_file, "PNG")
            
            
self.log(f"ERFOLG: {base_name} ({target_size[0]}x{target_size[1]})")
            return 
True
            
        except Exception 
as e:
            
self.log(f"FEHLER {base_name}: {str(e)}")
            return 
False

def main
():
    
root = tk.Tk()
    
ORMGeneratorGUI(root)
    
root.mainloop()

if 
__name__ == "__main__":
    
main() 

Gemischt angezeigt kommt natürlich etwas heraus was merkwürdig aussieht und erst in RGB zerlegt sinn ergibt.
   
Ein Metaversum sind viele kleine Räume, die nahtlos aneinander passen,
sowie direkt sichtbar und begehbar sind, als wäre es aus einem Guss.



Zitieren


Nachrichten in diesem Thema
OpenSim (O)RM Map Generator - von Manfred Aabye - 30.11.2025, 14:53

Möglicherweise verwandte Themen…
Thema Verfasser Antworten Ansichten Letzter Beitrag
  OpenSim Addon-modules Manfred Aabye 0 317 10.08.2026, 13:55
Letzter Beitrag: Manfred Aabye
  Idee BEPU Physics v2 als eigenständiges Physikmodul für OpenSim Manfred Aabye 4 947 07.07.2026, 00:58
Letzter Beitrag: Akira
  Server-Tutorial: Linux und OpenSim Mareta Dagostino 62 124.398 05.04.2026, 11:12
Letzter Beitrag: Pius Noel
  OpenSim Currency Server 2025 Manfred Aabye 13 6.306 31.01.2026, 16:50
Letzter Beitrag: Manfred Aabye
  Anfänger-Anleitung OpenSim Terrain Manfred Aabye 0 1.084 20.12.2025, 11:56
Letzter Beitrag: Manfred Aabye

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste