diff --git a/imgui.ini b/imgui.ini index 9df7054b..09cf658f 100644 --- a/imgui.ini +++ b/imgui.ini @@ -31,19 +31,19 @@ DockId=0x0000000D,0 [Window][场景树] Pos=0,20 -Size=276,622 +Size=276,634 Collapsed=0 DockId=0x00000007,0 [Window][属性面板] Pos=1575,20 -Size=345,971 +Size=345,989 Collapsed=0 DockId=0x00000003,0 [Window][控制台] -Pos=0,644 -Size=276,347 +Pos=0,656 +Size=276,353 Collapsed=0 DockId=0x00000008,0 @@ -60,7 +60,7 @@ Collapsed=0 [Window][WindowOverViewport_11111111] Pos=0,20 -Size=1920,971 +Size=1920,989 Collapsed=0 [Window][测试窗口1] @@ -99,7 +99,7 @@ Size=600,500 Collapsed=0 [Window][资源管理器] -Pos=278,657 +Pos=278,675 Size=1295,334 Collapsed=0 DockId=0x00000006,0 @@ -201,7 +201,7 @@ Size=600,400 Collapsed=0 [Docking][Data] -DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1920,971 Split=X +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1920,989 Split=X DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=1573,989 Split=X DockNode ID=0x00000009 Parent=0x00000001 SizeRef=276,989 Split=Y Selected=0xE0015051 DockNode ID=0x00000007 Parent=0x00000009 SizeRef=271,634 Selected=0xE0015051 diff --git a/ssbo_component/ssbo_controller.py b/ssbo_component/ssbo_controller.py index ae3018af..fb9cf2c3 100644 --- a/ssbo_component/ssbo_controller.py +++ b/ssbo_component/ssbo_controller.py @@ -30,6 +30,8 @@ class ObjectController: self.display_names = {} self.global_transforms = [] self.position_offsets = {} + self.vertex_index = {} + self.original_positions = {} self.local_to_global_id = {} self.local_transform_state = {} self.local_transform_base_positions = {} @@ -741,9 +743,30 @@ class ObjectController: chunk["dynamic_enabled"] = False self.active_chunks.discard(chunk_id) + def _resolve_chunk_and_local_idx(self, global_id): + """ + Compatibility helper for merged branches: + - legacy: id_to_chunk[gid] -> (chunk_id, local_idx) + - current: id_to_chunk[gid] -> chunk_id (local_idx defaults to gid) + """ + mapping = self.id_to_chunk.get(global_id) + if mapping is None: + return None, None + if isinstance(mapping, (tuple, list)): + if not mapping: + return None, None + chunk_id = mapping[0] + local_idx = mapping[1] if len(mapping) > 1 else global_id + return chunk_id, local_idx + return mapping, global_id + def set_active_ids(self, active_ids): """切换编辑激活集合,仅保留 active_ids 对应 chunk 为动态模式。""" - target_chunks = {self.id_to_chunk[obj_id] for obj_id in active_ids if obj_id in self.id_to_chunk} + target_chunks = set() + for obj_id in active_ids: + chunk_id, _ = self._resolve_chunk_and_local_idx(obj_id) + if chunk_id is not None: + target_chunks.add(chunk_id) # Demote no-longer-active chunks. Dirty chunks are re-baked before demotion. for chunk_id in list(self.active_chunks): @@ -940,10 +963,9 @@ class ObjectController: return local_indices seen = set() for global_id in global_ids: - mapping = self.id_to_chunk.get(global_id) - if not mapping: + _, local_idx = self._resolve_chunk_and_local_idx(global_id) + if local_idx is None: continue - _, local_idx = mapping if local_idx in seen: continue if local_idx not in self.vertex_index: @@ -1102,10 +1124,28 @@ class ObjectController: if global_id not in self.id_to_chunk: return - - _, local_idx = self.id_to_chunk[global_id] - - if local_idx not in self.vertex_index: + + chunk_id, local_idx = self._resolve_chunk_and_local_idx(global_id) + if local_idx is None: + return + + # Hybrid chunk mode (current) may move NodePaths directly without + # vertex_index/original_positions populated. + if local_idx not in self.vertex_index or local_idx not in self.original_positions: + obj_np = self.id_to_object_np.get(global_id) + if not obj_np or obj_np.is_empty(): + return + next_pos = obj_np.get_pos() + delta + if hasattr(obj_np, "set_fluid_pos"): + obj_np.set_fluid_pos(next_pos) + else: + obj_np.set_pos(next_pos) + pick_np = self.id_to_pick_np.get(global_id) + if pick_np and not pick_np.is_empty(): + pick_np.set_mat(self.model, obj_np.get_mat(self.model)) + if chunk_id is not None and chunk_id in self.chunks: + self.chunks[chunk_id]["dirty"] = True + self.position_offsets[local_idx] = self.position_offsets.get(local_idx, Vec3(0)) + delta return # Accumulate offset @@ -1132,9 +1172,17 @@ class ObjectController: self._apply_vertices_to_pick(local_idx, i, new_pos) def get_world_pos(self, global_id): - if global_id not in self.id_to_object_np or not self.model: + if not self.model: + return Vec3(0, 0, 0) + + obj_np = self.id_to_object_np.get(global_id) + if obj_np and not obj_np.is_empty(): + p = obj_np.get_pos(self.model) + return self._local_point_to_world(Vec3(p)) + + _, local_idx = self._resolve_chunk_and_local_idx(global_id) + if local_idx is None: return Vec3(0, 0, 0) - _, local_idx = self.id_to_chunk[global_id] original_mat = self.global_transforms[global_id] original_pos = original_mat.get_row3(3) diff --git a/ssbo_component/ssbo_editor.py b/ssbo_component/ssbo_editor.py index eb221162..46136118 100644 --- a/ssbo_component/ssbo_editor.py +++ b/ssbo_component/ssbo_editor.py @@ -66,6 +66,9 @@ class SSBOEditor: self.ssbo = None self.font_path = font_path self._transform_gizmo = None + self._ssbo_transform_active = False + self._ssbo_selected_local_indices = [] + self._ssbo_gizmo_proxy = None # Internal State self.selected_name = None