Bake library AO and lift environment textures
Full build / Full desktop build + optional release (push) Successful in 3m43s
Full build / Import + headless tests (push) Successful in 29s

Phase 4 of the v0.6.0 graphics plan:

- tools/bake_ao.py bakes 256² AO maps for every Blender character/gear/prop
  (Cycles, existing UVs) next to each GLB; Materials.apply_ao() wires the red
  channel into character slots, gear, and props. Compatibility has no SSAO.
- Regenerated brick/concrete/asphalt at 1024² with OpenRouter, derived tangent
  normal maps via tools/make_normal_maps.py, and wired them through
  SurfaceMaterials.textured() without changing UV scales.
- Evaluated Forward+: boots on desktop Vulkan, but the renderer is project-wide
  and Web must stay GL Compatibility; v0.6.0 keeps Compatibility (decision in
  MEMORY/plan). A desktop-only override is deferred.
- Recaptured screenshots; compare 11 good / 0 bad. Fixed marquee text alignment.
- Tests: baked AO maps exist for all 46 assets; prop/character AO material
  checks; headless 222/222, Python 69/69, all smokes pass.
- Version 0.6.0; ADR-0013 accepted; README/architecture/blender-assets/plan and
  TODO/DONE updated.
This commit is contained in:
zwitschi committed 2026-11-01 15:07:27 +01:00
1 parent d8cfddbf89
commit d872034388
78 files changed
+390 -28

No files matched your search

+11 -2
View File
@@ -453,6 +453,8 @@ func _apply_outfit_materials(npc_type: int, outfit: Dictionary, cloth: Color,
"hair": outfit["hair"],
"accessory": Color(0.10, 0.11, 0.14),
}
var ao := Materials.load_ao(
BLENDER_NPC_DIR + character_model + "_ao.png")
for index in mesh.get_surface_count():
var source := mesh.surface_get_material(index)
if source == null:
@@ -462,8 +464,12 @@ func _apply_outfit_materials(npc_type: int, outfit: Dictionary, cloth: Color,
# (hivis, reflective, leather, steel, ...) keep their authored colour.
if not tints.has(slot):
continue
_skinned_mesh.set_surface_override_material(index,
Materials.npc_slot(source, tints[slot]))
var material := Materials.npc_slot(source, tints[slot])
if ao != null:
material.ao_enabled = true
material.ao_texture = ao
material.ao_texture_channel = BaseMaterial3D.TEXTURE_CHANNEL_RED
_skinned_mesh.set_surface_override_material(index, material)
func _bind_bones() -> void:
_bone_indices.clear()
@@ -726,6 +732,9 @@ func _attach_gear(gear_name: String) -> bool:
node.free()
return false
_detail_nodes.append(node)
var ao := Materials.load_ao(BLENDER_GEAR_DIR + gear_name + "_ao.png")
for child in node.find_children("*", "MeshInstance3D", true, false):
Materials.apply_ao(child as MeshInstance3D, ao)
return true
## Character-specific library gear (firefighter helmet/SCBA, dress bag, vest