From b16e5ab75ac1c48f9ca69fc1e026f0aac077de7b Mon Sep 17 00:00:00 2001 From: D4rkst3r Date: Fri, 31 Jul 2026 10:41:16 +0200 Subject: [PATCH] Rock Generator 2.10.0: Quader als Grundform (Platten und Riegel) Auf Wunsch des Users neben Wuerfel und Ico-Sphere eine Quader-Grundform mit frei einstellbaren Proportionen (X/Y/Z) plus Streuung je Stein. Damit entstehen flache Platten und langgestreckte Riegel - passt besonders zum Plattenlook der Genshin-Referenz, wo Felsen aus flachen Schichten bestehen. Wichtiges Detail: die Proportionen werden auf die MESH-DATEN angewendet (transform_apply), nicht auf das Objekt. Der Displace arbeitet mit globalen Texturkoordinaten - eine Objekt-Skalierung wuerde das Rauschen mitverzerren statt die Form zu aendern. Gemessen bei Proportion (2.0, 1.5, 0.35): 3.43 / 2.56 / 0.79 m (Z = 23 % von X), bei (2.2, 0.8, 0.9): 3.81 / 1.40 / 1.60 m. Der Zufalls-Button kennt die neue Form ebenfalls. Neuer Test tests/test_base_shapes.py. Co-Authored-By: Claude Opus 4.8 --- README.md | 9 +++- blender_manifest.toml | 2 +- dist/index.json | 8 ++-- dist/stylized_rock_generator-2.10.0.zip | Bin 0 -> 20241 bytes dist/stylized_rock_generator-2.9.0.zip | Bin 19688 -> 0 bytes stylized_rock_generator.py | 44 ++++++++++++++++-- tests/test_base_shapes.py | 59 ++++++++++++++++++++++++ 7 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 dist/stylized_rock_generator-2.10.0.zip delete mode 100644 dist/stylized_rock_generator-2.9.0.zip create mode 100644 tests/test_base_shapes.py diff --git a/README.md b/README.md index 992efb7..e374c52 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,14 @@ damit die Raw-URL sie ausliefert. ## Features -- **Basis-Formen:** Cube oder Ico-Sphere, einstellbare Subsurf-Stufen. +- **Basis-Formen:** Wuerfel, **Quader** oder Ico-Sphere, einstellbare Subsurf-Stufen. + Der Quader hat frei einstellbare `Quader-Proportionen` (X/Y/Z) plus + `Proportions-Streuung` — damit entstehen flache **Platten** und langgestreckte + **Riegel** statt nur runder Brocken. Gemessen bei Proportion (2.0, 1.5, 0.35): + 3.43 / 2.56 / 0.79 m — Z also 23 % von X. + Die Proportionen werden auf die MESH-DATEN angewendet, nicht auf das Objekt: + der Displace nutzt globale Texturkoordinaten, eine Objekt-Skalierung wuerde + das Rauschen mitverzerren statt die Form zu aendern. - **Noise/Displace:** Voronoi / Clouds / Distorted Noise, Scale + Staerke, Seed. Seed-Variation ueber einen moderaten Welt-Offset (±25) vor dem Displace-Apply – Blenders prozedurale Texturen haben keinen echten Seed-Parameter. diff --git a/blender_manifest.toml b/blender_manifest.toml index 81c5c10..b37d3fb 100644 --- a/blender_manifest.toml +++ b/blender_manifest.toml @@ -1,7 +1,7 @@ schema_version = "1.0.0" id = "stylized_rock_generator" -version = "2.9.0" +version = "2.10.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 a9eee63..732dfe3 100644 --- a/dist/index.json +++ b/dist/index.json @@ -7,7 +7,7 @@ "id": "stylized_rock_generator", "name": "Stylized Rock Generator", "tagline": "Batch-Generator fuer stylized Rocks mit UE5-Export", - "version": "2.9.0", + "version": "2.10.0", "type": "add-on", "maintainer": "D4rkst3r", "license": [ @@ -23,9 +23,9 @@ "Mesh", "Modeling" ], - "archive_url": "./stylized_rock_generator-2.9.0.zip", - "archive_size": 19688, - "archive_hash": "sha256:78452434a3f175ae1a415b4d4b2abdb5cb803415499c114c0452fb0a4524959e" + "archive_url": "./stylized_rock_generator-2.10.0.zip", + "archive_size": 20241, + "archive_hash": "sha256:d092ae0a1cfefed9bdd4fbe1ffcd8160f4fffb00033cec346bbde3d14c755254" }, { "schema_version": "1.0.0", diff --git a/dist/stylized_rock_generator-2.10.0.zip b/dist/stylized_rock_generator-2.10.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..6debf0897057ce63cfb1df2b11acd1203169e39f GIT binary patch literal 20241 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 NtAl^3vG(87zX0@P!}$OJ diff --git a/stylized_rock_generator.py b/stylized_rock_generator.py index 2cedf4c..bf53df8 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, 9, 0), + "version": (2, 10, 0), "blender": (4, 2, 0), "location": "View3D > Sidebar > Rock Gen", "description": ( @@ -50,7 +50,7 @@ CLASS_SIZES = {'S': 0.45, 'M': 1.0, 'L': 1.9, 'XL': 3.2} # Property-Keys, die von Presets gespeichert/geladen werden. PRESET_KEYS = ( - "base_shape", "subsurf_levels", "texture_type", "noise_scale", + "base_shape", "box_proportions", "box_variation", "subsurf_levels", "texture_type", "noise_scale", "displace_strength", "seed", "decimate_ratio_1", "decimate_ratio_2", "dissolve_angle", "generate_uv0", "generate_lightmap_uv", "randomize_transform", "scale_min", "scale_max", @@ -303,8 +303,24 @@ def _make_lightmap_uv(context, obj): def _build_rock_mesh(context, settings, index, location, rng, name=None): """Baut das reine Rock-Mesh (ohne Transform/Material). Kann RockGenError werfen.""" # 1. Basis-Mesh - if settings.base_shape == 'CUBE': + if settings.base_shape in ('CUBE', 'BOX'): bpy.ops.mesh.primitive_cube_add(size=2, location=location) + if settings.base_shape == 'BOX': + # Proportionen auf die MESH-DATEN anwenden, nicht auf das Objekt: + # der Displace nutzt globale Texturkoordinaten, eine Objekt-Skalierung + # wuerde das Rauschen mitverzerren statt die Form zu aendern. + px, py, pz = settings.box_proportions + v = settings.box_variation + if v > 0.0: + px *= 1.0 + rng.uniform(-v, v) * 0.5 + py *= 1.0 + rng.uniform(-v, v) * 0.5 + pz *= 1.0 + rng.uniform(-v, v) * 0.5 + ob_tmp = context.active_object + ob_tmp.scale = (px, py, pz) + _deselect_all(context) + context.view_layer.objects.active = ob_tmp + ob_tmp.select_set(True) + bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) else: bpy.ops.mesh.primitive_ico_sphere_add( subdivisions=1, radius=1.0, location=location @@ -727,9 +743,24 @@ class RockGenSettings(PropertyGroup): # --- Basis --- base_shape: EnumProperty( name="Basis-Form", - items=[('CUBE', "Cube", ""), ('ICOSPHERE', "Ico-Sphere", "")], + items=[ + ('CUBE', "Wuerfel", "Gleichmaessiger Brocken"), + ('BOX', "Quader", "Laengliche oder flache Grundform - Proportionen unten"), + ('ICOSPHERE', "Ico-Sphere", "Rundlicher Brocken"), + ], default='CUBE', ) + box_proportions: FloatVectorProperty( + name="Quader-Proportionen", size=3, default=(1.6, 1.1, 0.55), + min=0.15, max=4.0, subtype='XYZ', + description=("Seitenverhaeltnis der Grundform bei 'Quader'. Flach (kleines Z) " + "ergibt Platten und Findlinge, langgestreckt ergibt Brocken. " + "Wird VOR dem Displace angewendet, damit die Verformung mitgeht"), + ) + box_variation: FloatProperty( + name="Proportions-Streuung", default=0.25, min=0.0, max=1.0, + description="Wuerfelt die Proportionen je Stein etwas anders (0 = alle gleich)", + ) subsurf_levels: IntProperty(name="Subsurf Levels", default=5, min=1, max=6) # --- Noise / Displace --- @@ -1501,7 +1532,7 @@ class ROCKGEN_OT_randomize(Operator): jitter("noise_scale_max", 0.6, 4.0) jitter("displace_strength_max", 0.2, 0.9) if s.random_shape: - s.base_shape = rng.choice(['CUBE', 'ICOSPHERE']) + s.base_shape = rng.choice(['CUBE', 'BOX', 'ICOSPHERE']) s.texture_type = rng.choice(['VORONOI', 'CLOUDS', 'DISTORTED_NOISE']) self.report({'INFO'}, "Neue Zufallswerte (Seed %d)." % s.seed) return {'FINISHED'} @@ -1626,6 +1657,9 @@ class VIEW3D_PT_rock_generator(Panel): 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() diff --git a/tests/test_base_shapes.py b/tests/test_base_shapes.py new file mode 100644 index 0000000..4733467 --- /dev/null +++ b/tests/test_base_shapes.py @@ -0,0 +1,59 @@ +import bpy, sys, importlib.util, mathutils +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=[] +s=bpy.context.scene.rock_gen_settings +s.batch_count=1; s.subsurf_levels=4; s.use_modal=False +s.shading_mode='FLAT'; s.bake_vertex_cavity=True; s.set_origin_bottom=True +s.randomize_transform=False # Proportionen isoliert messen +mat=bpy.data.materials.new("P"); mat.use_nodes=True +nt=mat.node_tree; nt.nodes.clear() +o_=nt.nodes.new("ShaderNodeOutputMaterial"); b=nt.nodes.new("ShaderNodeBsdfPrincipled") +c=nt.nodes.new("ShaderNodeVertexColor"); c.layer_name="Cavity" +sep=nt.nodes.new("ShaderNodeSeparateColor"); nt.links.new(c.outputs["Color"], sep.inputs[0]) +t=nt.nodes.new("ShaderNodeRGB"); t.outputs[0].default_value=(0.66,0.64,0.60,1) +mx=nt.nodes.new("ShaderNodeMixRGB"); mx.blend_type='MULTIPLY'; mx.inputs["Fac"].default_value=1.0 +nt.links.new(t.outputs[0],mx.inputs["Color1"]); nt.links.new(sep.outputs[0],mx.inputs["Color2"]) +nt.links.new(mx.outputs[0],b.inputs["Base Color"]); b.inputs["Roughness"].default_value=0.85 +nt.links.new(b.outputs[0],o_.inputs["Surface"]) +VARS=[("Wuerfel",'CUBE',None), + ("Platte",'BOX',(2.0,1.5,0.35)), + ("Riegel",'BOX',(2.2,0.8,0.9)), + ("Ico",'ICOSPHERE',None)] +print("%-9s %-6s %s" % ("Variante","Form","Abmessungen X/Y/Z (m)")) +keep=[]; x=0.0 +for name,shape,prop in VARS: + for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True) + s.base_shape=shape; s.box_variation=0.0 + if prop: s.box_proportions=prop + s.seed=7 + bpy.ops.object.generate_rocks_batch() + ob=[o for o in bpy.context.scene.objects if o.type=='MESH'][0] + bb=ob.bound_box + d=[max(v[i] for v in bb)-min(v[i] for v in bb) for i in range(3)] + print("%-9s %-6s %.2f / %.2f / %.2f" % (name,shape,d[0],d[1],d[2])) + if name=="Platte" and not (d[2] < d[0]*0.45): fails.append("platte_nicht_flach") + if name=="Riegel" and not (d[0] > d[1]*1.5): fails.append("riegel_nicht_laenglich") + cp=ob.copy(); cp.data=ob.data.copy(); keep.append((cp,x)) + x+=2.4 +for cp,px in keep: + bpy.context.collection.objects.link(cp); cp.location=(px,0,0) + cp.data.materials.clear(); cp.data.materials.append(mat) +for o in list(bpy.context.scene.objects): + if o.type=='MESH' and o not in [k[0] for k in keep]: bpy.data.objects.remove(o,do_unlink=True) +cam_d=bpy.data.cameras.new("C"); cam=bpy.data.objects.new("C",cam_d) +bpy.context.scene.collection.objects.link(cam); bpy.context.scene.camera=cam +cam.location=(3.6,-9.0,2.6) +d=mathutils.Vector((3.6,0,0.5))-cam.location +cam.rotation_euler=d.to_track_quat('-Z','Y').to_euler() +sun=bpy.data.objects.new("S", bpy.data.lights.new("S",'SUN')) +bpy.context.scene.collection.objects.link(sun); sun.rotation_euler=(0.9,0.2,0.7); sun.data.energy=3.5 +sc=bpy.context.scene; sc.render.engine='CYCLES'; sc.cycles.samples=18 +sc.render.resolution_x=1250; sc.render.resolution_y=470 +sc.render.filepath=r"C:\Users\az319\AppData\Local\Temp\claude\A--eco-EcoGame--claude-worktrees-rock-generator-hardening-3d5f61\cf805d69-059c-4821-ac92-afae28022987\scratchpad\formen.png" +bpy.ops.render.render(write_still=True) +r.unregister() +print("ERGEBNIS:", "ALLE CHECKS OK" if not fails else "FEHLER: "+", ".join(fails))