Tree Gen 1.34.0: Ziel-Cardzahl statt Dichte-Konstanten + Ursprung aus dem Stamm
Zwei Befunde von der Spielseite.
1) Dichte-Kompensation ueberschoss preset-abhaengig
Die Eichung am Standardbaum (11 Cards / 486 Tris) kam auf der Eiche als
1008 Tris an. Ursache ist strukturell: "Dichte" ist Punkte pro m2
Zweigflaeche, und die verteilt sich je Preset voellig anders. Jeder
Konstanten-Satz haette fuer den naechsten Baum neu geeicht werden muessen.
Strukturwechsel wie vorgeschlagen: in LEAF_STUFEN steht jetzt die
ZIEL-STUECKZAHL (S1 10, S2 40, S3 120, S4 = volle Dichte), und der Generator
regelt die Dichte per Bisektion dagegen ein. Der Seed wird dabei nicht
angefasst - gleicher Baum und Seed ergeben dieselbe Verteilung.
Gemessen ueber vier Presets (Ziel 10 / 40 / 120):
baum 9 41 104 eiche 10 43 138
birke 9 36 136 tanne 9 38 125
Die Eiche liegt bei S1 jetzt bei 576 Tris statt 1008.
Der Test prueft die Anzahl DIREKT, statt ueber Dichte x Anteil x Flaeche zu
rechnen - genau der Punkt des Vorschlags.
2) Baum stand "etwas in der Luft"
Der Export-Ursprung kam aus der Gesamt-Bbox inklusive Blatt-Cards. Eine
einzige tief haengende Card hebt damit den ganzen Baum an. Jetzt kommt er aus
der STAMM-Geometrie (Slot 0). Gemessen an der Eiche: Stamm-min.Z 0.000 auf
allen vier Stufen, waehrend die Gesamtbox bei S1 auf -0.106 liegt - das waren
die 10 cm, um die er zu hoch stand.
Beim Einbauen selbst verursacht und behoben: eine abgebrochene Befehlskette
liess die Operator-Verdrahtung aus, wodurch die Dichte mit der ZIEL-ANZAHL
multipliziert wurde (170 x 40) - 732 Cards statt 40. Faellt sofort auf, wenn man
die Zahlen anschaut, statt den Durchlauf fuer erfolgreich zu halten.
23 Tests bestehen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -403,6 +403,24 @@ gemessen und abgenommen:
|
|||||||
Zweigspitzen Laub, die Krone hatte nur Kontur und war innen nackt. Bei 0.04
|
Zweigspitzen Laub, die Krone hatte nur Kontur und war innen nackt. Bei 0.04
|
||||||
wachsen Bueschel auch am mittleren Geaest und die Krone bekommt Tiefe.
|
wachsen Bueschel auch am mittleren Geaest und die Krone bekommt Tiefe.
|
||||||
|
|
||||||
|
**Ziel-Cardzahl statt Dichte-Konstanten.** Dichte-Faktoren mussten je Preset neu
|
||||||
|
geeicht werden: „Dichte" ist Punkte pro m² *Zweigflaeche*, und die verteilt sich
|
||||||
|
je Baum voellig anders — ein Faktor, der am Standardbaum 11 Cards ergab,
|
||||||
|
ueberschoss auf der Eiche um mehr als das Doppelte. In `LEAF_STUFEN` steht
|
||||||
|
deshalb die gewuenschte **Stueckzahl**, und der Generator regelt die Dichte per
|
||||||
|
Bisektion dagegen ein (seed-stabil, der Seed wird nicht angefasst). Damit ist die
|
||||||
|
Kalibrierung preset-unabhaengig und der Test prueft die Anzahl **direkt**:
|
||||||
|
|
||||||
|
| Preset | S1 (Ziel 10) | S2 (Ziel 40) | S3 (Ziel 120) | S4 (voll) |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| baum | 9 · 518 Tris | 41 · 914 | 104 · 1436 | 130 · 1916 |
|
||||||
|
| eiche | 10 · 576 | 43 · 998 | 138 · 1872 | 463 · 4206 |
|
||||||
|
| birke | 9 · 570 | 36 · 1028 | 136 · 1952 | 207 · 2894 |
|
||||||
|
| tanne | 9 · 778 | 38 · 1160 | 125 · 2282 | 235 · 3302 |
|
||||||
|
|
||||||
|
S4 wird **nicht** geregelt — der Altbaum ist die Referenz, an der die Dichte
|
||||||
|
ueberhaupt eingestellt wurde.
|
||||||
|
|
||||||
**Deckung pro Stufe, nicht per Formel.** Card-Anteil und Groesse stehen als
|
**Deckung pro Stufe, nicht per Formel.** Card-Anteil und Groesse stehen als
|
||||||
Tabelle (`LEAF_STUFEN`). Der Dichte-Anteil bei S1/S2 sieht hoch aus — das
|
Tabelle (`LEAF_STUFEN`). Der Dichte-Anteil bei S1/S2 sieht hoch aus — das
|
||||||
taeuscht: „Dichte" ist Punkte pro m² *Zweigflaeche*, und die waechst ueber die
|
taeuscht: „Dichte" ist Punkte pro m² *Zweigflaeche*, und die waechst ueber die
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
schema_version = "1.0.0"
|
schema_version = "1.0.0"
|
||||||
|
|
||||||
id = "stylized_tree_generator"
|
id = "stylized_tree_generator"
|
||||||
version = "1.33.0"
|
version = "1.34.0"
|
||||||
name = "Stylized Tree Generator"
|
name = "Stylized Tree Generator"
|
||||||
tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen"
|
tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen"
|
||||||
maintainer = "D4rkst3r"
|
maintainer = "D4rkst3r"
|
||||||
|
|||||||
Vendored
+3
-3
@@ -50,17 +50,17 @@
|
|||||||
<td>34.1KB</td>
|
<td>34.1KB</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><tt><a href="./stylized_tree_generator-1.33.0.zip?repository=.%2Findex.json&blender_version_min=4.2.0">stylized_tree_generator-1.33.0</a></tt></td>
|
<td><tt><a href="./stylized_tree_generator-1.34.0.zip?repository=.%2Findex.json&blender_version_min=4.2.0">stylized_tree_generator-1.34.0</a></tt></td>
|
||||||
<td>Stylized Tree Generator</td>
|
<td>Stylized Tree Generator</td>
|
||||||
<td>Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen</td>
|
<td>Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen</td>
|
||||||
<td><a href="https://git.d4rkst3r.de/D4rkst3r/stylized-rock-generator">link</a></td>
|
<td><a href="https://git.d4rkst3r.de/D4rkst3r/stylized-rock-generator">link</a></td>
|
||||||
<td>4.2.0 - ~</td>
|
<td>4.2.0 - ~</td>
|
||||||
<td>all</td>
|
<td>all</td>
|
||||||
<td>all</td>
|
<td>all</td>
|
||||||
<td>38.5KB</td>
|
<td>40.0KB</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<center><p>Built 2026-08-06, 08:08</p></center>
|
<center><p>Built 2026-08-06, 08:32</p></center>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Vendored
+4
-4
@@ -82,7 +82,7 @@
|
|||||||
"id": "stylized_tree_generator",
|
"id": "stylized_tree_generator",
|
||||||
"name": "Stylized Tree Generator",
|
"name": "Stylized Tree Generator",
|
||||||
"tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen",
|
"tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen",
|
||||||
"version": "1.33.0",
|
"version": "1.34.0",
|
||||||
"type": "add-on",
|
"type": "add-on",
|
||||||
"maintainer": "D4rkst3r",
|
"maintainer": "D4rkst3r",
|
||||||
"license": [
|
"license": [
|
||||||
@@ -98,9 +98,9 @@
|
|||||||
"Mesh",
|
"Mesh",
|
||||||
"Modeling"
|
"Modeling"
|
||||||
],
|
],
|
||||||
"archive_url": "./stylized_tree_generator-1.33.0.zip",
|
"archive_url": "./stylized_tree_generator-1.34.0.zip",
|
||||||
"archive_size": 39431,
|
"archive_size": 40964,
|
||||||
"archive_hash": "sha256:757cecfccbac8f1a50eadd62d47b9439d98550ad2f0677604ed6832610fd74f8"
|
"archive_hash": "sha256:1cb548b5fef9bb79342ef92f7bc40f7ecb66e21f6356c8e00623ada5c842b0d6"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+141
-18
@@ -1,7 +1,7 @@
|
|||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "Stylized Tree Generator",
|
"name": "Stylized Tree Generator",
|
||||||
"author": "D4rkst3r",
|
"author": "D4rkst3r",
|
||||||
"version": (1, 33, 0),
|
"version": (1, 34, 0),
|
||||||
"blender": (4, 2, 0),
|
"blender": (4, 2, 0),
|
||||||
"location": "View3D > Sidebar > Tree Gen",
|
"location": "View3D > Sidebar > Tree Gen",
|
||||||
"description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen",
|
"description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen",
|
||||||
@@ -1434,20 +1434,30 @@ def leaf_socket_ids(ng):
|
|||||||
LEAF_RADIUS_YOUNG = 0.20
|
LEAF_RADIUS_YOUNG = 0.20
|
||||||
|
|
||||||
# Dichte-Anteil Groessen-Anteil
|
# Dichte-Anteil Groessen-Anteil
|
||||||
# Dichte Groesse Kronenansatz
|
# ZIEL-ANZAHL statt Dichte-Anteil.
|
||||||
|
#
|
||||||
|
# Dichte-Faktoren waren preset-abhaengig und mussten fuer jeden Baum neu
|
||||||
|
# geeicht werden: "Dichte" ist Punkte pro m2 Zweigflaeche, und die verteilt sich
|
||||||
|
# je Preset voellig anders. Ein Faktor, der am Standardbaum 11 Cards ergab,
|
||||||
|
# lieferte auf der Eiche mehr als das Doppelte - die Kompensation ueberschoss.
|
||||||
|
#
|
||||||
|
# Jetzt steht die gewuenschte Card-ANZAHL da, und der Generator regelt die
|
||||||
|
# Dichte per Bisektion dagegen ein. Das ist preset-unabhaengig, und der Test
|
||||||
|
# kann die Anzahl DIREKT pruefen statt ueber Dichte x Anteil x Flaeche zu
|
||||||
|
# rechnen. None = nicht regeln, volle Dichte (der Altbaum ist die Referenz,
|
||||||
|
# an der die Dichte ueberhaupt eingestellt wurde).
|
||||||
|
#
|
||||||
|
# Ziel-Cards Groesse Kronenansatz
|
||||||
LEAF_STUFEN = (
|
LEAF_STUFEN = (
|
||||||
# S1/S2 Dichte nachgezogen, nachdem der Hoehen-Filter dazukam: er nimmt dem
|
(10, 0.45, 0.40), # S1 - wenige kleine Bueschel, Fuss bleibt frei
|
||||||
# Setzling die Haelfte der Cards (9 -> 4), weil dessen Laub vorher ueber die
|
(40, 0.63, 0.35), # S2
|
||||||
# ganze Stammhoehe verteilt war.
|
(120, 0.82, 0.30), # S3
|
||||||
(13.0, 0.45, 0.40), # S1 - wenige kleine Bueschel, Fuss bleibt frei
|
(None, 1.00, 0.25), # S4 - volle Dichte, keine Regelung
|
||||||
(2.10, 0.63, 0.35), # S2
|
|
||||||
(1.00, 0.82, 0.30), # S3
|
|
||||||
(1.00, 1.00, 0.25), # S4 - Sicherheitsnetz, hier sitzt ohnehin nichts tief
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _stufen_anteile(growth_t):
|
def _stufen_anteile(growth_t):
|
||||||
"""Dichte-, Groessen- und Kronenansatz-Wert fuer einen Wachstums-Fortschritt.
|
"""Ziel-Cardzahl, Groessen- und Kronenansatz-Wert fuer einen Wachstums-Fortschritt.
|
||||||
|
|
||||||
Die Stufen liegen bei t = 0 / 1/3 / 2/3 / 1 (vier Stufen). Zwischen den
|
Die Stufen liegen bei t = 0 / 1/3 / 2/3 / 1 (vier Stufen). Zwischen den
|
||||||
Stuetzstellen wird linear gemischt, damit auch drei oder fuenf Stufen
|
Stuetzstellen wird linear gemischt, damit auch drei oder fuenf Stufen
|
||||||
@@ -1457,9 +1467,12 @@ def _stufen_anteile(growth_t):
|
|||||||
x = max(0.0, min(1.0, growth_t)) * (n - 1)
|
x = max(0.0, min(1.0, growth_t)) * (n - 1)
|
||||||
i = min(int(x), n - 2)
|
i = min(int(x), n - 2)
|
||||||
f = x - i
|
f = x - i
|
||||||
d0, g0, h0 = LEAF_STUFEN[i]
|
z0, g0, h0 = LEAF_STUFEN[i]
|
||||||
d1, g1, h1 = LEAF_STUFEN[i + 1]
|
z1, g1, h1 = LEAF_STUFEN[i + 1]
|
||||||
return (d0 + (d1 - d0) * f,
|
# Groesse und Kronenansatz werden gemischt, die Ziel-ANZAHL nicht: sie ist
|
||||||
|
# eine Stueckzahl, kein Verlauf. Es gilt die naeher liegende Stuetzstelle.
|
||||||
|
ziel = z0 if f < 0.5 else z1
|
||||||
|
return (ziel,
|
||||||
g0 + (g1 - g0) * f,
|
g0 + (g1 - g0) * f,
|
||||||
h0 + (h1 - h0) * f)
|
h0 + (h1 - h0) * f)
|
||||||
|
|
||||||
@@ -1492,6 +1505,88 @@ def _modifier_anstossen(md):
|
|||||||
md.show_viewport = sichtbar
|
md.show_viewport = sichtbar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _cards_pro_stueck(card_obj, card_coll):
|
||||||
|
"""Wie viele Faces hat EINE Card? Fuer die Umrechnung Faces -> Cardzahl."""
|
||||||
|
quellen = []
|
||||||
|
if card_coll is not None:
|
||||||
|
quellen = [o for o in card_coll.objects if o.type == 'MESH']
|
||||||
|
elif card_obj is not None and card_obj.type == 'MESH':
|
||||||
|
quellen = [card_obj]
|
||||||
|
zahlen = [len(o.data.polygons) for o in quellen if o.data.polygons]
|
||||||
|
if not zahlen:
|
||||||
|
return 1
|
||||||
|
return max(1, int(round(sum(zahlen) / float(len(zahlen)))))
|
||||||
|
|
||||||
|
|
||||||
|
def _card_zahl(ob, pro_stueck, dg=None):
|
||||||
|
"""Anzahl gestreuter Cards auf einer ausgewerteten Blatt-Ebene."""
|
||||||
|
dg = dg or bpy.context.evaluated_depsgraph_get()
|
||||||
|
ev = ob.evaluated_get(dg)
|
||||||
|
me = ev.to_mesh()
|
||||||
|
n = len(me.polygons)
|
||||||
|
ev.to_mesh_clear()
|
||||||
|
return int(round(n / float(max(pro_stueck, 1))))
|
||||||
|
|
||||||
|
|
||||||
|
def _dichte_einregeln(context, ob, md, ids, ziel, start_dichte, pro_stueck,
|
||||||
|
schritte=14, toleranz=0.15):
|
||||||
|
"""Regelt die Dichte per Bisektion auf eine Ziel-Cardzahl ein.
|
||||||
|
|
||||||
|
Warum ueberhaupt regeln: "Dichte" ist Punkte pro m2 Zweigflaeche, und die
|
||||||
|
faellt je Preset voellig anders aus. Ein Faktor, der am Standardbaum passte,
|
||||||
|
ueberschoss auf der Eiche um mehr als das Doppelte. Eine Stueckzahl ist
|
||||||
|
dagegen preset-unabhaengig - und direkt pruefbar.
|
||||||
|
|
||||||
|
Seed-stabil: der Seed wird nicht angefasst, nur die Dichte. Gleicher Baum
|
||||||
|
und gleicher Seed ergeben deshalb dieselbe Verteilung.
|
||||||
|
"""
|
||||||
|
if not ziel or ziel <= 0:
|
||||||
|
return start_dichte, _card_zahl(ob, pro_stueck)
|
||||||
|
|
||||||
|
def _messen(dichte):
|
||||||
|
md[ids["Density"]] = float(dichte)
|
||||||
|
_modifier_anstossen(md)
|
||||||
|
context.view_layer.update()
|
||||||
|
return _card_zahl(ob, pro_stueck)
|
||||||
|
|
||||||
|
lo, hi = start_dichte, start_dichte
|
||||||
|
n = _messen(start_dichte)
|
||||||
|
if n == ziel:
|
||||||
|
return start_dichte, n
|
||||||
|
|
||||||
|
# Klammer suchen: verdoppeln bzw. halbieren, bis das Ziel eingeschlossen ist.
|
||||||
|
if n < ziel:
|
||||||
|
for _ in range(12):
|
||||||
|
hi = hi * 2.0
|
||||||
|
if _messen(hi) >= ziel:
|
||||||
|
break
|
||||||
|
lo = start_dichte
|
||||||
|
else:
|
||||||
|
for _ in range(12):
|
||||||
|
lo = lo * 0.5
|
||||||
|
if lo < 1e-3 or _messen(lo) <= ziel:
|
||||||
|
break
|
||||||
|
hi = start_dichte
|
||||||
|
|
||||||
|
bestes = (abs(n - ziel), start_dichte, n)
|
||||||
|
for _ in range(schritte):
|
||||||
|
mitte = (lo + hi) * 0.5
|
||||||
|
n = _messen(mitte)
|
||||||
|
if abs(n - ziel) < bestes[0]:
|
||||||
|
bestes = (abs(n - ziel), mitte, n)
|
||||||
|
if abs(n - ziel) <= max(1, ziel * toleranz):
|
||||||
|
return mitte, n
|
||||||
|
if n < ziel:
|
||||||
|
lo = mitte
|
||||||
|
else:
|
||||||
|
hi = mitte
|
||||||
|
|
||||||
|
# Beste gefundene Naeherung wiederherstellen.
|
||||||
|
_messen(bestes[1])
|
||||||
|
return bestes[1], bestes[2]
|
||||||
|
|
||||||
|
|
||||||
def make_leaves(context, tree_obj, card_obj, name=None, card_coll=None, **overrides):
|
def make_leaves(context, tree_obj, card_obj, name=None, card_coll=None, **overrides):
|
||||||
"""Erzeugt/aktualisiert ein <Baum>_Leaf-Objekt mit dem Blattwerk-Modifier."""
|
"""Erzeugt/aktualisiert ein <Baum>_Leaf-Objekt mit dem Blattwerk-Modifier."""
|
||||||
name = name or (tree_obj.name + "_Leaf")
|
name = name or (tree_obj.name + "_Leaf")
|
||||||
@@ -2219,9 +2314,23 @@ def _origin_bottom_center(ob):
|
|||||||
ob.matrix_parent_inverse = Matrix.Identity(4)
|
ob.matrix_parent_inverse = Matrix.Identity(4)
|
||||||
if not me.vertices:
|
if not me.vertices:
|
||||||
return Matrix.Identity(4)
|
return Matrix.Identity(4)
|
||||||
xs = [v.co.x for v in me.vertices]
|
|
||||||
ys = [v.co.y for v in me.vertices]
|
# Der Ursprung kommt aus der STAMM-Geometrie (Slot 0), nicht aus der
|
||||||
zs = [v.co.z for v in me.vertices]
|
# Gesamt-Bbox. Sonst hebt eine einzige tief haengende Blatt-Card den ganzen
|
||||||
|
# Baum an und er steht in UE in der Luft - gemeldet am S1-Setzling, wo die
|
||||||
|
# Krone relativ zum kurzen Stamm weit ausladet.
|
||||||
|
stamm_verts = None
|
||||||
|
if len(me.materials) > 1:
|
||||||
|
idx = {vi for p in me.polygons if p.material_index == 0
|
||||||
|
for vi in p.vertices}
|
||||||
|
if idx:
|
||||||
|
stamm_verts = [me.vertices[i].co for i in idx]
|
||||||
|
if stamm_verts is None:
|
||||||
|
stamm_verts = [v.co for v in me.vertices]
|
||||||
|
|
||||||
|
xs = [c.x for c in stamm_verts]
|
||||||
|
ys = [c.y for c in stamm_verts]
|
||||||
|
zs = [c.z for c in stamm_verts]
|
||||||
versatz = Matrix.Translation((
|
versatz = Matrix.Translation((
|
||||||
-(min(xs) + max(xs)) * 0.5,
|
-(min(xs) + max(xs)) * 0.5,
|
||||||
-(min(ys) + max(ys)) * 0.5,
|
-(min(ys) + max(ys)) * 0.5,
|
||||||
@@ -2596,7 +2705,7 @@ class TREEGEN_OT_leaves(Operator):
|
|||||||
# traegt kleinere Bueschel. Baeume ohne Wachstums-Stufe haben
|
# traegt kleinere Bueschel. Baeume ohne Wachstums-Stufe haben
|
||||||
# growth_t = 1.0 und bleiben unveraendert.
|
# growth_t = 1.0 und bleiben unveraendert.
|
||||||
gt = float(t.get("growth_t", 1.0))
|
gt = float(t.get("growth_t", 1.0))
|
||||||
d_anteil, g_anteil, h_anteil = _stufen_anteile(gt)
|
ziel_cards, g_anteil, h_anteil = _stufen_anteile(gt)
|
||||||
|
|
||||||
# Der RADIUS-FILTER muss mit dem Baum schrumpfen. Er trennt
|
# Der RADIUS-FILTER muss mit dem Baum schrumpfen. Er trennt
|
||||||
# duenne Zweige (Laub) von dickem Geaest (kein Laub) - aber ein
|
# duenne Zweige (Laub) von dickem Geaest (kein Laub) - aber ein
|
||||||
@@ -2613,12 +2722,26 @@ class TREEGEN_OT_leaves(Operator):
|
|||||||
|
|
||||||
lf = make_leaves(context, t, s.leaf_card,
|
lf = make_leaves(context, t, s.leaf_card,
|
||||||
card_coll=s.leaf_cards,
|
card_coll=s.leaf_cards,
|
||||||
Density=s.leaf_density * d_anteil,
|
Density=s.leaf_density,
|
||||||
Size=s.leaf_size * g_anteil,
|
Size=s.leaf_size * g_anteil,
|
||||||
**{"Size Var": s.leaf_size_var,
|
**{"Size Var": s.leaf_size_var,
|
||||||
"Max Radius": s.leaf_max_radius * r_faktor,
|
"Max Radius": s.leaf_max_radius * r_faktor,
|
||||||
"Min Height": h_anteil,
|
"Min Height": h_anteil,
|
||||||
"Tilt": s.leaf_tilt, "Seed": s.seed})
|
"Tilt": s.leaf_tilt, "Seed": s.seed})
|
||||||
|
# Dichte auf die ZIEL-CARDZAHL einregeln. Muss nach dem Anlegen
|
||||||
|
# passieren, weil dafuer gemessen werden muss, was tatsaechlich
|
||||||
|
# herauskommt - die Zweigflaeche faellt je Preset voellig
|
||||||
|
# anders aus.
|
||||||
|
if ziel_cards:
|
||||||
|
md = lf.modifiers.get("GN_Leaves")
|
||||||
|
ng = md.node_group if md is not None else None
|
||||||
|
if ng is not None:
|
||||||
|
pro = _cards_pro_stueck(s.leaf_card, s.leaf_cards)
|
||||||
|
dichte, ist = _dichte_einregeln(
|
||||||
|
context, lf, md, leaf_socket_ids(ng),
|
||||||
|
ziel_cards, s.leaf_density, pro)
|
||||||
|
print("[TreeGen] %s: %d Cards (Ziel %d) bei Dichte %.0f"
|
||||||
|
% (t.name, ist, ziel_cards, dichte))
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
self.report({'WARNING'}, "%s: %s" % (t.name, exc))
|
self.report({'WARNING'}, "%s: %s" % (t.name, exc))
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ if not (130.0 <= s.leaf_density <= 200.0):
|
|||||||
% s.leaf_density)
|
% s.leaf_density)
|
||||||
# Die Deckung steht als Tabelle pro Stufe, nicht als Formel. Card-ANZAHL muss
|
# Die Deckung steht als Tabelle pro Stufe, nicht als Formel. Card-ANZAHL muss
|
||||||
# ueber die Stufen steigen, Card-Groesse auch.
|
# ueber die Stufen steigen, Card-Groesse auch.
|
||||||
_d0, _g0, _h0 = tg._stufen_anteile(0.0)
|
_z0, _g0, _h0 = tg._stufen_anteile(0.0)
|
||||||
_d1, _g1, _h1 = tg._stufen_anteile(1.0)
|
_z1, _g1, _h1 = tg._stufen_anteile(1.0)
|
||||||
if _g0 >= _g1:
|
if _g0 >= _g1:
|
||||||
fails.append("Groessen-Anteil steigt nicht ueber die Stufen (%.2f -> %.2f)"
|
fails.append("Groessen-Anteil steigt nicht ueber die Stufen (%.2f -> %.2f)"
|
||||||
% (_g0, _g1))
|
% (_g0, _g1))
|
||||||
@@ -275,6 +275,34 @@ if abs(kante_ohne - kanten[-1]) > 0.02:
|
|||||||
fails.append("Ein Baum ohne Wachstums-Stufen (%.2f) sieht anders aus als "
|
fails.append("Ein Baum ohne Wachstums-Stufen (%.2f) sieht anders aus als "
|
||||||
"die letzte Stufe (%.2f)" % (kante_ohne, kanten[-1]))
|
"die letzte Stufe (%.2f)" % (kante_ohne, kanten[-1]))
|
||||||
|
|
||||||
|
# --- 3c) Ziel-Cardzahl wird preset-UNABHAENGIG eingeregelt ---------------
|
||||||
|
# Frueher standen hier Dichte-Faktoren. Die mussten je Preset neu geeicht
|
||||||
|
# werden: "Dichte" ist Punkte pro m2 Zweigflaeche, und die verteilt sich je
|
||||||
|
# Baum voellig anders - ein Faktor, der am Standardbaum 11 Cards ergab,
|
||||||
|
# ueberschoss auf der Eiche um mehr als das Doppelte. Jetzt steht die
|
||||||
|
# Stueckzahl da und wird eingeregelt; der Test prueft sie DIREKT.
|
||||||
|
print("")
|
||||||
|
print("%-10s %8s %8s %8s %8s" % ("Preset", "S1", "S2", "S3", "S4"))
|
||||||
|
for pname in ("baum", "eiche", "birke"):
|
||||||
|
reihe = bauen(pname, wachstum=True, stufen=4)
|
||||||
|
pro = tg._cards_pro_stueck(card, None)
|
||||||
|
dg = bpy.context.evaluated_depsgraph_get()
|
||||||
|
zellen = []
|
||||||
|
for st in reihe:
|
||||||
|
bl = bpy.data.objects.get(st.name + "_Leaf")
|
||||||
|
n = tg._card_zahl(bl, pro, dg) if bl else 0
|
||||||
|
gt = float(st.get("growth_t", 1.0))
|
||||||
|
ziel, _, _ = tg._stufen_anteile(gt)
|
||||||
|
zellen.append((n, ziel))
|
||||||
|
if ziel:
|
||||||
|
# 25 % Toleranz: die Bisektion arbeitet auf einer diskreten
|
||||||
|
# Punktverteilung, exakt treffen kann sie nicht.
|
||||||
|
if abs(n - ziel) > max(2, ziel * 0.25):
|
||||||
|
fails.append("%s/%s: %d Cards, Ziel %d - die Regelung trifft "
|
||||||
|
"nicht" % (pname, st.name, n, ziel))
|
||||||
|
print("%-10s %8s %8s %8s %8s"
|
||||||
|
% (pname, *["%d/%s" % (n, z if z else "voll") for n, z in zellen]))
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
if fails:
|
if fails:
|
||||||
print("ERGEBNIS: %d FEHLER" % len(fails))
|
print("ERGEBNIS: %d FEHLER" % len(fails))
|
||||||
|
|||||||
Reference in New Issue
Block a user