Rock Gen 2.18.0: Material-Slots, Praefix Rock, Warnung bei zu grobem Erz-Mesh

Drei Rueckmeldungen von der Spielseite abgearbeitet.

1) Fehlende Material-Slots
   "Material zuweisen" stand auf Standard AUS, deshalb kamen alle Proben mit
   mats: [] an - Unreal legt dann nur einen Default-Slot an und die
   eingefrorene Konvention M_Rock_<Sorte> greift nicht. Jetzt Standard AN.
   Normale Steine rotieren durch M_Rock_Granite/Basalt/Sandstone/Mossy, das
   Erzfels-Set bekommt einen NEUTRALEN Slot M_Rock_Ore - ein Set fuer alle
   Erzsorten, die Sorte macht die Material-Instanz.

2) Namens-Drift Fels_ statt Rock_
   War ein Versehen, keine Absicht: der Standard-Praefix stammte noch aus der
   ersten Fassung, bevor die Konvention Rock_<Set>_<Groesse>_<NN> stand. Der
   Erz-Set-Knopf setzte "Rock" schon selbst, der allgemeine Standard nicht.
   Standard ist jetzt "Rock" - keine Asset-Zwillinge, keine Migration noetig.

3) Erzfelsen mit ~870 statt ~2700 Tris
   Nachgestellt: aus den Werkseinstellungen liefert der Set-Knopf 2590-2690
   Tris, die Automatik greift also. ~870 entstehen genau dann, wenn man den
   Erz-Haken setzt und den NORMALEN Erzeugen-Knopf nimmt - Werkseinstellung ist
   Decimate 0.20/0.50 statt 0.40/0.80. Das ist eine Bedienluecke, kein Fehler
   in der Automatik: die Dichte wird bewusst nur ueber den Set-Knopf gesetzt,
   damit niemandem seine Einstellungen unterm Hintern weggezogen werden.
   Deshalb warnt der Operator jetzt, wenn mit Erz-Haken ein Mesh unter 800
   Verts entsteht, und nennt den Knopf "Smooth & dicht" beim Namen. Sonst
   faellt das erst in UE auf und sieht dort nach einem Material-Fehler aus.

Tests halten den Vertrag jetzt fest: Auslieferungszustand (assign_material an,
Praefix Rock), neutraler Erz-Slot, Sorten-Slots bei normalen Steinen.
17 Tests bestehen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 14:08:21 +02:00
co-authored by Claude Opus 4.8
parent a2d46424ec
commit f996832d75
9 changed files with 123 additions and 25 deletions
+47 -1
View File
@@ -34,6 +34,16 @@ for o in list(bpy.data.objects):
bpy.data.objects.remove(o, do_unlink=True)
s = bpy.context.scene.rock_gen_settings
# Auslieferungszustand festhalten, BEVOR der Test etwas verstellt: die
# Material-Zuweisung muss standardmaessig AN sein, sonst kommt in UE nur ein
# Default-Slot an und die Konvention M_Rock_<Sorte> greift nicht.
if not s.assign_material:
fails.append("assign_material ist im Auslieferungszustand aus - dann fehlt "
"der Material-Slot und die UE-Skripte koennen nicht mappen")
if s.name_prefix != "Rock":
fails.append("Standard-Praefix ist '%s', die eingefrorene Konvention "
"verlangt 'Rock'" % s.name_prefix)
s.use_modal = False
s.assign_material = False
s.generate_lods = False
@@ -110,7 +120,7 @@ for o in list(bpy.data.objects):
bpy.data.objects.remove(o, do_unlink=True)
s.batch_count = 2
s.subsurf_levels = 4 # absichtlich duenn: das Set muss selbst dicht stellen
s.name_prefix = "Fels"
s.name_prefix = "Fels" # absichtlich abweichend: das Set muss selbst umstellen
s.name_form = "A"
s.name_class = 'M'
s.bake_ore = False
@@ -140,6 +150,12 @@ for ob in bpy.context.scene.objects:
if max(erz_aus_a(a)) < 0.9:
fails.append("%s traegt keine Erz-Maske ((1-A) max %.2f)"
% (ob.name, max(erz_aus_a(a))))
# EIN neutraler Slot fuer ALLE Erzsorten. Die UE-Skripte mappen ueber den
# Slot-NAMEN - ohne Slot legt Unreal nur einen Default an.
slots = [m.name for m in ob.data.materials]
if slots != [rg.ORE_MATERIAL[0]]:
fails.append("%s: Slots %s, erwartet ['%s']"
% (ob.name, slots, rg.ORE_MATERIAL[0]))
s_hoch = max(v for k, v in hoehen.items() if "_S_" in k)
m_hoch = min(v for k, v in hoehen.items() if "_M_" in k)
@@ -153,7 +169,37 @@ if (s.name_prefix, s.name_form, s.name_class, s.bake_ore, s.subsurf_levels) != m
% str((s.name_prefix, s.name_form, s.name_class, s.bake_ore,
s.subsurf_levels)))
# --- 4b) Normale Steine tragen die Sorten-Slots --------------------------
for o in list(bpy.data.objects):
bpy.data.objects.remove(o, do_unlink=True)
s.bake_ore = False
s.name_prefix = "Rock"
s.batch_count = 4
s.assign_material = True
bpy.ops.object.generate_rocks_batch()
normale = sorted((o for o in bpy.context.scene.objects if o.type == 'MESH'),
key=lambda o: o.name)
slots_normal = [[m.name for m in o.data.materials] for o in normale]
print("Normale Steine: %s" % ", ".join(x[0] if x else "KEINE" for x in slots_normal))
for o, sl in zip(normale, slots_normal):
if not sl:
fails.append("%s hat keinen Material-Slot - Unreal legt dann nur einen "
"Default an und die Konvention M_Rock_<Sorte> greift nicht"
% o.name)
elif not sl[0].startswith("M_Rock_"):
fails.append("%s: Slot '%s' folgt nicht M_Rock_<Sorte>" % (o.name, sl[0]))
elif sl[0] == rg.ORE_MATERIAL[0]:
fails.append("%s: traegt den Erz-Slot, obwohl kein Erz gebacken wurde"
% o.name)
if not any(n.startswith("Rock_") for n in (o.name for o in normale)):
fails.append("Standard-Praefix ist nicht 'Rock' - das bricht die "
"eingefrorene Konvention und erzeugt Asset-Zwillinge in UE")
# --- 5) A ueberlebt den FBX-Roundtrip ------------------------------------
for o in list(bpy.data.objects):
bpy.data.objects.remove(o, do_unlink=True)
s.batch_count = 1
bpy.ops.rockgen.ore_set()
bpy.ops.object.export_rocks_fbx()
dateien = sorted(f for f in os.listdir(OUT) if f.lower().endswith(".fbx"))
if not dateien: