""" 软体物理和布料模拟插件主入口 提供完整的软体物理和布料模拟功能 """ from panda3d.core import Vec3 from plugins.plugin_interface_spec import BasePlugin from .core.cloth_manager import ClothManager from .core.soft_body_manager import SoftBodyManager from .core.cloth_physics import ClothPhysics from .core.soft_body_physics import SoftBodyPhysics from .materials.cloth_materials import ClothMaterialManager from .utils.mesh_generator import MeshGenerator from .debug.cloth_debug import PhysicsDebugManager import json import os class Plugin(BasePlugin): """ 软体物理和布料模拟插件 提供布料模拟和软体物理功能,支持多种材质、形状和物理效应 """ def __init__(self, plugin_manager, name: str = "soft_body_cloth_physics"): super().__init__(plugin_manager, name) # 核心管理器 self.cloth_manager = None self.soft_body_manager = None self.cloth_physics = None self.soft_body_physics = None self.material_manager = None self.mesh_generator = None self.debug_manager = None # 配置 self.config = { 'gravity': Vec3(0, 0, -9.81), 'time_step': 1.0/60.0, 'sub_steps': 4, 'default_cloth_density': 0.5, 'default_soft_body_density': 1.0, 'enable_debug_visualization': False, 'debug_flags': { 'show_mesh': True, 'show_anchors': True, 'show_forces': False, 'show_velocities': False, 'show_normals': False, 'show_tears': True, 'show_collisions': False, 'show_bounding_box': False }, 'performance': { 'max_cloth_objects': 50, 'max_soft_body_objects': 50, 'update_frequency': 60, 'sub_steps': 4 }, 'physics': { 'air_density': 1.225, 'water_density': 1000.0, 'water_offset': 0.0, 'water_normal': Vec3(0, 0, 1) }, 'wind': { 'enabled': False, 'velocity': Vec3(0, 0, 0), 'turbulence': 0.0, 'frequency': 1.0 } } # 状态 self.initialized = False self.performance_stats = { 'total_cloth_objects': 0, 'total_soft_body_objects': 0, 'simulation_time': 0.0, 'update_count': 0 } def initialize(self) -> bool: """ 初始化插件 Returns: 是否初始化成功 """ try: print(f"正在初始化 {self.name} 插件...") # 获取世界对象 world = self.plugin_manager.world # 初始化所有管理器 self.cloth_manager = ClothManager(world) self.soft_body_manager = SoftBodyManager(world) self.cloth_physics = ClothPhysics(world) self.soft_body_physics = SoftBodyPhysics(world) self.material_manager = ClothMaterialManager() self.mesh_generator = MeshGenerator() self.debug_manager = PhysicsDebugManager(world.render) # 加载配置 self._load_config() # 应用配置 self._apply_config() # 启用调试可视化(如果配置中启用) if self.config['enable_debug_visualization']: self.debug_manager.enable() # 设置调试标志 for flag, value in self.config['debug_flags'].items(): if flag == 'show_mesh': self.debug_manager.set_cloth_visibility(mesh=value) self.debug_manager.set_soft_body_visibility(mesh=value) elif flag == 'show_anchors': self.debug_manager.set_cloth_visibility(anchors=value) elif flag == 'show_forces': self.debug_manager.set_cloth_visibility(forces=value) self.debug_manager.set_soft_body_visibility(forces=value) elif flag == 'show_velocities': self.debug_manager.set_cloth_visibility(velocities=value) self.debug_manager.set_soft_body_visibility(velocities=value) elif flag == 'show_normals': self.debug_manager.set_cloth_visibility(normals=value) elif flag == 'show_tears': self.debug_manager.set_cloth_visibility(tears=value) elif flag == 'show_collisions': self.debug_manager.set_cloth_visibility(collisions=value) self.debug_manager.set_soft_body_visibility(collisions=value) elif flag == 'show_bounding_box': self.debug_manager.set_cloth_visibility(bounding_box=value) # 设置性能参数 self.cloth_manager.max_cloth_objects = self.config['performance']['max_cloth_objects'] self.cloth_manager.cloth_update_frequency = self.config['performance']['update_frequency'] self.soft_body_manager.max_soft_body_objects = self.config['performance']['max_soft_body_objects'] self.soft_body_manager.soft_body_update_frequency = self.config['performance']['update_frequency'] # 设置风力参数 self._apply_wind_config() self.initialized = True print(f"✓ {self.name} 插件初始化成功") return True except Exception as e: print(f"✗ {self.name} 插件初始化失败: {e}") import traceback traceback.print_exc() return False def enable(self) -> bool: """ 启用插件 Returns: 是否启用成功 """ try: if not self.initialized: print("⚠ 插件未初始化,无法启用") return False # 启用所有管理器 if self.cloth_manager: self.cloth_manager.enable() if self.soft_body_manager: self.soft_body_manager.enable() if self.cloth_physics: # 无需特殊启用 pass if self.soft_body_physics: # 无需特殊启用 pass if self.debug_manager: self.debug_manager.enable() self.enabled = True print(f"✓ {self.name} 插件已启用") return True except Exception as e: print(f"✗ {self.name} 插件启用失败: {e}") import traceback traceback.print_exc() return False def disable(self) -> bool: """ 禁用插件 Returns: 是否禁用成功 """ try: # 禁用所有管理器 if self.cloth_manager: self.cloth_manager.disable() if self.soft_body_manager: self.soft_body_manager.disable() if self.debug_manager: self.debug_manager.disable() self.enabled = False print(f"✓ {self.name} 插件已禁用") return True except Exception as e: print(f"✗ {self.name} 插件禁用失败: {e}") import traceback traceback.print_exc() return False def finalize(self): """ 清理插件资源 """ try: # 清理所有管理器 if self.cloth_manager: self.cloth_manager.cleanup() self.cloth_manager = None if self.soft_body_manager: self.soft_body_manager.cleanup() self.soft_body_manager = None if self.cloth_physics: self.cloth_physics = None if self.soft_body_physics: self.soft_body_physics = None if self.material_manager: self.material_manager = None if self.mesh_generator: self.mesh_generator = None if self.debug_manager: self.debug_manager.cleanup() self.debug_manager = None print(f"✓ {self.name} 插件资源已清理") except Exception as e: print(f"✗ {self.name} 插件清理失败: {e}") import traceback traceback.print_exc() def get_info(self): """ 获取插件信息 Returns: 插件信息字典 """ info = super().get_info() info.update({ "name": "SoftBodyClothPhysics", "version": "1.0.0", "author": "iFlow Team", "description": "提供软体物理和布料模拟功能的插件", "features": [ "布料物理模拟", "软体物理模拟", "多种布料材质类型", "参数实时调节", "调试可视化", "风力模拟", "撕裂和碰撞检测", "高级网格生成" ], "dependencies": [ "panda3d", "panda3d.bullet" ], "capabilities": { "cloth_types": self.material_manager.get_all_material_types() if self.material_manager else [], "mesh_generation": [ "cloth_patch", "sphere", "box", "capsule", "cylinder", "rope", "torus", "custom" ], "debug_visualization": [ "mesh", "anchors", "forces", "velocities", "normals", "tears", "collisions", "bounding_box" ] } }) return info def update(self, dt: float): """ 更新插件(每帧调用) Args: dt: 时间增量 """ if not self.enabled or not self.initialized: return # 更新所有管理器 if self.cloth_manager: self.cloth_manager.update_all_cloths(dt) if self.soft_body_manager: self.soft_body_manager.update_all_soft_bodies(dt) if self.cloth_physics: self.cloth_physics.update_wind(dt) if self.debug_manager: # 更新可视化 if self.cloth_manager: self.debug_manager.update_all_visualizations( self.cloth_manager.cloth_objects, self.soft_body_manager.soft_body_objects if self.soft_body_manager else [] ) # 更新性能统计 self.performance_stats['update_count'] += 1 if self.cloth_manager: self.performance_stats['total_cloth_objects'] = len(self.cloth_manager.cloth_objects) if self.soft_body_manager: self.performance_stats['total_soft_body_objects'] = len(self.soft_body_manager.soft_body_objects) def get_performance_stats(self) -> dict: """ 获取性能统计信息 Returns: 性能统计信息字典 """ stats = self.performance_stats.copy() # 添加管理器统计 if self.cloth_manager: cloth_stats = self.cloth_manager.get_cloth_stats() stats.update(cloth_stats) if self.soft_body_manager: soft_stats = self.soft_body_manager.get_soft_body_stats() stats.update(soft_stats) if self.debug_manager: debug_stats = self.debug_manager.get_debug_stats() stats['debug_stats'] = debug_stats return stats def create_cloth(self, parent_node, cloth_type: str, width: float, height: float, resolution_x: int, resolution_y: int, params: dict = None, behavior_mode: str = None) -> dict: """ 创建布料对象 Args: parent_node: 父节点 cloth_type: 布料类型 width: 宽度 height: 高度 resolution_x: X分辨率 resolution_y: Y分辨率 params: 参数 behavior_mode: 行为模式 Returns: 布料对象信息 """ if not self.initialized or not self.cloth_manager: return None return self.cloth_manager.create_cloth_patch( parent_node, width, height, resolution_x, resolution_y, params ) def create_soft_body(self, parent_node, soft_type: str, shape_type: str = "sphere", **kwargs) -> dict: """ 创建软体对象 Args: parent_node: 父节点 soft_type: 软体类型 shape_type: 形状类型 **kwargs: 形状参数 Returns: 软体对象信息 """ if not self.initialized or not self.soft_body_manager: return None return self.soft_body_manager.create_soft_body_from_mesh( parent_node, soft_type, shape_type, **kwargs ) def set_config(self, key: str, value): """ 设置配置参数 Args: key: 配置键 value: 配置值 """ if key in self.config: self.config[key] = value if key == 'gravity': self._apply_config() elif key == 'enable_debug_visualization': if value and self.debug_manager: self.debug_manager.enable() elif not value and self.debug_manager: self.debug_manager.disable() def get_config(self, key: str = None): """ 获取配置参数 Args: key: 配置键(如果为None则返回整个配置) Returns: 配置值或整个配置字典 """ if key: return self.config.get(key) return self.config.copy() def _load_config(self): """ 从配置文件加载配置 """ try: config_path = os.path.join( os.path.dirname(__file__), "config", "cloth_settings.json" ) if os.path.exists(config_path): with open(config_path, 'r', encoding='utf-8') as f: file_config = json.load(f) # 合并配置 self._merge_config(self.config, file_config.get('plugin', {})) except Exception as e: print(f"⚠ 加载配置文件失败: {e}") def _merge_config(self, target: dict, source: dict): """ 合并配置字典 Args: target: 目标字典 source: 源字典 """ for key, value in source.items(): if isinstance(value, dict) and key in target and isinstance(target[key], dict): self._merge_config(target[key], value) else: target[key] = value def _apply_config(self): """ 应用配置设置 """ if self.cloth_manager: self.cloth_manager.set_gravity(self.config['gravity']) if self.soft_body_manager: self.soft_body_manager.set_gravity(self.config['gravity']) if self.cloth_physics: self.cloth_physics.update_soft_body_world_info( air_density=self.config['physics']['air_density'], water_density=self.config['physics']['water_density'], water_offset=self.config['physics']['water_offset'], water_normal=self.config['physics']['water_normal'], gravity=self.config['gravity'] ) if self.soft_body_physics: self.soft_body_physics.update_soft_body_world_info( air_density=self.config['physics']['air_density'], water_density=self.config['physics']['water_density'], water_offset=self.config['physics']['water_offset'], water_normal=self.config['physics']['water_normal'], gravity=self.config['gravity'] ) def _apply_wind_config(self): """ 应用风力配置 """ if self.cloth_physics and self.config['wind']['enabled']: self.cloth_physics.set_wind_parameters( enabled=self.config['wind']['enabled'], velocity=self.config['wind']['velocity'], turbulence=self.config['wind']['turbulence'], frequency=self.config['wind']['frequency'] )