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:
+50
-26
@@ -8,38 +8,62 @@ fails=[]
|
||||
for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True)
|
||||
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.name_prefix="Fels"; s.name_form="A"; s.name_class='M'
|
||||
res=bpy.ops.object.generate_rocks_batch()
|
||||
obs=[o for o in bpy.context.scene.objects if o.type=='MESH']
|
||||
ob=obs[0]
|
||||
s.shading_mode='FLAT'; s.bake_vertex_cavity=True; s.set_origin_bottom=True
|
||||
bpy.ops.object.generate_rocks_batch()
|
||||
ob=[o for o in bpy.context.scene.objects if o.type=='MESH'][0]
|
||||
me=ob.data
|
||||
names=[a.name for a in me.color_attributes]
|
||||
print("FARB-ATTRIBUTE:", names)
|
||||
if "Cavity" not in names: fails.append("kein_attribut")
|
||||
else:
|
||||
vals=[d.color[0] for d in me.color_attributes["Cavity"].data]
|
||||
vals.sort()
|
||||
print("CAVITY min=%.3f p10=%.3f median=%.3f max=%.3f (n=%d)"
|
||||
% (vals[0], vals[len(vals)//10], vals[len(vals)//2], vals[-1], len(vals)))
|
||||
if vals[-1]-vals[0] < 0.05: fails.append("kein_kontrast")
|
||||
# Faceted?
|
||||
sm=sum(1 for p in me.polygons if p.use_smooth)
|
||||
print("Shading: smooth=%d / flat=%d" % (sm, len(me.polygons)-sm))
|
||||
# FBX-Roundtrip: ueberleben die Vertex-Farben?
|
||||
tmp=tempfile.mkdtemp(); fp=os.path.join(tmp,"cav.fbx")
|
||||
d=me.color_attributes["Cavity"].data
|
||||
R=[x.color[0] for x in d]; G=[x.color[1] for x in d]
|
||||
B=[x.color[2] for x in d]; A=[x.color[3] for x in d]
|
||||
def rng_(v): return (min(v),max(v))
|
||||
print("R (Cavity) %.2f..%.2f | G (Moos) %.2f..%.2f | B (Hoehe) %.2f..%.2f | A %.2f..%.2f"
|
||||
% (*rng_(R),*rng_(G),*rng_(B),*rng_(A)))
|
||||
if max(R)-min(R)<0.05: fails.append("R_ohne_kontrast")
|
||||
if max(G)-min(G)<0.05: fails.append("G_ohne_kontrast")
|
||||
if max(A)!=1.0 or min(A)!=1.0: fails.append("A_nicht_1")
|
||||
|
||||
# B muss mit der Hoehe korrelieren
|
||||
zs=[me.vertices[me.loops[i].vertex_index].co.z for i in range(len(d))]
|
||||
zmin,zmax=min(zs),max(zs)
|
||||
lo=[B[i] for i in range(len(d)) if zs[i] < zmin+(zmax-zmin)*0.15]
|
||||
hi=[B[i] for i in range(len(d)) if zs[i] > zmin+(zmax-zmin)*0.85]
|
||||
print("B unten=%.2f oben=%.2f (muss steigen)" % (sum(lo)/len(lo), sum(hi)/len(hi)))
|
||||
if sum(lo)/len(lo) >= sum(hi)/len(hi): fails.append("B_falsch_herum")
|
||||
|
||||
# R darf KEINEN Hoehen-Verlauf mehr haben (das war v1)
|
||||
rlo=sum(R[i] for i in range(len(d)) if zs[i]<zmin+(zmax-zmin)*0.15)/max(1,len(lo))
|
||||
rhi=sum(R[i] for i in range(len(d)) if zs[i]>zmin+(zmax-zmin)*0.85)/max(1,len(hi))
|
||||
print("R unten=%.2f oben=%.2f (Differenz soll klein sein)" % (rlo,rhi))
|
||||
if abs(rlo-rhi) > 0.25: fails.append("R_hat_noch_verlauf")
|
||||
|
||||
# G soll oben mehr sein als unten
|
||||
glo=sum(G[i] for i in range(len(d)) if zs[i]<zmin+(zmax-zmin)*0.15)/max(1,len(lo))
|
||||
ghi=sum(G[i] for i in range(len(d)) if zs[i]>zmin+(zmax-zmin)*0.85)/max(1,len(hi))
|
||||
print("G unten=%.2f oben=%.2f (oben soll mehr sein)" % (glo,ghi))
|
||||
if ghi <= glo: fails.append("G_nicht_oben")
|
||||
|
||||
# Moos-Seed aendert die Verteilung?
|
||||
s.moss_seed=42
|
||||
for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True)
|
||||
bpy.ops.object.generate_rocks_batch()
|
||||
ob2=[o for o in bpy.context.scene.objects if o.type=='MESH'][0]
|
||||
G2=[x.color[1] for x in ob2.data.color_attributes["Cavity"].data]
|
||||
same = len(G)==len(G2) and all(abs(a-b)<1e-4 for a,b in zip(G,G2))
|
||||
print("Moos-Seed 0 vs 42 identisch:", same)
|
||||
if same: fails.append("seed_wirkungslos")
|
||||
|
||||
# FBX-Roundtrip
|
||||
tmp=tempfile.mkdtemp(); fp=os.path.join(tmp,"v2.fbx")
|
||||
for o in bpy.context.selected_objects: o.select_set(False)
|
||||
ob.select_set(True); bpy.context.view_layer.objects.active=ob
|
||||
ob2.select_set(True); bpy.context.view_layer.objects.active=ob2
|
||||
bpy.ops.export_scene.fbx(filepath=fp, use_selection=True, colors_type='SRGB',
|
||||
mesh_smooth_type='FACE', use_triangles=True)
|
||||
for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True)
|
||||
bpy.ops.import_scene.fbx(filepath=fp)
|
||||
imp=[o for o in bpy.data.objects if o.type=='MESH'][0]
|
||||
inames=[a.name for a in imp.data.color_attributes]
|
||||
print("NACH FBX-ROUNDTRIP:", inames, "Tris=%d" % sum(len(p.vertices)-2 for p in imp.data.polygons))
|
||||
if not inames: fails.append("fbx_verliert_farben")
|
||||
else:
|
||||
iv=[d.color[0] for d in imp.data.color_attributes[0].data]
|
||||
print(" Wertebereich nach Import: %.3f .. %.3f" % (min(iv), max(iv)))
|
||||
id_=imp.data.color_attributes[0].data
|
||||
iR=[x.color[0] for x in id_]; iG=[x.color[1] for x in id_]; iB=[x.color[2] for x in id_]
|
||||
print("NACH FBX: R %.2f..%.2f G %.2f..%.2f B %.2f..%.2f" % (*rng_(iR),*rng_(iG),*rng_(iB)))
|
||||
if max(iG)-min(iG)<0.05 or max(iB)-min(iB)<0.05: fails.append("fbx_kanaele_verloren")
|
||||
r.unregister()
|
||||
print("ERGEBNIS:", "ALLE CHECKS OK" if not fails else "FEHLER: "+", ".join(fails))
|
||||
|
||||
Reference in New Issue
Block a user