Rock Generator 2.9.0: Vertex-Farb-Layout v2 (kanal-getrennt)
Nach Wunschliste des Users. Attribut "Cavity" traegt jetzt drei UNABHAENGIGE
Masken statt einer eingebackenen Mischung:
R = Cavity pur 1 = offene Flaeche, 0 = tiefe Fuge - OHNE Hoehen-Verlauf
G = Moos/Schmutz aus Oberseiten-Anteil + Fugennaehe + Noise, mit Reglern
fuer Menge, Aufbruch und Seed
B = Hoehen-Verlauf 0 = Unterseite, 1 = oben, separat
A = 1 (Reserve)
Der Punkt: Boden-Saum und Moosfarbe entscheidet jetzt das MATERIAL pro Instanz,
nicht mehr das Mesh. In v1 steckte der Verlauf fest in R und liess sich nicht
mehr trennen.
Gemessen: R ohne Hoehenabhaengigkeit (unten 0.62 / oben 0.59 - vorher war das
der eingebackene Verlauf), B steigt 0.08 -> 0.92, G oben 0.57 vs unten 0.20,
A konstant 1.00. Moos-Seed aendert die Verteilung. Alle drei Kanaele ueberleben
den FBX-Roundtrip.
tests/test_vertex_cavity.py prueft jeden Kanal einzeln inkl. Roundtrip.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+64
-32
@@ -1,7 +1,7 @@
|
||||
bl_info = {
|
||||
"name": "Stylized Rock Generator",
|
||||
"author": "D4rkst3r",
|
||||
"version": (2, 8, 1),
|
||||
"version": (2, 9, 0),
|
||||
"blender": (4, 2, 0),
|
||||
"location": "View3D > Sidebar > Rock Gen",
|
||||
"description": (
|
||||
@@ -60,7 +60,8 @@ PRESET_KEYS = (
|
||||
"shading_mode", "autosmooth_angle",
|
||||
"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", "cavity_gradient",
|
||||
"bake_vertex_cavity", "cavity_strength", "cavity_blur",
|
||||
"moss_amount", "moss_noise", "moss_seed",
|
||||
"use_class_size", "base_size",
|
||||
)
|
||||
|
||||
@@ -455,23 +456,27 @@ def _apply_random_transform(context, obj, settings, rng):
|
||||
|
||||
|
||||
def _bake_vertex_cavity(context, obj, settings):
|
||||
"""Cavity + Hoehen-Verlauf in die VERTEX-FARBEN backen.
|
||||
"""Vertex-Farb-Layout v2 - KANAL-GETRENNT im Attribut "Cavity".
|
||||
|
||||
Warum: das Material braucht damit KEINE Textur. Base Color = Farbton x
|
||||
Vertex-Farbe, dazu Kantenlicht und Schattentint im Shader - genau der
|
||||
Genshin-Aufbau. Ausserdem sitzen die dunklen Fugen auf den ECHTEN Kanten
|
||||
des Meshes, statt per Triplanar darueberzuschweben.
|
||||
R = Cavity pur 1 = offene Flaeche, 0 = tiefe Fuge (ohne Verlauf!)
|
||||
G = Moos/Schmutz 1 = hier waechst was (Oberseite + Fugennaehe + Noise)
|
||||
B = Hoehen-Verlauf 0 = Unterseite, 1 = oben
|
||||
A = 1 (Reserve)
|
||||
|
||||
Aufloesung haengt an der Vertex-Dichte; fuer flaechige Platten reicht das,
|
||||
fuer feine Struktur nicht (dann Textur nehmen).
|
||||
Getrennt statt eingebacken, damit das Material selbst entscheidet: Boden-Saum
|
||||
und Moosfarbe werden pro Material-Instanz geregelt, nicht im Mesh festgelegt.
|
||||
"""
|
||||
import random as _rnd
|
||||
me = obj.data
|
||||
layer = me.color_attributes.get("Cavity")
|
||||
if layer is None:
|
||||
layer = me.color_attributes.new(name="Cavity", type='BYTE_COLOR', domain='CORNER')
|
||||
me.color_attributes.active_color = layer
|
||||
me.color_attributes.render_color_index = me.color_attributes.find("Cavity")
|
||||
idx = me.color_attributes.find("Cavity")
|
||||
if idx >= 0:
|
||||
me.color_attributes.render_color_index = idx
|
||||
|
||||
# --- R: Cavity ueber Blenders Dirty-Vertex-Colors ---
|
||||
_deselect_all(context)
|
||||
context.view_layer.objects.active = obj
|
||||
obj.select_set(True)
|
||||
@@ -481,36 +486,51 @@ def _bake_vertex_cavity(context, obj, settings):
|
||||
pass
|
||||
try:
|
||||
bpy.ops.paint.vertex_color_dirt(
|
||||
blur_strength=1.0,
|
||||
blur_iterations=settings.cavity_blur,
|
||||
clean_angle=3.14159,
|
||||
dirt_angle=0.0,
|
||||
dirt_only=False,
|
||||
normalize=True,
|
||||
blur_strength=1.0, blur_iterations=settings.cavity_blur,
|
||||
clean_angle=3.14159, dirt_angle=0.0, dirt_only=False, normalize=True,
|
||||
)
|
||||
except RuntimeError as exc:
|
||||
raise RockGenError("Vertex-Cavity fehlgeschlagen: %s" % exc)
|
||||
|
||||
# Staerke regeln + optionaler Hoehen-Verlauf (unten dunkler, wie in der
|
||||
# Referenz). Beides direkt auf den Farbwerten, das ist schnell genug.
|
||||
data = layer.data
|
||||
cav_raw = [data[i].color[0] for i in range(len(data))]
|
||||
|
||||
zs = [v.co.z for v in me.vertices]
|
||||
if not zs:
|
||||
return
|
||||
zmin, zmax = min(zs), max(zs)
|
||||
span = max(zmax - zmin, 1e-6)
|
||||
|
||||
# Normalen je Loop fuer den Oberseiten-Anteil
|
||||
me.calc_normals_split() if hasattr(me, "calc_normals_split") else None
|
||||
rng = _rnd.Random(settings.moss_seed)
|
||||
# Noise-Wert je VERTEX (nicht je Loop), damit er nicht flackert
|
||||
vnoise = [rng.random() for _ in range(len(me.vertices))]
|
||||
|
||||
amt = settings.cavity_strength
|
||||
grad = settings.cavity_gradient
|
||||
data = layer.data
|
||||
moss = settings.moss_amount
|
||||
mnoise = settings.moss_noise
|
||||
|
||||
for poly in me.polygons:
|
||||
nz = poly.normal.z # 1 = zeigt nach oben
|
||||
for li in poly.loop_indices:
|
||||
vi = me.loops[li].vertex_index
|
||||
c = data[li].color
|
||||
val = 1.0 - (1.0 - c[0]) * amt # Cavity abschwaechen
|
||||
if grad > 0.0:
|
||||
t = (me.vertices[vi].co.z - zmin) / span
|
||||
val *= (1.0 - grad) + grad * (0.35 + 0.65 * t)
|
||||
val = max(0.0, min(1.0, val))
|
||||
data[li].color = (val, val, val, 1.0)
|
||||
c_raw = cav_raw[li]
|
||||
|
||||
# R: reine Cavity, Staerke geregelt, KEIN Hoehen-Verlauf
|
||||
r = max(0.0, min(1.0, 1.0 - (1.0 - c_raw) * amt))
|
||||
|
||||
# B: Hoehen-Verlauf 0..1
|
||||
b = max(0.0, min(1.0, (me.vertices[vi].co.z - zmin) / span))
|
||||
|
||||
# G: Moos - Oberseite UND Fugennaehe, mit Noise aufgebrochen
|
||||
up = max(0.0, nz) # 0 unten, 1 oben
|
||||
crev = 1.0 - c_raw # 1 in der Fuge
|
||||
base = up * 0.7 + crev * 0.5
|
||||
n = 1.0 - mnoise + mnoise * vnoise[vi]
|
||||
g = max(0.0, min(1.0, base * n * moss * 1.6))
|
||||
|
||||
data[li].color = (r, g, b, 1.0)
|
||||
|
||||
|
||||
def _apply_shading(context, obj, settings):
|
||||
@@ -807,10 +827,18 @@ class RockGenSettings(PropertyGroup):
|
||||
name="Weichzeichnen", default=1, min=0, max=5,
|
||||
description="Glaettet den Cavity-Verlauf ueber benachbarte Vertices",
|
||||
)
|
||||
cavity_gradient: FloatProperty(
|
||||
name="Hoehen-Verlauf", default=0.35, min=0.0, max=1.0,
|
||||
description=("Dunkelt den Stein nach unten hin ab (wie in der Referenz). "
|
||||
"0 = aus"),
|
||||
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) "
|
||||
"markiert. Die FARBE bestimmt das Material, nicht das Mesh"),
|
||||
)
|
||||
moss_noise: FloatProperty(
|
||||
name="Moos-Aufbruch", default=0.55, min=0.0, max=1.0,
|
||||
description="Bricht die Maske mit Rauschen auf, damit sie nicht flaechig wirkt",
|
||||
)
|
||||
moss_seed: IntProperty(
|
||||
name="Moos-Seed", default=0, min=0, max=9999,
|
||||
description="Anderer Wert = andere Moos-Verteilung bei gleicher Form",
|
||||
)
|
||||
|
||||
# --- Material ---
|
||||
@@ -1658,8 +1686,12 @@ class VIEW3D_PT_rock_generator(Panel):
|
||||
sub = box.column(align=True)
|
||||
sub.enabled = settings.bake_vertex_cavity
|
||||
sub.prop(settings, "cavity_strength")
|
||||
sub.prop(settings, "cavity_gradient")
|
||||
sub.prop(settings, "cavity_blur")
|
||||
sub.separator()
|
||||
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')
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Material")
|
||||
|
||||
Reference in New Issue
Block a user