refactor: tree.assemble() 接管树构建,_add_polyhaven_trees 移除
把 polyhaven 树的实例化逻辑从 generate_scene.py 移到 osmassets/tree.py::assemble(),与 water/grass/scrub 的要素 注册表模式对齐。 generate_scene.py 现在只有一个 _assemble_building 残留(因为需要 make_prism / add_roof / add_wall_panel 这些 mesh 构建函数)。 后续 P2c 会把 building 也搬出去。 parity: control-1 vs p2b-unify = PARITY OK (两区域) smoke: tree_style=polyhaven SCENE_DONE (181棵树, exit 0) tests: 42/42 OK Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -91,40 +91,6 @@ def _assemble_building(ring, way_id, tag, args, buildings_c, building_mats):
|
|||||||
building_mats, buildings_c)
|
building_mats, buildings_c)
|
||||||
return 1, int(industrial), ring
|
return 1, int(industrial), ring
|
||||||
|
|
||||||
|
|
||||||
def _add_polyhaven_trees(positions, collection):
|
|
||||||
"""Scatter island_tree_01 instances at `positions`.
|
|
||||||
|
|
||||||
positions is a list of (x, y, height) tuples as gathered by the two
|
|
||||||
tree-collecting loops (point nodes + tree_row samples).
|
|
||||||
"""
|
|
||||||
variants = _tree.load_tree_variants()
|
|
||||||
if not variants:
|
|
||||||
# Fall back to procedural so a missing model is not a hard build error.
|
|
||||||
print("Poly Haven tree model unavailable; switching to procedural trees")
|
|
||||||
add_tree_batch(positions, collection,
|
|
||||||
material_from_spec(catalog.MATERIALS["tree_trunk"]),
|
|
||||||
material_from_spec(catalog.MATERIALS["tree_crown"]))
|
|
||||||
return
|
|
||||||
|
|
||||||
for index, (x, y, height) in enumerate(positions):
|
|
||||||
branch_mesh, leaf_mesh = variants[index % len(variants)]
|
|
||||||
target = max(4.0, height)
|
|
||||||
factor = target / 3.2
|
|
||||||
|
|
||||||
b_obj = bpy.data.objects.new(f"Tree_PH_{index:03d}_Branch", branch_mesh)
|
|
||||||
b_obj.location = (x, y, 0.0)
|
|
||||||
b_obj.scale = (factor, factor, factor)
|
|
||||||
b_obj.rotation_euler = (0, 0, (index * 1.61803398875) % 1.0 * math.tau)
|
|
||||||
collection.objects.link(b_obj)
|
|
||||||
|
|
||||||
l_obj = bpy.data.objects.new(f"Tree_PH_{index:03d}_Leaf", leaf_mesh)
|
|
||||||
l_obj.location = (x, y, 0.0)
|
|
||||||
l_obj.scale = (factor, factor, factor)
|
|
||||||
l_obj.rotation_euler = (0, 0, (index * 1.61803398875) % 1.0 * math.tau)
|
|
||||||
collection.objects.link(l_obj)
|
|
||||||
|
|
||||||
|
|
||||||
MODEL_ROOT = os.path.abspath(os.path.join(
|
MODEL_ROOT = os.path.abspath(os.path.join(
|
||||||
os.path.dirname(__file__), "..", "assets", "models", "polyhaven"
|
os.path.dirname(__file__), "..", "assets", "models", "polyhaven"
|
||||||
))
|
))
|
||||||
@@ -749,7 +715,7 @@ def build(args):
|
|||||||
if trees:
|
if trees:
|
||||||
tree_style = args.get("tree_style")
|
tree_style = args.get("tree_style")
|
||||||
if tree_style == "polyhaven":
|
if tree_style == "polyhaven":
|
||||||
_add_polyhaven_trees(trees, props_c)
|
_tree.assemble(trees, props_c)
|
||||||
elif tree_style == "natural":
|
elif tree_style == "natural":
|
||||||
tree_trunk = material_from_spec(catalog.MATERIALS["tree_trunk"])
|
tree_trunk = material_from_spec(catalog.MATERIALS["tree_trunk"])
|
||||||
add_natural_tree_instances(
|
add_natural_tree_instances(
|
||||||
|
|||||||
@@ -95,8 +95,33 @@ def load_tree_variants():
|
|||||||
for obj in imported:
|
for obj in imported:
|
||||||
bpy.data.objects.remove(obj, do_unlink=True)
|
bpy.data.objects.remove(obj, do_unlink=True)
|
||||||
|
|
||||||
tris = sum(len(bm.loop_triangles) + len(lm.loop_triangles)
|
def assemble(positions, collection):
|
||||||
for bm, lm in variants)
|
"""Place island_tree_01 instances at `positions`.
|
||||||
print(f"Poly Haven tree variants loaded: {len(variants)} "
|
|
||||||
f"({tris} tris per instance)")
|
positions is a list of (x, y, height) tuples. Returns the number of
|
||||||
return variants
|
trees placed (0 when the model is unavailable).
|
||||||
|
"""
|
||||||
|
import math # noqa — tree.py has no top-level math import by design
|
||||||
|
|
||||||
|
variants = load_tree_variants()
|
||||||
|
if not variants:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
for index, (x, y, height) in enumerate(positions):
|
||||||
|
branch_mesh, leaf_mesh = variants[index % len(variants)]
|
||||||
|
target = max(4.0, height)
|
||||||
|
factor = target / 3.2
|
||||||
|
|
||||||
|
b_obj = bpy.data.objects.new(f"Tree_PH_{index:03d}_Branch", branch_mesh)
|
||||||
|
b_obj.location = (x, y, 0.0)
|
||||||
|
b_obj.scale = (factor, factor, factor)
|
||||||
|
b_obj.rotation_euler = (0, 0, (index * 1.61803398875) % 1.0 * math.tau)
|
||||||
|
collection.objects.link(b_obj)
|
||||||
|
|
||||||
|
l_obj = bpy.data.objects.new(f"Tree_PH_{index:03d}_Leaf", leaf_mesh)
|
||||||
|
l_obj.location = (x, y, 0.0)
|
||||||
|
l_obj.scale = (factor, factor, factor)
|
||||||
|
l_obj.rotation_euler = (0, 0, (index * 1.61803398875) % 1.0 * math.tau)
|
||||||
|
collection.objects.link(l_obj)
|
||||||
|
|
||||||
|
return len(positions)
|
||||||
|
|||||||
Reference in New Issue
Block a user