Tree Gen 1.31.0: LOD1-3 trugen die Standposition mit (aus UE gemeldet)
Fehler: _origin_bottom_center backt zuerst die Weltmatrix ins Mesh und wendet DANN die Zentrierung an - zurueck gibt es aber nur die Zentrierung. Den Stufen 1-3 wurde nur diese aufgedrueckt, ihre Weltmatrix blieb ungebacken. Ergebnis: sie landeten bei MINUS der Standposition. Gemeldet fuer einen Baum bei x = 18 m, dessen LOD1-3 bei x = -1894 cm sassen - exakt die Standposition, in Zentimetern wegen FBX_SCALE_ALL. Jetzt backt jede Stufe erst ihre EIGENE Weltmatrix, dann kommt die gemeinsame Zentrierung aus LOD0. Warum der Test das nicht gefunden hat: er baute den Baum am URSPRUNG. Dort ist minus null eben null. Der Baum steht jetzt bewusst bei (18, -7.5), und je Stufe wird die X/Y-Mitte im reimportierten FBX gemessen - an derselben Stelle wie die Radialitaets-Pruefung. Gegenprobe gemacht: mit zurueckgedrehtem Fix meldet der Test LOD1-3 bei -17.87/7.46, also exakt minus der Standposition, und faellt mit 6 Fehlern durch. Mit Fix liegen alle Stufen bei 0.000-0.135 um den Ursprung. Ausserdem Dichte 170 -> 150. Grund: mit der REALEN Diamond-Card (6 Tris, nicht die 2-Tri-Attrappe aus meinen Sweeps) landet die Eiche bei Dichte 170 auf 4206 Tris - 2778 Krone plus 1428 Stamm - und damit ueber dem 4000er-Budget aus ASSETS.md Teil 6. Die abgenommene Krone (2778) und das dokumentierte Budget (4000) sind also nicht gleichzeitig haltbar. 150 liegt im abgesegneten Sweetspot 130-170 und haelt das Budget mit 3816. Wenn der Look bei 170 wichtiger ist, muesste das Budget auf ~4300 - das ist eine Entscheidung der Spielseite. Nebenbei: test_leaves hatte leaf_size fest auf 0.22 stehen (alter Blaettchen-Wert) und pruefte gegen ein fest verdrahtetes 2500er-Budget. Beides kommt jetzt aus den Einstellungen. 23 Tests bestehen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+52
-15
@@ -8,6 +8,12 @@ Gemessen wird am reimportierten FBX, und die Kugel-Normalen werden auf JEDER
|
||||
Stufe geprueft: LOD1-3 haben eine eigene Card-Verteilung, die Normalen muessen
|
||||
dazu passen. Nur LOD0 zu pruefen wuerde genau das verfehlen.
|
||||
|
||||
WICHTIG: Der Baum steht hier NICHT am Ursprung. Eine fruehere Fassung dieses
|
||||
Tests baute ihn bei (0,0,0) - und ist damit an einem Fehler vorbeigelaufen, den
|
||||
die Spielseite gefunden hat: LOD1-3 landeten bei MINUS der Standposition, weil
|
||||
ihre Weltmatrix nie ins Mesh gebacken wurde. Bei x = 0 faellt das nicht auf,
|
||||
weil minus null eben null ist.
|
||||
|
||||
Aufruf: blender --background --factory-startup --python tests/test_baum_lod.py
|
||||
"""
|
||||
import os
|
||||
@@ -53,11 +59,19 @@ bpy.ops.object.treegen_create()
|
||||
baum = [o for o in bpy.context.scene.objects
|
||||
if o.type == 'MESH' and o.name.startswith("Eiche_01")
|
||||
and not o.name.endswith(("_Leaf", "_Frucht"))][0]
|
||||
|
||||
# Der Baum wird BEWUSST weit vom Ursprung gestellt - siehe Kopf der Datei.
|
||||
STANDORT = (18.0, -7.5, 0.0)
|
||||
baum.location = STANDORT
|
||||
for o in bpy.context.scene.objects:
|
||||
o.select_set(o is baum)
|
||||
bpy.context.view_layer.objects.active = baum
|
||||
s.leaf_card = card
|
||||
bpy.ops.object.treegen_leaves()
|
||||
# Die Blattebene muss mit an die Standposition - sie folgt dem Stamm.
|
||||
_bl = bpy.data.objects.get(baum.name + "_Leaf")
|
||||
if _bl is not None:
|
||||
_bl.location = STANDORT
|
||||
|
||||
for o in bpy.context.scene.objects:
|
||||
o.select_set(o is baum)
|
||||
@@ -86,8 +100,11 @@ meshes = [o for o in bpy.context.scene.objects if o.type == 'MESH']
|
||||
empties = [o for o in bpy.context.scene.objects if o.type == 'EMPTY']
|
||||
stufen = sorted(meshes, key=lambda o: o.name)
|
||||
print("")
|
||||
print("%-24s %7s %7s %7s %9s %s"
|
||||
% ("Stufe", "Rinde", "Blatt", "Tris", "Radial", "Slots"))
|
||||
print("Baum stand bei x=%.1f, y=%.1f - die Stufen muessen trotzdem um den "
|
||||
"Ursprung liegen." % (STANDORT[0], STANDORT[1]))
|
||||
print("")
|
||||
print("%-24s %7s %7s %7s %9s %9s %9s"
|
||||
% ("Stufe", "Rinde", "Blatt", "Tris", "Radial", "X-Mitte", "Y-Mitte"))
|
||||
|
||||
if len(stufen) != len(tg.LOD_STUFEN):
|
||||
fails.append("%d LOD-Meshes, erwartet %d" % (len(stufen), len(tg.LOD_STUFEN)))
|
||||
@@ -96,6 +113,7 @@ if not empties:
|
||||
|
||||
blatt_zahlen = []
|
||||
rinde_zahlen = []
|
||||
spannen = []
|
||||
for ob in stufen:
|
||||
m = ob.data
|
||||
rinde = sum(1 for p in m.polygons if p.material_index == 0)
|
||||
@@ -126,9 +144,18 @@ for ob in stufen:
|
||||
treffer += 1
|
||||
quote = 100.0 * treffer / gesamt if gesamt else 0.0
|
||||
|
||||
print("%-24s %7d %7d %7d %8.0f%% %s"
|
||||
% (ob.name, rinde, laub, tris, quote,
|
||||
[x.name if x else "-" for x in m.materials]))
|
||||
# X/Y-Spanne dieser Stufe im FBX. Alle Stufen muessen deckungsgleich um
|
||||
# den Ursprung liegen - eine verschobene Stufe waere in UE beim
|
||||
# LOD-Wechsel schlagartig woanders.
|
||||
co = [ob.matrix_world @ v.co for v in m.vertices]
|
||||
lo = [min(c[i] for c in co) for i in range(3)]
|
||||
hi = [max(c[i] for c in co) for i in range(3)]
|
||||
xm = (lo[0] + hi[0]) * 0.5
|
||||
ym = (lo[1] + hi[1]) * 0.5
|
||||
spannen.append((ob.name, xm, ym, lo, hi))
|
||||
|
||||
print("%-24s %7d %7d %7d %8.0f%% %9.3f %9.3f"
|
||||
% (ob.name, rinde, laub, tris, quote, xm, ym))
|
||||
|
||||
if len(m.materials) != 2:
|
||||
fails.append("%s: %d Slots, erwartet 2" % (ob.name, len(m.materials)))
|
||||
@@ -160,18 +187,28 @@ if blatt_zahlen and blatt_zahlen[0] > 0:
|
||||
"teuer" % anteil)
|
||||
|
||||
# --- Alle Stufen deckungsgleich am Ursprung ------------------------------
|
||||
for ob in stufen:
|
||||
co = [ob.matrix_world @ v.co for v in ob.data.vertices]
|
||||
lo = [min(c[i] for c in co) for i in range(3)]
|
||||
hi = [max(c[i] for c in co) for i in range(3)]
|
||||
if abs((lo[0] + hi[0]) * 0.5) > 0.25 or abs((lo[1] + hi[1]) * 0.5) > 0.25:
|
||||
fails.append("%s: Bbox nicht zentriert (%.2f/%.2f)"
|
||||
% (ob.name, (lo[0] + hi[0]) * 0.5, (lo[1] + hi[1]) * 0.5))
|
||||
# Die Stufen muessen auf derselben Hoehe stehen - sonst springt der Baum
|
||||
# beim LOD-Wechsel.
|
||||
# Das ist der Test fuer den aus UE gemeldeten Fehler: LOD1-3 sassen bei MINUS
|
||||
# der Standposition, weil ihre Weltmatrix nie ins Mesh gebacken wurde.
|
||||
print("")
|
||||
for name, xm, ym, lo, hi in spannen:
|
||||
if abs(xm) > 0.25 or abs(ym) > 0.25:
|
||||
fails.append("%s: Mitte bei %.2f/%.2f statt am Ursprung - die Stufe "
|
||||
"traegt die Standposition des Baums (%.1f/%.1f) mit"
|
||||
% (name, xm, ym, STANDORT[0], STANDORT[1]))
|
||||
if abs(lo[2]) > 0.15:
|
||||
fails.append("%s: steht %.3f m ueber/unter dem Ursprung - der Baum "
|
||||
"wuerde beim LOD-Wechsel springen" % (ob.name, lo[2]))
|
||||
"wuerde beim LOD-Wechsel springen" % (name, lo[2]))
|
||||
|
||||
# Und die Stufen muessen ZUEINANDER passen, nicht nur je einzeln zum Ursprung.
|
||||
if len(spannen) > 1:
|
||||
_, x0, y0, lo0, hi0 = spannen[0]
|
||||
for name, xm, ym, lo, hi in spannen[1:]:
|
||||
if abs(xm - x0) > 0.30 or abs(ym - y0) > 0.30:
|
||||
fails.append("%s liegt %.2f/%.2f neben LOD0 - beim LOD-Wechsel "
|
||||
"wuerde der Baum springen" % (name, xm - x0, ym - y0))
|
||||
print("Versatz zu LOD0: %s"
|
||||
% ", ".join("%s %.3f/%.3f" % (n.split("_")[-1], x - x0, y - y0)
|
||||
for n, x, y, _, _ in spannen[1:]))
|
||||
|
||||
print("")
|
||||
if fails:
|
||||
|
||||
Reference in New Issue
Block a user