Tree Gen 1.43.0: UCX in _Pieces_All.fbx - und zwei Fehler, die dabei auffielen
Die Gesamtdatei kam ohne Kollision an, waehrend die Einzeldateien welche hatten. Jetzt bekommt jedes Teil auch dort seine Huelle, gleiche Konvention wie beim Stand-Baum: UCX_<Teilname> als Geschwister, kein Elternteil. Sie entstehen VOR dem Umsetzen der Pivots, weil in der Gesamtdatei alle Teile noch an ihrer Originalposition stehen. Beim Nachmessen kamen zwei Fehler heraus, die auch die BESTEHENDEN Einzeldateien betrafen: 1) Die Huellen umschlossen das Laub mit _tree_ucx las alle Vertices eines Teils, also auch die Blatt-Cards. Gemessen am baum-Preset war die Huelle dadurch 1.4- bis 2.1-mal so gross wie das Holz. Jetzt nur noch Material-Slot 0. Die Spielseite hatte das fuer ihre Interim-Boxen laengst so gemacht - zu Recht. 2) Das Aufweiten war fuer schlanke Teile kaputt Nach dem Vereinfachen wurde die Huelle durch Skalieren um die Huellenmitte aufgeblasen. Bei langgestreckten Teilen entgleist das: liegt eine Flaeche fast durch die Mitte, wird der Hebel winzig und der Faktor explodiert - gemessen 4.2 an einem Stammsegment mit Laenge zu Dicke 13:1. An der dicken Eiche blieb es bei 1.0-1.4, deshalb ist es nie aufgefallen; erst der Wechsel auf Rinde-only machte die Teile schlank genug. Jetzt wird je Flaeche der ECHTE Fehlbetrag gemessen und die Vertices um genau diesen Betrag nach aussen geschoben - eine Verschiebung in Metern, kein Verhaeltnis. Iterativ, weil ein Vertex mehreren Flaechen angehoert und entlang seiner eigenen Normale wandert (ein Durchgang liess einen Rest stehen, der Test schlug an). Bleibt danach etwas uebrig, faellt die Funktion auf die unvereinfachte Huelle zurueck. Ergebnis am 12-teiligen Baum: alle Huellen 14-31 Verts (Budget 32), keine groesser als das 1.35-fache ihres Holzes. test_faell_teile prueft die Gesamtdatei jetzt auf: je Teil genau eine Huelle, richtiger Name, kein Elternteil, und Huellengroesse gegen die RINDE. Gegenproben: ohne Rinde-Filter 10 Fehler (1.41x bis 2.06x), ohne Huellen in der Gesamtdatei 1 Fehler. 27 Tests bestehen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ Aufruf: blender --background --factory-startup --python tests/test_faell_teile.p
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import math
|
||||
import tempfile
|
||||
import importlib.util
|
||||
from collections import Counter
|
||||
@@ -171,13 +172,64 @@ if blatt_summe != cards_gesamt:
|
||||
if gesamt:
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
bpy.ops.import_scene.fbx(filepath=os.path.join(OUT, gesamt[0]))
|
||||
teile = [o for o in bpy.context.scene.objects if o.type == 'MESH']
|
||||
meshes = [o for o in bpy.context.scene.objects if o.type == 'MESH']
|
||||
teile = [o for o in meshes if not o.name.startswith("UCX_")]
|
||||
hullen = [o for o in meshes if o.name.startswith("UCX_")]
|
||||
alle = [o.matrix_world @ v.co for o in teile for v in o.data.vertices]
|
||||
hoehe = max(c.z for c in alle) - min(c.z for c in alle)
|
||||
print("Gesamtdatei: %d Teile, Hoehe %.2f m" % (len(teile), hoehe))
|
||||
print("Gesamtdatei: %d Teile, %d Huellen, Hoehe %.2f m"
|
||||
% (len(teile), len(hullen), hoehe))
|
||||
if len(teile) != len(einzeln):
|
||||
fails.append("Gesamtdatei hat %d Teile, einzeln waren es %d"
|
||||
% (len(teile), len(einzeln)))
|
||||
|
||||
# Die Gesamtdatei kam frueher OHNE Huellen an, waehrend die Einzeldateien
|
||||
# welche hatten - gemeldet von der Spielseite, die interimsweise eigene
|
||||
# Boxen setzen musste. Je Teil GENAU eine Huelle, gleiche Konvention wie
|
||||
# beim Stand-Baum: `UCX_<Teilname>` als Geschwister, kein Elternteil.
|
||||
namen = {o.name for o in teile}
|
||||
for h in hullen:
|
||||
if h.parent is not None:
|
||||
fails.append("Gesamtdatei: Huelle '%s' haengt unter '%s'"
|
||||
% (h.name, h.parent.name))
|
||||
if h.name[4:] not in namen:
|
||||
fails.append("Gesamtdatei: Huelle '%s' gehoert zu keinem Teil"
|
||||
% h.name)
|
||||
fehlend = sorted(n for n in namen if ("UCX_" + n) not in
|
||||
{h.name for h in hullen})
|
||||
if fehlend:
|
||||
fails.append("Gesamtdatei: %d Teile ohne Huelle (%s)"
|
||||
% (len(fehlend), ", ".join(fehlend[:3])))
|
||||
|
||||
# Und die Huelle umschliesst das HOLZ, nicht das Laub. Beim obersten
|
||||
# Stammsegment, das die Krone traegt, war der Unterschied gemessen 67 %
|
||||
# (Diagonale 1.75 m statt 1.05 m) - eine Kollision, die weit ins Laub ragt.
|
||||
nach_name = {o.name: o for o in teile}
|
||||
for h in hullen:
|
||||
koerper = nach_name.get(h.name[4:])
|
||||
if koerper is None:
|
||||
continue
|
||||
hc = [h.matrix_world @ v.co for v in h.data.vertices]
|
||||
rinde_idx = {vi for p in koerper.data.polygons
|
||||
if p.material_index == 0 for vi in p.vertices}
|
||||
if not rinde_idx:
|
||||
continue
|
||||
rc = [koerper.matrix_world @ koerper.data.vertices[i].co
|
||||
for i in rinde_idx]
|
||||
|
||||
def spanne(pts):
|
||||
lo = [min(c[i] for c in pts) for i in range(3)]
|
||||
hi = [max(c[i] for c in pts) for i in range(3)]
|
||||
return math.dist(lo, hi)
|
||||
|
||||
h_d, r_d = spanne(hc), spanne(rc)
|
||||
if h_d < r_d * 0.95:
|
||||
fails.append("%s: Huelle %.2f kleiner als die Rinde %.2f"
|
||||
% (h.name, h_d, r_d))
|
||||
if h_d > r_d * 1.35:
|
||||
fails.append("%s: Huelle %.2f gegen Rinde %.2f (%.2fx) - sie "
|
||||
"umschliesst das Laub mit"
|
||||
% (h.name, h_d, r_d, h_d / r_d))
|
||||
# Zusammengesetzt muss der Baum wieder seine volle Hoehe haben - das ist
|
||||
# der Beleg, dass die Teile deckungsgleich rekonstruierbar sind.
|
||||
if hoehe < 3.0:
|
||||
|
||||
Reference in New Issue
Block a user