| … | … | @@ -11,7 +11,7 @@ Usage: |
| 11 | 11 | |
| 12 | 12 | import bpy |
| 13 | 13 | |
| 14 | | ADDON_VERSION = "0.13.2" |
| 14 | ADDON_VERSION = "0.13.3" |
| 15 | 15 | |
| 16 | 16 | # Support hot-reload (F3 > Reload Scripts) |
| 17 | 17 | if "shm_protocol" in locals(): |
| … | … | @@ -57,6 +57,42 @@ def _make_poll_timer(generation: int): |
| 57 | 57 | return _poll_timer |
| 58 | 58 | |
| 59 | 59 | |
| 60 | def _request_texture_registrations(): |
| 61 | """Scan Blender scene for materials with image textures and request VT registration.""" |
| 62 | global _conn, _baker |
| 63 | |
| 64 | if _conn is None or _baker is None: |
| 65 | return |
| 66 | |
| 67 | import bpy |
| 68 | |
| 69 | requested = set() |
| 70 | for obj in bpy.data.objects: |
| 71 | if obj.type != "MESH" or obj.active_material is None: |
| 72 | continue |
| 73 | mat = obj.active_material |
| 74 | if not mat.use_nodes or not mat.node_tree: |
| 75 | continue |
| 76 | for node in mat.node_tree.nodes: |
| 77 | if node.type == "BSDF_PRINCIPLED": |
| 78 | # Check if Base Color has an image texture connected |
| 79 | base_color_input = node.inputs.get("Base Color") |
| 80 | if base_color_input is None or not base_color_input.is_linked: |
| 81 | continue |
| 82 | for link in base_color_input.links: |
| 83 | from_node = link.from_node |
| 84 | if from_node.type == "TEX_IMAGE" and from_node.image is not None: |
| 85 | img_name = from_node.image.name |
| 86 | if img_name not in requested and img_name not in _baker._texture_ids: |
| 87 | requested.add(img_name) |
| 88 | msg = f"request_texture:{img_name}" |
| 89 | _conn.send_message(msg.encode()) |
| 90 | print(f"BlenderBridge: Requesting texture registration for '{img_name}'") |
| 91 | |
| 92 | if requested: |
| 93 | print(f"BlenderBridge: Requested {len(requested)} texture(s)") |
| 94 | |
| 95 | |
| 60 | 96 | def _poll_timer_impl(generation: int): |
| 61 | 97 | """Called by Blender's timer to poll for updates from Godot.""" |
| 62 | 98 | global _conn, _shm, _importer, _detector, _baker, _timer_running |
| … | … | @@ -103,6 +139,8 @@ def _poll_timer_impl(generation: int): |
| 103 | 139 | _detector.suppress(set(_importer._id_to_name.values()), 5) |
| 104 | 140 | got_incoming = True |
| 105 | 141 | print(f"BlenderBridge: Synced scene from Godot") |
| 142 | # Scan Blender scene for image textures and request VT registration |
| 143 | _request_texture_registrations() |
| 106 | 144 | elif text in ("updated", "transform_update"): |
| 107 | 145 | # Incremental update from Godot (region 0) |
| 108 | 146 | if _importer is not None: |
| … | … | @@ -116,8 +154,13 @@ def _poll_timer_impl(generation: int): |
| 116 | 154 | # Godot registered a texture: texture_registered:name,id |
| 117 | 155 | parts = text.split(":", 1)[1].split(",") |
| 118 | 156 | if len(parts) == 2 and _baker is not None: |
| 119 | | _baker.register_texture(parts[0], int(parts[1])) |
| 120 | | print(f"BlenderBridge: Registered texture '{parts[0]}' id={parts[1]}") |
| 157 | img_name = parts[0] |
| 158 | tex_id = int(parts[1]) |
| 159 | _baker.register_texture(img_name, tex_id) |
| 160 | print(f"BlenderBridge: Registered texture '{img_name}' id={tex_id}") |
| 161 | # Bake immediately so tiles flow on this tick |
| 162 | _baker.bake_full_image(img_name) |
| 163 | print(f"BlenderBridge: Baked texture '{img_name}'") |
| 121 | 164 | |
| 122 | 165 | # Flush accumulated Blender changes to SHM and notify Godot |
| 123 | 166 | if _detector is not None: |