docs: tree.py + ingest_tree.py 补充文档注释

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-30 09:20:40 +08:00
parent 3c6c21ff2f
commit 365b158878
2 changed files with 37 additions and 39 deletions

View File

@@ -1,10 +1,14 @@
"""Import Poly Haven island_tree_01 as instanced-tree asset.
This is the analog of load_tuft_variants() for trees. It appends only the
LOD1 meshes from the vendored .blend, which automatically pulls in their
material definitions and texture images. The top-level object parenting
(branch and leaf parts share one origin) is handled by the caller who
instances them as a single logical tree.
The runtime counterpart to blender/tools/ingest_tree.py. Instead of exporting
pre-baked GLBs (which would duplicate textures), this module appends the
vendored .blend at scene-build time. The appended objects pull in their
material datablocks and texture images automatically — the textures live next
to the .blend and are resolved via relative paths.
load_tree_variants() is the analog of load_tuft_variants() for trees: import
once, copy the meshes, remove the imported objects, return mesh datablocks
ready for instancing.
"""
import os
@@ -19,36 +23,33 @@ TREE_BLEND = os.path.join(
)
# Branch / leaf LOD1 pairings for the four variants.
# Each pairing is a single logical tree that the caller instances as one.
# Each pairing is one logical tree that the caller instances as a unit.
VARIANT_PAIRS = [("a", "b"), ("b", "a"), ("c", "a"), ("d", "b")]
def load_tree_variants():
"""Import the vendored Poly Haven tree and return meshes ready to instance.
Returns a list of (branch_mesh, leaf_mesh) tuples, one per variant. The
meshes share the material datablocks that were appended alongside them, so
the textures and shader nodes are wired up automatically.
Returns a list of (branch_mesh, leaf_mesh) tuples, one per variant.
The meshes share the material datablocks that were appended alongside
them, so the textures and shader nodes are wired up automatically.
Returns [] when the source .blend is absent so a clean checkout still
builds. The caller falls back to procedural trees.
Returns [] when the source .blend is absent — the caller falls back to
procedural trees so a clean checkout still builds.
"""
if not os.path.exists(TREE_BLEND):
return []
before_objects = set(bpy.data.objects)
before_meshes = set(bpy.data.meshes)
# Gather the object names we need from the library.
# Append one object at a time: bpy.ops.wm.append with a multi-file list
# can crash when objects in the same library share data that was already
# linked by an earlier append in the same batch.
wanted = []
for branch_id, leaf_id in VARIANT_PAIRS:
wanted.append(f"island_tree_01_branches_{branch_id}_LOD1")
wanted.append(f"island_tree_01_leaves_{leaf_id}_LOD1")
# bpy.ops.wm.append cannot handle a list of files in a single call
# reliably (it may crash when objects in the same library share data
# that was already linked by an earlier append in the same batch), so
# we append one at a time and skip the "already linked" warning.
for name in wanted:
try:
bpy.ops.wm.append(
@@ -59,22 +60,12 @@ def load_tree_variants():
)
except RuntimeError:
# Object already linked by an earlier append of a sibling mesh
# that shared materials; this is expected and harmless.
# that shared materials; harmless.
pass
imported = [obj for obj in set(bpy.data.objects) - before_objects
if obj.type == "MESH"]
# Pair branch + leaf into variants. We append in the order above so
# a simple zip works.
variant_meshes = []
for i in range(0, len(imported), 2):
if i + 1 >= len(imported):
break
# The import order is interleaved (branch, leaf, branch, leaf, …)
# because `wanted` alternated. Sort by name to be safe.
pass
# Rebuild the pairs from the imported object names.
variants = []
for branch_id, leaf_id in VARIANT_PAIRS:
@@ -105,10 +96,12 @@ def load_tree_variants():
def assemble(positions, collection):
"""Place island_tree_01 instances at `positions`.
positions is a list of (x, y, height) tuples. Returns the number of
trees placed (0 when the model is unavailable).
positions is a list of (x, y, height) tuples as gathered by the two
tree-collecting loops (point nodes + tree_row samples).
Returns the number of trees placed (0 when the model is unavailable).
"""
import math # noqa — tree.py has no top-level math import by design
import math # noqa — tree.py has no top-level math import otherwise
variants = load_tree_variants()
if not variants: