511 lines
18 KiB
Python
511 lines
18 KiB
Python
"""
|
||
软体物理和布料模拟插件主入口
|
||
提供完整的软体物理和布料模拟功能
|
||
"""
|
||
|
||
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']
|
||
) |