Rock Generator 2.5.0: - "Zufaellig"-Button: wuerfelt Seed und Form-Parameter, "Streuung" steuert die Abweichung von den aktuellen Werten (0 = nur neuer Seed). Optional werden auch Basis-Form und Noise-Typ gewuerfelt. Werte werden auf ihre Grenzen geklemmt. - Skalierung streut jetzt die FORM, nicht die Groesse: nicht-uniform ist Default, und "Gesamtgroesse konstant halten" normiert das geometrische Mittel auf 1. Gemessen ueber 6 Rocks: Volumen-Spanne 1.92x -> 1.11x. Wichtig, weil EcoGame die Groesse zusaetzlich ueber ScaleMin/Max streut. Tree Generator 1.19.0: - "Zufaellig"-Button: neuer Seed plus Streuung auf Hoehe, Radius, Biegung, Ast-Anzahl/-Laenge, Kronenform und Wurzelanlauf. Preset-Charakter bleibt, weil relativ zu den aktuellen Werten gestreut wird (gemessen: Hoehe 6.65 -> 8.34 m). - "_Leaf"- und "_Frucht"-Ebenen: leere Objekte mit IDENTISCHEM Ursprung neben dem Baum (gemessen: Abstand 0.000000), damit die Ebenen in UE deckungsgleich sitzen. Vier Test-Suiten liegen jetzt unter tests/ statt nur im Scratchpad. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 lines
2.4 KiB
Python
52 lines
2.4 KiB
Python
import bpy, sys, importlib.util, os, glob, tempfile, numpy as np
|
|
ADDON=r"A:\eco\stylized_rock_generator\stylized_rock_generator.py"
|
|
spec=importlib.util.spec_from_file_location("srg",ADDON)
|
|
m=importlib.util.module_from_spec(spec); sys.modules["srg"]=m; spec.loader.exec_module(m)
|
|
try: m.unregister()
|
|
except Exception: pass
|
|
m.register()
|
|
fails=[]
|
|
s=bpy.context.scene.rock_gen_settings
|
|
for o in list(bpy.data.objects): bpy.data.objects.remove(o, do_unlink=True)
|
|
|
|
# --- Namensschema ---
|
|
s.batch_count=3; s.subsurf_levels=3; s.use_modal=False; s.generate_lods=False
|
|
s.name_prefix="Fels"; s.name_form="a"; s.name_class='L'
|
|
bpy.ops.object.generate_rocks_batch()
|
|
names=sorted(o.name for o in bpy.context.scene.objects if o.type=='MESH')
|
|
print("NAMEN:", names)
|
|
if not all(n.startswith("Fels_A_L") for n in names): fails.append("naming")
|
|
|
|
# Einzeln (ohne Nummer)
|
|
for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True)
|
|
s.batch_count=1
|
|
bpy.ops.object.generate_rocks_batch()
|
|
single=[o.name for o in bpy.context.scene.objects if o.type=='MESH']
|
|
print("EINZELN:", single)
|
|
if single and single[0]!="Fels_A_L": fails.append("naming_single")
|
|
print("LIGHTMAP-DEFAULT aus:", not m.RockGenSettings.bl_rna.properties['generate_lightmap_uv'].default)
|
|
|
|
# --- Bake: nur _albedo + _normal, AO drin ---
|
|
out=tempfile.mkdtemp()
|
|
s.bake_dir=out; s.bake_prefix="fels_a"; s.bake_resolution='512'
|
|
s.bake_color=True; s.bake_normal=True; s.bake_roughness=False; s.bake_ao=False
|
|
def run(ao_on, strength=1.0):
|
|
for f in glob.glob(os.path.join(out,"*.png")): os.remove(f)
|
|
s.bake_ao_into_albedo=ao_on; s.bake_ao_strength=strength
|
|
bpy.ops.object.bake_rock_textures()
|
|
files=sorted(os.path.basename(f) for f in glob.glob(os.path.join(out,"*.png")))
|
|
img=bpy.data.images.load(os.path.join(out,"fels_a_albedo.png"))
|
|
px=np.array(img.pixels[:],dtype=np.float32).reshape(-1,4)[:,:3]
|
|
bpy.data.images.remove(img)
|
|
return files, float(px.mean()), float(px.std())
|
|
f_on, mean_on, std_on = run(True)
|
|
f_off, mean_off, std_off = run(False)
|
|
print("DATEIEN:", f_on)
|
|
print("AO an : mean=%.4f std=%.4f" % (mean_on, std_on))
|
|
print("AO aus: mean=%.4f std=%.4f" % (mean_off, std_off))
|
|
if f_on != ["fels_a_albedo.png","fels_a_normal.png"]: fails.append("dateinamen")
|
|
if not (mean_on < mean_off): fails.append("ao_nicht_eingerechnet")
|
|
m.unregister()
|
|
print("ERGEBNIS:", "ALLE CHECKS OK" if not fails else "FEHLER: "+", ".join(fails))
|
|
sys.exit(1 if fails else 0)
|