From 512d61e370d5a659b65c2efd5c63610634003649 Mon Sep 17 00:00:00 2001 From: D4rkst3r Date: Fri, 31 Jul 2026 11:43:30 +0200 Subject: [PATCH] Rock Generator 2.12.0: Vertex-Cavity auf beliebige Meshes + Teil-Maske Der User baut Pilze von Hand (Hut und Stiel als getrennte Objekte, mit Strg+J verbunden) und fragte, was er wegen Vertex-Farben beachten muss. Zwei Ergaenzungen: 1) Button "Vertex-Cavity auf Auswahl": backt R=Cavity / G / B=Hoehe auf JEDES markierte Mesh - nicht mehr nur auf generierte Steine. Damit lassen sich handgebaute Assets (Pilze, Baumstumpf, Erzfels) auf dasselbe Layout bringen. 2) Option "G = Teil-Maske (Shells)": statt der Moos-Maske werden getrennte Mesh-Teile markiert. Der oberste/breiteste Teil bekommt G=1, der Rest 0. Bei Strg+J-verbundenen Assets ist die Trennung dadurch EXAKT statt ueber Normalen geschaetzt - beim Pilz also Hut vs Stiel. Ein Material toent beide unterschiedlich, ein zweiter Material-Slot entfaellt. Einteilige Meshes bleiben bewusst unmarkiert (G=0), damit die Maske nichts Falsches behauptet. Am nachgebauten Pilz geprueft: 2 Shells erkannt, G im obersten Teil ausschliess- lich 1.0, im Rest ausschliesslich 0.0, Maske binaer, Einzelteil-Mesh -> nur 0.0. Co-Authored-By: Claude Opus 4.8 --- README.md | 8 ++ blender_manifest.toml | 2 +- dist/index.json | 8 +- dist/stylized_rock_generator-2.11.0.zip | Bin 20382 -> 0 bytes dist/stylized_rock_generator-2.12.0.zip | Bin 0 -> 21754 bytes stylized_rock_generator.py | 115 +++++++++++++++++++++++- tests/test_part_mask.py | 70 +++++++++++++++ 7 files changed, 195 insertions(+), 8 deletions(-) delete mode 100644 dist/stylized_rock_generator-2.11.0.zip create mode 100644 dist/stylized_rock_generator-2.12.0.zip create mode 100644 tests/test_part_mask.py diff --git a/README.md b/README.md index 70ca002..9d2b8fa 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,14 @@ Abgestimmt auf `A:\eco\EcoGame` (UE 5.8). Kurzfassung: **Moosfarbe** werden pro Material-Instanz geregelt, nicht im Mesh festgelegt. Regler: `Cavity-Staerke`, `Weichzeichnen`, `Moos-Menge`, `Moos-Aufbruch`, `Moos-Seed`. + **G alternativ als Teil-Maske:** Haken `G = Teil-Maske (Shells)` markiert + getrennte Mesh-Teile statt Moos — der oberste/breiteste Teil bekommt 1, der + Rest 0. Assets, die aus mehreren Objekten mit **Strg+J** verbunden wurden + (Pilz = Hut + Stiel), lassen sich damit EXAKT trennen statt ueber Normalen + geschaetzt. Ein Material toent dann beide Teile unterschiedlich — **kein + zweiter Material-Slot noetig**. Einteilige Meshes bleiben unmarkiert (G=0). + **Der Button `Vertex-Cavity auf Auswahl` backt das Layout auf JEDES markierte + Mesh** — also auch auf handgebaute Assets, nicht nur auf generierte Steine. Verifiziert: R ohne Hoehenabhaengigkeit (unten 0.62 / oben 0.59), B steigt sauber (0.08 -> 0.92), G oben staerker (0.20 -> 0.57), A konstant 1, Seed aendert die Verteilung, und alle Kanaele ueberleben den FBX-Roundtrip. diff --git a/blender_manifest.toml b/blender_manifest.toml index 0db2713..73dd23d 100644 --- a/blender_manifest.toml +++ b/blender_manifest.toml @@ -1,7 +1,7 @@ schema_version = "1.0.0" id = "stylized_rock_generator" -version = "2.11.0" +version = "2.12.0" name = "Stylized Rock Generator" tagline = "Batch-Generator fuer stylized Rocks mit UE5-Export" maintainer = "D4rkst3r" diff --git a/dist/index.json b/dist/index.json index e153d8e..ddd8d1b 100644 --- a/dist/index.json +++ b/dist/index.json @@ -32,7 +32,7 @@ "id": "stylized_rock_generator", "name": "Stylized Rock Generator", "tagline": "Batch-Generator fuer stylized Rocks mit UE5-Export", - "version": "2.11.0", + "version": "2.12.0", "type": "add-on", "maintainer": "D4rkst3r", "license": [ @@ -48,9 +48,9 @@ "Mesh", "Modeling" ], - "archive_url": "./stylized_rock_generator-2.11.0.zip", - "archive_size": 20382, - "archive_hash": "sha256:50eeed1d105ad68487e25020fdf28f5e3b8d81e83f9a21b9d33968eaa06aff2d" + "archive_url": "./stylized_rock_generator-2.12.0.zip", + "archive_size": 21754, + "archive_hash": "sha256:6e18e32b841d627edfa6530587c99080c50d02ac4b0a532ed6079796bfa2aaf4" }, { "schema_version": "1.0.0", diff --git a/dist/stylized_rock_generator-2.11.0.zip b/dist/stylized_rock_generator-2.11.0.zip deleted file mode 100644 index 61dcccc9f18036f75c15ed7498623cdd5d439a98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20382 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 diff --git a/dist/stylized_rock_generator-2.12.0.zip b/dist/stylized_rock_generator-2.12.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..e47815dd55eb2c91ec257df16ce914eba3fbb213 GIT binary patch literal 21754 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 literal 0 HcmV?d00001 diff --git a/stylized_rock_generator.py b/stylized_rock_generator.py index a7f3243..b1ef431 100644 --- a/stylized_rock_generator.py +++ b/stylized_rock_generator.py @@ -1,7 +1,7 @@ bl_info = { "name": "Stylized Rock Generator", "author": "D4rkst3r", - "version": (2, 11, 0), + "version": (2, 12, 0), "blender": (4, 2, 0), "location": "View3D > Sidebar > Rock Gen", "description": ( @@ -61,7 +61,7 @@ PRESET_KEYS = ( "randomize_shape", "noise_scale_max", "displace_strength_max", "nonuniform_scale", "flatten_bottom", "flatten_ratio", "set_origin_bottom", "keep_size", "bake_vertex_cavity", "cavity_strength", "cavity_blur", - "moss_amount", "moss_noise", "moss_seed", + "moss_amount", "moss_noise", "moss_seed", "part_mask_from_shells", "use_class_size", "base_size", ) @@ -865,6 +865,13 @@ class RockGenSettings(PropertyGroup): name="Weichzeichnen", default=1, min=0, max=5, description="Glaettet den Cavity-Verlauf ueber benachbarte Vertices", ) + part_mask_from_shells: BoolProperty( + name="G = Teil-Maske (Shells)", default=False, + description=("Statt der Moos-Maske: getrennte Mesh-Teile markieren. " + "Der oberste/breiteste Teil bekommt G=1 (z.B. Pilzhut), " + "der Rest 0 (Stiel). Nutzt Strg+J-verbundene Objekte aus - " + "damit tont EIN Material beide Teile unterschiedlich"), + ) moss_amount: FloatProperty( name="Moos-Menge", default=0.55, min=0.0, max=1.0, description=("Wie viel der Oberflaeche die Moos-/Schmutzmaske (Kanal G) " @@ -1505,6 +1512,102 @@ class OBJECT_OT_bake_rock_textures(Operator): # Operatoren: Presets # --------------------------------------------------------------------------- +def _mesh_shells(me): + """Zusammenhaengende Teile (Shells) als Listen von Polygon-Indizes. + + Bei Assets, die aus mehreren Objekten mit Strg+J verbunden wurden (z.B. + Pilz = Hut + Stiel), bleiben die Teile geometrisch getrennt. Damit laesst + sich die Teil-Maske EXAKT bilden statt sie ueber Normalen zu schaetzen. + """ + adj = {} + for poly in me.polygons: + for ek in poly.edge_keys: + adj.setdefault(ek, []).append(poly.index) + seen = set() + shells = [] + for poly in me.polygons: + if poly.index in seen: + continue + stack = [poly.index] + comp = set() + while stack: + pi = stack.pop() + if pi in comp: + continue + comp.add(pi) + for ek in me.polygons[pi].edge_keys: + for nb in adj.get(ek, ()): + if nb not in comp: + stack.append(nb) + seen |= comp + shells.append(comp) + return shells + + +def _shell_part_mask(me): + """G-Wert je Polygon: 1 fuer den OBEREN/breiteren Teil (z.B. Hut), 0 sonst. + + Bei nur einer Shell gibt es nichts zu trennen -> alles 0, damit die Maske + nicht faelschlich etwas markiert. + """ + shells = _mesh_shells(me) + if len(shells) < 2: + return {p.index: 0.0 for p in me.polygons}, len(shells) + infos = [] + for sh in shells: + vs = {vi for pi in sh for vi in me.polygons[pi].vertices} + zs = [me.vertices[i].co.z for i in vs] + xs = [me.vertices[i].co.x for i in vs] + ys = [me.vertices[i].co.y for i in vs] + infos.append((sh, max(zs), max(max(xs) - min(xs), max(ys) - min(ys)))) + # Oberster Teil, bei Gleichstand der breitere -> das ist der Hut/Deckel + top = max(infos, key=lambda t: (t[1], t[2])) + out = {} + for sh, _, _ in infos: + val = 1.0 if sh is top[0] else 0.0 + for pi in sh: + out[pi] = val + return out, len(shells) + + +class ROCKGEN_OT_bake_cavity_selection(Operator): + bl_idname = "rockgen.bake_cavity_selection" + bl_label = "Vertex-Cavity auf Auswahl" + bl_description = ("Backt das Layout R=Cavity / G=Teil-Maske / B=Hoehe auf ALLE " + "ausgewaehlten Meshes - auch auf handgebaute Assets") + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + s = context.scene.rock_gen_settings + targets = [o for o in context.selected_objects if o.type == 'MESH'] + if not targets: + self.report({'ERROR'}, "Kein Mesh ausgewaehlt.") + return {'CANCELLED'} + _ensure_object_mode(context) + done, notes = 0, [] + for ob in targets: + try: + _bake_vertex_cavity(context, ob, s) + if s.part_mask_from_shells: + mask, n = _shell_part_mask(ob.data) + layer = ob.data.color_attributes.get("Cavity") + if layer is not None: + for poly in ob.data.polygons: + g = mask.get(poly.index, 0.0) + for li in poly.loop_indices: + c = layer.data[li].color + layer.data[li].color = (c[0], g, c[2], 1.0) + notes.append("%s: %d Teil(e)" % (ob.name, n)) + done += 1 + except Exception as exc: # noqa: BLE001 + self.report({'WARNING'}, "%s: %s" % (ob.name, exc)) + msg = "Cavity auf %d Mesh(es) gebacken." % done + if notes: + msg += " " + ", ".join(notes[:4]) + self.report({'INFO'}, msg) + return {'FINISHED'} + + class ROCKGEN_OT_randomize(Operator): bl_idname = "rockgen.randomize" bl_label = "Zufaellig" @@ -1732,7 +1835,12 @@ class VIEW3D_PT_rock_generator(Panel): sub.prop(settings, "moss_amount") sub.prop(settings, "moss_noise") sub.prop(settings, "moss_seed") - sub.label(text="R=Cavity G=Moos B=Hoehe", icon='INFO') + 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") @@ -1803,6 +1911,7 @@ classes = ( OBJECT_OT_generate_rocks, OBJECT_OT_export_rocks_fbx, OBJECT_OT_bake_rock_textures, + ROCKGEN_OT_bake_cavity_selection, ROCKGEN_OT_randomize, ROCKGEN_OT_preset_save, ROCKGEN_OT_preset_load, diff --git a/tests/test_part_mask.py b/tests/test_part_mask.py new file mode 100644 index 0000000..663d34d --- /dev/null +++ b/tests/test_part_mask.py @@ -0,0 +1,70 @@ +import bpy, sys, importlib.util, bmesh +spec=importlib.util.spec_from_file_location("srg", r"A:\eco\stylized_rock_generator\stylized_rock_generator.py") +r=importlib.util.module_from_spec(spec); sys.modules["srg"]=r; spec.loader.exec_module(r) +try: r.unregister() +except Exception: pass +r.register() +fails=[] +for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True) + +# Pilz nachbauen: Stiel (Zylinder) + Hut (UV-Kugel oben), dann Strg+J +bpy.ops.mesh.primitive_cylinder_add(vertices=10, radius=0.028, depth=0.126, location=(0,0,0.063)) +stiel=bpy.context.active_object; stiel.name="Stiel" +bpy.ops.mesh.primitive_uv_sphere_add(segments=14, ring_count=7, radius=0.042, location=(0,0,0.13)) +hut=bpy.context.active_object; hut.name="Hut" +hut.scale=(1,1,0.5); bpy.ops.object.transform_apply(scale=True) +for o in bpy.context.selected_objects: o.select_set(False) +stiel.select_set(True); hut.select_set(True) +bpy.context.view_layer.objects.active=stiel +bpy.ops.object.join() +pilz=bpy.context.active_object; pilz.name="Mushroom_Test" +print("Pilz: %d Tris" % sum(len(p.vertices)-2 for p in pilz.data.polygons)) + +s=bpy.context.scene.rock_gen_settings +s.bake_vertex_cavity=True; s.cavity_strength=0.7 +s.part_mask_from_shells=True +pilz.select_set(True); bpy.context.view_layer.objects.active=pilz +res=bpy.ops.rockgen.bake_cavity_selection() +print("Operator:", list(res)) + +me=pilz.data +ca=me.color_attributes.get("Cavity") +if ca is None: fails.append("kein_attribut") +else: + # Hut liegt oben -> dort muss G=1 sein, am Stiel G=0 + # Direkt gegen die Shell-Zerlegung pruefen statt ueber z-Schwellen: + # der oberste Teil (Hut) muss ueberall G=1 haben, alle anderen Teile G=0. + shells = r._mesh_shells(me) + infos = [] + for sh in shells: + vs = {vi for pi in sh for vi in me.polygons[pi].vertices} + infos.append((sh, max(me.vertices[v].co.z for v in vs))) + infos.sort(key=lambda t: -t[1]) + top_sh = infos[0][0] + g_top = {round(ca.data[li].color[1],3) + for pi in top_sh for li in me.polygons[pi].loop_indices} + g_rest = {round(ca.data[li].color[1],3) + for sh,_ in infos[1:] for pi in sh for li in me.polygons[pi].loop_indices} + print("Shells: %d | G im obersten Teil: %s | G im Rest: %s" + % (len(shells), sorted(g_top), sorted(g_rest))) + if g_top != {1.0}: fails.append("hut_nicht_1") + if g_rest != {0.0}: fails.append("stiel_nicht_0") + # G darf NUR 0 oder 1 sein (harte Maske) + vals={round(d.color[1],3) for d in ca.data} + print("G Werte insgesamt: %s" % sorted(vals)) + if not vals <= {0.0,1.0}: fails.append("G_nicht_binaer") + R=[d.color[0] for d in ca.data]; B=[d.color[2] for d in ca.data] + print("R %.2f..%.2f B %.2f..%.2f" % (min(R),max(R),min(B),max(B))) + if max(B)-min(B) < 0.8: fails.append("B_kein_verlauf") + +# Einzel-Shell-Fall: darf nichts faelschlich markieren +bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=2, radius=0.1, location=(1,0,0.1)) +solo=bpy.context.active_object +for o in bpy.context.selected_objects: o.select_set(False) +solo.select_set(True); bpy.context.view_layer.objects.active=solo +bpy.ops.rockgen.bake_cavity_selection() +g2={round(d.color[1],3) for d in solo.data.color_attributes["Cavity"].data} +print("Einzelteil-Mesh -> G Werte: %s" % sorted(g2)) +if g2 != {0.0}: fails.append("einzelshell_markiert") +r.unregister() +print("ERGEBNIS:", "ALLE CHECKS OK" if not fails else "FEHLER: "+", ".join(fails))