Panels aufgeraeumt (alle vier Addons) + Test-Suite instandgesetzt
Panel-Umbau
-----------
Jedes Addon hatte seine Einstellungen als Kette dauerhaft offener Boxen - beim
Rock Generator 15 Stueck, man musste am ganzen Panel vorbeiscrollen, um an den
Erzeugen-Knopf zu kommen. Jetzt steht oben nur, was man bei jedem Asset anfasst
(Vorlage, Name, grosser Erzeugen-Knopf, Zufall), der Rest liegt in nummerierten,
eingeklappten Unter-Panels in der Reihenfolge des Arbeitsablaufs:
Rock Gen 9 Unter-Panels (Benennung ... Textur-Bake)
Tree Gen 4 (Wachstum, Blattwerk, Zusatz-Ebenen, Export)
Grass Gen 4 (Form, Haltung, Batch, Kanal-Belegung)
Asset Utils 5 (war schon so, dient als Vorlage)
Schalter, die ein ganzes Unter-Panel steuern (Vertex-Farben backen,
Wachstums-Stufen), sitzen jetzt als Haekchen im Panel-Kopf - Zustand sichtbar
ohne aufzuklappen.
Gemessen statt geglaubt: test_panels.py registriert alle vier Addons, laesst
jedes Panel zeichnen, prueft Tab-Zugehoerigkeit und Auf-/Zugeklappt-Absicht,
dass jeder angebotene Operator existiert - und vor allem, dass JEDE definierte
Property irgendwo erreichbar bleibt (Zweige wie base_shape='BOX' werden dabei
durchgeschaltet). Ergebnis: 0 von 122 Properties beim Umbau verloren.
Test-Suite
----------
Beim Gegenpruefen kam heraus, dass fuenf Tests still veraltet waren und eine
echte Regression nicht gemeldet haetten:
test_rock_gen suchte Objekte mit Praefix "Rock_" - die heissen seit dem
Benennungssystem "Fels_A_M_01". Fand 0 von 3.
test_base_shapes loeschte am Schleifenanfang ALLE Objekte, auch die eigenen
Kopien aus vorigen Durchlaeufen -> StructRNA removed.
test_ecogame_tree erwartete eine feste Namensliste ohne die spaeter
dazugekommenen _Leaf-Objekte.
test_tree_addon dito, ausserdem Zip-Version 1.22.0 fest verdrahtet.
test_leaves Zip-Version 1.23.0 fest verdrahtet.
Drei Muster vermieden statt nur die Symptome geflickt: neue Objekte ueber die
Differenz vorher/nachher finden statt ueber ein Namens-Praefix, Zips per glob
statt mit fester Version, Zusatz-Ebenen beim Zaehlen herausfiltern.
Neu: run_tests.ps1 faehrt die komplette Suite mit einem Befehl (-Filter fuer
einzelne). Genau das fehlte - deshalb war das Veralten nicht aufgefallen.
13 von 13 Tests bestehen.
Nebenbei
--------
build.ps1 ruft server-generate jetzt mit --html auf (browsbare index.html fuer
statisches Hosting). Nachgemessen und im README festgehalten: zwei Zips
derselben Extension-ID sind KEIN Versions-Archiv - server-generate warnt
("archive found with duplicates ... conflicting blender versions"), mehrere
Versionen einer ID gehen nur bei verschiedenen Blender-Bereichen.
Versionen: Rock 2.13.0, Tree 1.24.0, Grass 1.1.0, Asset Utils 1.1.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+244
-163
@@ -1,7 +1,7 @@
|
||||
bl_info = {
|
||||
"name": "Stylized Rock Generator",
|
||||
"author": "D4rkst3r",
|
||||
"version": (2, 12, 0),
|
||||
"version": (2, 13, 0),
|
||||
"blender": (4, 2, 0),
|
||||
"location": "View3D > Sidebar > Rock Gen",
|
||||
"description": (
|
||||
@@ -1725,6 +1725,12 @@ class ROCKGEN_OT_preset_delete(Operator):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class VIEW3D_PT_rock_generator(Panel):
|
||||
"""Haupt-Panel: nur was man bei JEDEM Stein anfasst.
|
||||
|
||||
Alles andere sitzt in eingeklappten Unter-Panels (bl_parent_id). Vorher war
|
||||
das eine Kette aus 15 dauerhaft offenen Boxen - man musste scrollen, um an
|
||||
den Erzeugen-Knopf zu kommen.
|
||||
"""
|
||||
bl_label = "Rock Generator"
|
||||
bl_idname = "VIEW3D_PT_rock_generator"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
@@ -1733,173 +1739,237 @@ class VIEW3D_PT_rock_generator(Panel):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = context.scene.rock_gen_settings
|
||||
s = context.scene.rock_gen_settings
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Presets", icon='PRESET')
|
||||
box.prop(settings, "active_preset", text="")
|
||||
row = box.row(align=True)
|
||||
row.operator("rockgen.preset_load", text="Laden", icon='IMPORT')
|
||||
row.operator("rockgen.preset_delete", text="Loeschen", icon='TRASH')
|
||||
row = box.row(align=True)
|
||||
row.prop(settings, "new_preset_name", text="")
|
||||
row.operator("rockgen.preset_save", text="Speichern", icon='ADD')
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Benennung", icon='SORTALPHA')
|
||||
row = box.row(align=True)
|
||||
row.prop(settings, "name_prefix", text="")
|
||||
row.prop(settings, "name_form", text="")
|
||||
row.prop(settings, "name_class", text="")
|
||||
box.prop(settings, "name_numbered")
|
||||
row = box.row(align=True)
|
||||
row.prop(settings, "use_class_size")
|
||||
sub = row.row()
|
||||
sub.enabled = not settings.use_class_size
|
||||
sub.prop(settings, "base_size", text="")
|
||||
if settings.use_class_size:
|
||||
box.label(text="Basis-Groesse aus Klasse %s: x%.2f"
|
||||
% (settings.name_class, CLASS_SIZES.get(settings.name_class, 1.0)),
|
||||
icon='FIXED_SIZE')
|
||||
box.label(text="Ergebnis: %s" % _asset_name(settings, 0, settings.batch_count),
|
||||
icon='INFO')
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Basis")
|
||||
box.prop(settings, "base_shape")
|
||||
if settings.base_shape == 'BOX':
|
||||
box.prop(settings, "box_proportions")
|
||||
box.prop(settings, "box_variation")
|
||||
box.prop(settings, "subsurf_levels")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Noise / Displace")
|
||||
box.prop(settings, "texture_type")
|
||||
box.prop(settings, "noise_scale")
|
||||
box.prop(settings, "displace_strength")
|
||||
box.prop(settings, "seed")
|
||||
box.prop(settings, "randomize_shape")
|
||||
sub = box.column(align=True)
|
||||
sub.enabled = settings.randomize_shape
|
||||
sub.prop(settings, "noise_scale_max")
|
||||
sub.prop(settings, "displace_strength_max")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Decimate / Cleanup")
|
||||
box.prop(settings, "decimate_ratio_1")
|
||||
box.prop(settings, "decimate_ratio_2")
|
||||
box.prop(settings, "dissolve_angle")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Hard-Surface (optional)")
|
||||
box.prop(settings, "add_bevel")
|
||||
sub = box.column(align=True)
|
||||
sub.enabled = settings.add_bevel
|
||||
sub.prop(settings, "bevel_width")
|
||||
sub.prop(settings, "bevel_segments")
|
||||
box.prop(settings, "add_weighted_normal")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Shading / Form")
|
||||
box.prop(settings, "shading_mode")
|
||||
row = box.row()
|
||||
row.enabled = settings.shading_mode == 'AUTO'
|
||||
row.prop(settings, "autosmooth_angle")
|
||||
box.prop(settings, "flatten_bottom")
|
||||
row = box.row()
|
||||
row.enabled = settings.flatten_bottom
|
||||
row.prop(settings, "flatten_ratio")
|
||||
box.prop(settings, "set_origin_bottom")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="UV (Unreal Export)")
|
||||
box.prop(settings, "generate_uv0")
|
||||
box.prop(settings, "generate_lightmap_uv")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="LOD")
|
||||
box.prop(settings, "generate_lods")
|
||||
sub = box.column(align=True)
|
||||
sub.enabled = settings.generate_lods
|
||||
sub.prop(settings, "lod_count")
|
||||
sub.prop(settings, "lod_ratio_step")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Vertex-Cavity (ohne Textur)")
|
||||
box.prop(settings, "bake_vertex_cavity")
|
||||
sub = box.column(align=True)
|
||||
sub.enabled = settings.bake_vertex_cavity
|
||||
sub.prop(settings, "cavity_strength")
|
||||
sub.prop(settings, "cavity_blur")
|
||||
sub.separator()
|
||||
sub.prop(settings, "moss_amount")
|
||||
sub.prop(settings, "moss_noise")
|
||||
sub.prop(settings, "moss_seed")
|
||||
sub.prop(settings, "part_mask_from_shells")
|
||||
sub.label(text="R=Cavity G=%s B=Hoehe"
|
||||
% ("Teil-Maske" if settings.part_mask_from_shells else "Moos"),
|
||||
icon='INFO')
|
||||
box.separator()
|
||||
box.operator("rockgen.bake_cavity_selection", icon='BRUSH_DATA')
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Material")
|
||||
box.prop(settings, "assign_material")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Transform")
|
||||
box.prop(settings, "randomize_transform")
|
||||
row = box.row(align=True)
|
||||
row.prop(settings, "scale_min")
|
||||
row.prop(settings, "scale_max")
|
||||
box.prop(settings, "nonuniform_scale")
|
||||
box.prop(settings, "keep_size")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Batch")
|
||||
box.prop(settings, "batch_count")
|
||||
box.prop(settings, "spacing")
|
||||
box.prop(settings, "use_modal")
|
||||
sub = box.row()
|
||||
sub.enabled = settings.use_modal
|
||||
sub.prop(settings, "modal_threshold")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Zufall", icon='FILE_REFRESH')
|
||||
row = box.row(align=True)
|
||||
row.prop(settings, "random_amount")
|
||||
row.prop(settings, "random_shape", text="", icon='MOD_NOISE')
|
||||
box.operator("rockgen.randomize", icon='FILE_REFRESH')
|
||||
row = layout.row(align=True)
|
||||
row.prop(s, "active_preset", text="")
|
||||
row.operator("rockgen.preset_load", text="", icon='IMPORT')
|
||||
row.operator("rockgen.preset_delete", text="", icon='TRASH')
|
||||
row = layout.row(align=True)
|
||||
row.prop(s, "new_preset_name", text="")
|
||||
row.operator("rockgen.preset_save", text="", icon='ADD')
|
||||
|
||||
layout.separator()
|
||||
layout.operator("object.generate_rocks_batch", icon='MESH_ICOSPHERE')
|
||||
col = layout.column(align=True)
|
||||
col.scale_y = 1.4
|
||||
col.operator("object.generate_rocks_batch",
|
||||
text="%d Stein(e) erzeugen" % s.batch_count,
|
||||
icon='MESH_ICOSPHERE')
|
||||
layout.label(text=_asset_name(s, 0, s.batch_count), icon='INFO')
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="FBX-Export (Unreal)")
|
||||
box.prop(settings, "export_dir")
|
||||
box.prop(settings, "export_selected_only")
|
||||
box.operator("object.export_rocks_fbx", icon='EXPORT')
|
||||
row = layout.row(align=True)
|
||||
row.prop(s, "random_amount", text="Zufall")
|
||||
row.prop(s, "random_shape", text="", icon='MOD_NOISE')
|
||||
row.operator("rockgen.randomize", text="", icon='FILE_REFRESH')
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Textur-Bake (tileable / Triplanar)")
|
||||
box.prop(settings, "bake_dir")
|
||||
box.prop(settings, "bake_prefix")
|
||||
box.prop(settings, "bake_resolution")
|
||||
box.prop(settings, "bake_base_color")
|
||||
box.prop(settings, "bake_cell_scale")
|
||||
box.prop(settings, "bake_seam_width")
|
||||
box.prop(settings, "bake_plate_flat")
|
||||
row = box.row(align=True)
|
||||
row.prop(settings, "bake_color", toggle=True)
|
||||
row.prop(settings, "bake_normal", toggle=True)
|
||||
box.prop(settings, "bake_ao_into_albedo")
|
||||
sub = box.row()
|
||||
sub.enabled = settings.bake_ao_into_albedo
|
||||
sub.prop(settings, "bake_ao_strength")
|
||||
row = box.row(align=True)
|
||||
row.prop(settings, "bake_roughness", toggle=True)
|
||||
row.prop(settings, "bake_ao", toggle=True)
|
||||
box.operator("object.bake_rock_textures", icon='TEXTURE')
|
||||
|
||||
class _RockSub(Panel):
|
||||
"""Basis aller Unter-Panels - spart neunmal dieselben vier Zeilen."""
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "Rock Gen"
|
||||
bl_parent_id = "VIEW3D_PT_rock_generator"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_naming(_RockSub):
|
||||
bl_label = "1 - Benennung & Groesse"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
row = layout.row(align=True)
|
||||
row.prop(s, "name_prefix", text="")
|
||||
row.prop(s, "name_form", text="")
|
||||
row.prop(s, "name_class", text="")
|
||||
layout.prop(s, "name_numbered")
|
||||
layout.separator()
|
||||
layout.prop(s, "use_class_size")
|
||||
sub = layout.row()
|
||||
sub.active = not s.use_class_size
|
||||
sub.prop(s, "base_size")
|
||||
if s.use_class_size:
|
||||
layout.label(text="Klasse %s: x%.2f"
|
||||
% (s.name_class, CLASS_SIZES.get(s.name_class, 1.0)),
|
||||
icon='FIXED_SIZE')
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_shape(_RockSub):
|
||||
bl_label = "2 - Form"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
layout.prop(s, "base_shape")
|
||||
if s.base_shape == 'BOX':
|
||||
layout.prop(s, "box_proportions")
|
||||
layout.prop(s, "box_variation")
|
||||
layout.prop(s, "subsurf_levels")
|
||||
layout.separator()
|
||||
layout.prop(s, "texture_type")
|
||||
col = layout.column(align=True)
|
||||
col.prop(s, "noise_scale")
|
||||
col.prop(s, "displace_strength")
|
||||
layout.prop(s, "seed")
|
||||
layout.separator()
|
||||
layout.prop(s, "randomize_shape")
|
||||
sub = layout.column(align=True)
|
||||
sub.active = s.randomize_shape
|
||||
sub.prop(s, "noise_scale_max")
|
||||
sub.prop(s, "displace_strength_max")
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_detail(_RockSub):
|
||||
bl_label = "3 - Detail & Cleanup"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
col = layout.column(align=True)
|
||||
col.prop(s, "decimate_ratio_1")
|
||||
col.prop(s, "decimate_ratio_2")
|
||||
layout.prop(s, "dissolve_angle")
|
||||
layout.separator()
|
||||
layout.prop(s, "add_bevel")
|
||||
sub = layout.column(align=True)
|
||||
sub.active = s.add_bevel
|
||||
sub.prop(s, "bevel_width")
|
||||
sub.prop(s, "bevel_segments")
|
||||
layout.prop(s, "add_weighted_normal")
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_shading(_RockSub):
|
||||
bl_label = "4 - Shading & Ausrichtung"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
layout.prop(s, "shading_mode")
|
||||
row = layout.row()
|
||||
row.active = s.shading_mode == 'AUTO'
|
||||
row.prop(s, "autosmooth_angle")
|
||||
layout.separator()
|
||||
layout.prop(s, "flatten_bottom")
|
||||
row = layout.row()
|
||||
row.active = s.flatten_bottom
|
||||
row.prop(s, "flatten_ratio")
|
||||
layout.prop(s, "set_origin_bottom")
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_vcol(_RockSub):
|
||||
bl_label = "5 - Vertex-Farben"
|
||||
|
||||
def draw_header(self, context):
|
||||
# Schalter im Panel-Kopf: man sieht auch eingeklappt, ob gebacken wird.
|
||||
self.layout.prop(context.scene.rock_gen_settings,
|
||||
"bake_vertex_cavity", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
col = layout.column()
|
||||
col.active = s.bake_vertex_cavity
|
||||
sub = col.column(align=True)
|
||||
sub.prop(s, "cavity_strength")
|
||||
sub.prop(s, "cavity_blur")
|
||||
col.separator()
|
||||
sub = col.column(align=True)
|
||||
sub.prop(s, "moss_amount")
|
||||
sub.prop(s, "moss_noise")
|
||||
sub.prop(s, "moss_seed")
|
||||
col.prop(s, "part_mask_from_shells")
|
||||
col.label(text="R=Cavity G=%s B=Hoehe"
|
||||
% ("Teil-Maske" if s.part_mask_from_shells else "Moos"),
|
||||
icon='INFO')
|
||||
# Nicht in der ausgegrauten Spalte: der Knopf arbeitet auf der Auswahl
|
||||
# und ist auch dann sinnvoll, wenn beim Erzeugen nicht gebacken wird.
|
||||
layout.separator()
|
||||
layout.operator("rockgen.bake_cavity_selection", icon='BRUSH_DATA')
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_uv(_RockSub):
|
||||
bl_label = "6 - UV, LOD & Material"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
layout.prop(s, "generate_uv0")
|
||||
layout.prop(s, "generate_lightmap_uv")
|
||||
layout.separator()
|
||||
layout.prop(s, "generate_lods")
|
||||
sub = layout.column(align=True)
|
||||
sub.active = s.generate_lods
|
||||
sub.prop(s, "lod_count")
|
||||
sub.prop(s, "lod_ratio_step")
|
||||
layout.separator()
|
||||
layout.prop(s, "assign_material")
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_batch(_RockSub):
|
||||
bl_label = "7 - Batch & Transform"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
col = layout.column(align=True)
|
||||
col.prop(s, "batch_count")
|
||||
col.prop(s, "spacing")
|
||||
layout.separator()
|
||||
layout.prop(s, "use_modal")
|
||||
row = layout.row()
|
||||
row.active = s.use_modal
|
||||
row.prop(s, "modal_threshold")
|
||||
layout.separator()
|
||||
layout.prop(s, "randomize_transform")
|
||||
sub = layout.column(align=True)
|
||||
sub.active = s.randomize_transform
|
||||
row = sub.row(align=True)
|
||||
row.prop(s, "scale_min")
|
||||
row.prop(s, "scale_max")
|
||||
sub.prop(s, "nonuniform_scale")
|
||||
sub.prop(s, "keep_size")
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_export(_RockSub):
|
||||
bl_label = "8 - FBX-Export (Unreal)"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
layout.prop(s, "export_dir")
|
||||
layout.prop(s, "export_selected_only")
|
||||
layout.operator("object.export_rocks_fbx", icon='EXPORT')
|
||||
|
||||
|
||||
class VIEW3D_PT_rock_bake(_RockSub):
|
||||
bl_label = "9 - Textur-Bake (tileable)"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
s = context.scene.rock_gen_settings
|
||||
layout.prop(s, "bake_dir")
|
||||
row = layout.row(align=True)
|
||||
row.prop(s, "bake_prefix", text="")
|
||||
row.prop(s, "bake_resolution", text="")
|
||||
layout.separator()
|
||||
col = layout.column(align=True)
|
||||
col.prop(s, "bake_base_color")
|
||||
col.prop(s, "bake_cell_scale")
|
||||
col.prop(s, "bake_seam_width")
|
||||
col.prop(s, "bake_plate_flat")
|
||||
layout.separator()
|
||||
row = layout.row(align=True)
|
||||
row.prop(s, "bake_color", toggle=True)
|
||||
row.prop(s, "bake_normal", toggle=True)
|
||||
row = layout.row(align=True)
|
||||
row.prop(s, "bake_roughness", toggle=True)
|
||||
row.prop(s, "bake_ao", toggle=True)
|
||||
layout.prop(s, "bake_ao_into_albedo")
|
||||
row = layout.row()
|
||||
row.active = s.bake_ao_into_albedo
|
||||
row.prop(s, "bake_ao_strength")
|
||||
layout.separator()
|
||||
layout.operator("object.bake_rock_textures", icon='TEXTURE')
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -1916,7 +1986,18 @@ classes = (
|
||||
ROCKGEN_OT_preset_save,
|
||||
ROCKGEN_OT_preset_load,
|
||||
ROCKGEN_OT_preset_delete,
|
||||
# Das Eltern-Panel MUSS vor seinen Unter-Panels stehen, sonst findet Blender
|
||||
# die bl_parent_id nicht. Die Reihenfolge hier ist die Reihenfolge im N-Panel.
|
||||
VIEW3D_PT_rock_generator,
|
||||
VIEW3D_PT_rock_naming,
|
||||
VIEW3D_PT_rock_shape,
|
||||
VIEW3D_PT_rock_detail,
|
||||
VIEW3D_PT_rock_shading,
|
||||
VIEW3D_PT_rock_vcol,
|
||||
VIEW3D_PT_rock_uv,
|
||||
VIEW3D_PT_rock_batch,
|
||||
VIEW3D_PT_rock_export,
|
||||
VIEW3D_PT_rock_bake,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user