EG/plugins/user/haptic_feedback_system/physics/physics_integration.py
2025-12-12 16:16:15 +08:00

732 lines
26 KiB
Python

"""
物理引擎集成模块
负责将物理引擎中的碰撞和力反馈转换为触觉效果
"""
import time
from typing import Dict, Any, List, Optional
import math
class PhysicsIntegration:
"""
物理引擎集成
负责将物理引擎中的碰撞和力反馈转换为触觉效果
"""
def __init__(self, plugin):
"""
初始化物理引擎集成
Args:
plugin: 触觉反馈系统插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 物理事件监听器
self.physics_listeners = {}
# 碰撞效果配置
self.collision_config = {
'enable_collision_feedback': True,
'min_impulse_threshold': 0.1,
'max_impulse_threshold': 100.0,
'intensity_scale': 1.0,
'frequency_scale': 1.0,
'duration_scale': 1.0,
'effect_type': 'impulse'
}
# 力反馈配置
self.force_config = {
'enable_force_feedback': True,
'min_force_threshold': 0.01,
'max_force_threshold': 10.0,
'intensity_scale': 1.0,
'frequency_scale': 1.0,
'smoothing_factor': 0.1
}
# 摩擦效果配置
self.friction_config = {
'enable_friction_feedback': True,
'min_velocity_threshold': 0.1,
'texture_sensitivity': 1.0,
'vibration_frequency': 20.0
}
# 材质反馈配置
self.material_config = {
'enable_material_feedback': True,
'material_effects': {
'metal': {'intensity': 0.8, 'frequency': 60.0, 'type': 'buzz'},
'wood': {'intensity': 0.6, 'frequency': 30.0, 'type': 'rumble'},
'stone': {'intensity': 0.9, 'frequency': 80.0, 'type': 'click'},
'fabric': {'intensity': 0.3, 'frequency': 15.0, 'type': 'soft_rumble'},
'rubber': {'intensity': 0.5, 'frequency': 25.0, 'type': 'bounce'}
}
}
# 状态跟踪
self.contact_points = {}
self.force_feedback_state = {}
self.friction_state = {}
# 统计信息
self.stats = {
'collisions_detected': 0,
'forces_processed': 0,
'friction_effects': 0,
'material_effects': 0,
'haptic_effects_generated': 0
}
# 回调函数
self.physics_callbacks = {
'collision_detected': [],
'force_applied': [],
'friction_updated': [],
'haptic_effect_generated': []
}
print("✓ 物理引擎集成已创建")
def initialize(self) -> bool:
"""
初始化物理引擎集成
Returns:
是否初始化成功
"""
try:
self.initialized = True
print("✓ 物理引擎集成初始化完成")
return True
except Exception as e:
print(f"✗ 物理引擎集成初始化失败: {e}")
import traceback
traceback.print_exc()
return False
def enable(self) -> bool:
"""
启用物理引擎集成
Returns:
是否启用成功
"""
try:
if not self.initialized:
print("✗ 物理引擎集成未初始化")
return False
self.enabled = True
print("✓ 物理引擎集成已启用")
return True
except Exception as e:
print(f"✗ 物理引擎集成启用失败: {e}")
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用物理引擎集成"""
try:
self.enabled = False
print("✓ 物理引擎集成已禁用")
except Exception as e:
print(f"✗ 物理引擎集成禁用失败: {e}")
import traceback
traceback.print_exc()
def finalize(self):
"""清理物理引擎集成资源"""
try:
self.disable()
self.physics_listeners.clear()
self.contact_points.clear()
self.force_feedback_state.clear()
self.friction_state.clear()
self.physics_callbacks.clear()
self.initialized = False
print("✓ 物理引擎集成资源已清理")
except Exception as e:
print(f"✗ 物理引擎集成资源清理失败: {e}")
import traceback
traceback.print_exc()
def update(self, dt: float):
"""
更新物理引擎集成状态
Args:
dt: 时间增量
"""
try:
if not self.enabled:
return
# 更新摩擦状态
self._update_friction_state(dt)
# 更新力反馈状态
self._update_force_feedback_state(dt)
except Exception as e:
print(f"✗ 物理引擎集成更新失败: {e}")
import traceback
traceback.print_exc()
def _update_friction_state(self, dt: float):
"""更新摩擦状态"""
try:
# 减少摩擦状态值(衰减)
decay_rate = 0.95
keys_to_remove = []
for key, state in self.friction_state.items():
state['intensity'] *= decay_rate
if state['intensity'] < 0.01:
keys_to_remove.append(key)
# 移除已衰减完毕的状态
for key in keys_to_remove:
del self.friction_state[key]
except Exception as e:
print(f"✗ 摩擦状态更新失败: {e}")
def _update_force_feedback_state(self, dt: float):
"""更新力反馈状态"""
try:
# 减少力反馈状态值(平滑)
smoothing = self.force_config['smoothing_factor']
keys_to_remove = []
for key, state in self.force_feedback_state.items():
state['current_force'] = (
state['current_force'] * (1 - smoothing) +
state['target_force'] * smoothing
)
if abs(state['current_force']) < 0.001:
keys_to_remove.append(key)
# 移除已平滑完毕的状态
for key in keys_to_remove:
del self.force_feedback_state[key]
except Exception as e:
print(f"✗ 力反馈状态更新失败: {e}")
def process_collision(self, collision_data: Dict[str, Any]) -> bool:
"""
处理碰撞事件并生成触觉效果
Args:
collision_data: 碰撞数据
Returns:
是否处理成功
"""
try:
if not self.enabled or not self.collision_config['enable_collision_feedback']:
return False
# 提取碰撞信息
impulse = collision_data.get('impulse', 0.0)
contact_point = collision_data.get('contact_point', (0, 0, 0))
object_a = collision_data.get('object_a', 'unknown')
object_b = collision_data.get('object_b', 'unknown')
material_a = collision_data.get('material_a', 'default')
material_b = collision_data.get('material_b', 'default')
device_id = collision_data.get('device_id')
# 检查冲量阈值
if impulse < self.collision_config['min_impulse_threshold']:
return False
if impulse > self.collision_config['max_impulse_threshold']:
impulse = self.collision_config['max_impulse_threshold']
# 计算触觉效果强度
intensity = (
impulse / self.collision_config['max_impulse_threshold'] *
self.collision_config['intensity_scale']
)
intensity = max(0.0, min(1.0, intensity))
# 计算频率
frequency = 20.0 + (impulse * self.collision_config['frequency_scale'])
frequency = max(1.0, min(100.0, frequency))
# 计算持续时间
duration = 0.05 + (impulse * 0.01 * self.collision_config['duration_scale'])
duration = max(0.01, min(1.0, duration))
# 获取材质效果
material_effect = self._get_material_effect(material_a, material_b)
# 生成触觉效果
effect_type = self.collision_config['effect_type']
if material_effect:
effect_type = material_effect.get('type', effect_type)
intensity *= material_effect.get('intensity', 1.0)
frequency = material_effect.get('frequency', frequency)
# 播放触觉效果
if self.plugin.haptic_manager:
effect_id = self.plugin.haptic_manager.play_effect(
effect_type=effect_type,
device_id=device_id,
intensity=intensity,
duration=duration,
frequency=frequency,
parameters={
'collision_impulse': impulse,
'contact_point': contact_point,
'objects': [object_a, object_b],
'materials': [material_a, material_b]
}
)
if effect_id >= 0:
# 触发效果生成回调
self._trigger_physics_callback('haptic_effect_generated', {
'effect_id': effect_id,
'effect_type': effect_type,
'source': 'collision',
'intensity': intensity,
'frequency': frequency,
'duration': duration
})
self.stats['haptic_effects_generated'] += 1
self.stats['collisions_detected'] += 1
print(f"✓ 碰撞触觉效果已生成: {effect_type}")
return True
return False
except Exception as e:
print(f"✗ 碰撞处理失败: {e}")
return False
def process_force_feedback(self, force_data: Dict[str, Any]) -> bool:
"""
处理力反馈并生成连续触觉效果
Args:
force_data: 力反馈数据
Returns:
是否处理成功
"""
try:
if not self.enabled or not self.force_config['enable_force_feedback']:
return False
# 提取力反馈信息
force = force_data.get('force', 0.0)
force_direction = force_data.get('direction', (0, 0, 0))
object_id = force_data.get('object_id', 'unknown')
device_id = force_data.get('device_id')
# 检查力阈值
if abs(force) < self.force_config['min_force_threshold']:
return False
if abs(force) > self.force_config['max_force_threshold']:
force = math.copysign(self.force_config['max_force_threshold'], force)
# 计算触觉效果强度
intensity = (
abs(force) / self.force_config['max_force_threshold'] *
self.force_config['intensity_scale']
)
intensity = max(0.0, min(1.0, intensity))
# 计算频率
frequency = 10.0 + (abs(force) * self.force_config['frequency_scale'])
frequency = max(1.0, min(100.0, frequency))
# 更新力反馈状态
state_key = f"force_{object_id}"
if state_key not in self.force_feedback_state:
self.force_feedback_state[state_key] = {
'current_force': 0.0,
'target_force': force
}
else:
self.force_feedback_state[state_key]['target_force'] = force
# 生成连续触觉效果
if self.plugin.haptic_manager:
# 播放连续效果
effect_id = self.plugin.haptic_manager.play_effect(
effect_type='periodic',
device_id=device_id,
intensity=intensity,
duration=0.1, # 短持续时间,循环播放
frequency=frequency,
parameters={
'force': force,
'direction': force_direction,
'object_id': object_id
}
)
if effect_id >= 0:
# 触发效果生成回调
self._trigger_physics_callback('haptic_effect_generated', {
'effect_id': effect_id,
'effect_type': 'periodic',
'source': 'force',
'intensity': intensity,
'frequency': frequency
})
self.stats['haptic_effects_generated'] += 1
self.stats['forces_processed'] += 1
print(f"✓ 力反馈触觉效果已生成: 强度 {intensity:.2f}")
return True
return False
except Exception as e:
print(f"✗ 力反馈处理失败: {e}")
return False
def process_friction(self, friction_data: Dict[str, Any]) -> bool:
"""
处理摩擦并生成纹理触觉效果
Args:
friction_data: 摩擦数据
Returns:
是否处理成功
"""
try:
if not self.enabled or not self.friction_config['enable_friction_feedback']:
return False
# 提取摩擦信息
velocity = friction_data.get('velocity', 0.0)
surface_normal = friction_data.get('normal', (0, 0, 1))
object_id = friction_data.get('object_id', 'unknown')
material = friction_data.get('material', 'default')
device_id = friction_data.get('device_id')
# 检查速度阈值
if abs(velocity) < self.friction_config['min_velocity_threshold']:
return False
# 计算触觉效果强度
intensity = min(1.0, abs(velocity) * 0.1 * self.friction_config['texture_sensitivity'])
# 获取材质效果
material_effect = self._get_material_effect(material)
# 计算频率
frequency = self.friction_config['vibration_frequency']
if material_effect:
frequency = material_effect.get('frequency', frequency)
# 更新摩擦状态
state_key = f"friction_{object_id}"
if state_key not in self.friction_state:
self.friction_state[state_key] = {
'intensity': intensity,
'velocity': velocity
}
else:
self.friction_state[state_key]['intensity'] = max(
self.friction_state[state_key]['intensity'],
intensity
)
# 生成摩擦触觉效果
if self.plugin.haptic_manager:
effect_id = self.plugin.haptic_manager.play_effect(
effect_type='noise',
device_id=device_id,
intensity=intensity,
duration=0.05,
frequency=frequency,
parameters={
'velocity': velocity,
'material': material,
'object_id': object_id
}
)
if effect_id >= 0:
# 触发效果生成回调
self._trigger_physics_callback('haptic_effect_generated', {
'effect_id': effect_id,
'effect_type': 'noise',
'source': 'friction',
'intensity': intensity,
'frequency': frequency
})
self.stats['haptic_effects_generated'] += 1
self.stats['friction_effects'] += 1
print(f"✓ 摩擦触觉效果已生成: 强度 {intensity:.2f}")
return True
return False
except Exception as e:
print(f"✗ 摩擦处理失败: {e}")
return False
def _get_material_effect(self, *materials) -> Optional[Dict[str, Any]]:
"""
获取材质效果配置
Args:
*materials: 材质名称
Returns:
材质效果配置或None
"""
try:
if not self.material_config['enable_material_feedback']:
return None
material_effects = self.material_config['material_effects']
# 尝试匹配每个材质
for material in materials:
if material in material_effects:
return material_effects[material]
return None
except Exception as e:
print(f"✗ 材质效果获取失败: {e}")
return None
def register_physics_listener(self, event_type: str, callback: callable):
"""
注册物理事件监听器
Args:
event_type: 事件类型
callback: 回调函数
"""
try:
if event_type in self.physics_listeners:
self.physics_listeners[event_type].append(callback)
else:
self.physics_listeners[event_type] = [callback]
print(f"✓ 物理事件监听器已注册: {event_type}")
except Exception as e:
print(f"✗ 物理事件监听器注册失败: {e}")
def unregister_physics_listener(self, event_type: str, callback: callable):
"""
注销物理事件监听器
Args:
event_type: 事件类型
callback: 回调函数
"""
try:
if event_type in self.physics_listeners:
if callback in self.physics_listeners[event_type]:
self.physics_listeners[event_type].remove(callback)
print(f"✓ 物理事件监听器已注销: {event_type}")
except Exception as e:
print(f"✗ 物理事件监听器注销失败: {e}")
def _trigger_physics_callback(self, callback_type: str, data: Dict[str, Any]):
"""
触发物理回调
Args:
callback_type: 回调类型
data: 回调数据
"""
try:
if callback_type in self.physics_callbacks:
for callback in self.physics_callbacks[callback_type]:
try:
callback(data)
except Exception as e:
print(f"✗ 物理回调执行失败: {e}")
except Exception as e:
print(f"✗ 物理回调触发失败: {e}")
def register_physics_callback(self, callback_type: str, callback: callable):
"""
注册物理回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.physics_callbacks:
self.physics_callbacks[callback_type].append(callback)
print(f"✓ 物理回调已注册: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 物理回调注册失败: {e}")
def unregister_physics_callback(self, callback_type: str, callback: callable):
"""
注销物理回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.physics_callbacks:
if callback in self.physics_callbacks[callback_type]:
self.physics_callbacks[callback_type].remove(callback)
print(f"✓ 物理回调已注销: {callback_type}")
except Exception as e:
print(f"✗ 物理回调注销失败: {e}")
def set_collision_config(self, config: Dict[str, Any]) -> bool:
"""
设置碰撞配置
Args:
config: 配置字典
Returns:
是否设置成功
"""
try:
self.collision_config.update(config)
print(f"✓ 碰撞配置已更新: {self.collision_config}")
return True
except Exception as e:
print(f"✗ 碰撞配置设置失败: {e}")
return False
def set_force_config(self, config: Dict[str, Any]) -> bool:
"""
设置力反馈配置
Args:
config: 配置字典
Returns:
是否设置成功
"""
try:
self.force_config.update(config)
print(f"✓ 力反馈配置已更新: {self.force_config}")
return True
except Exception as e:
print(f"✗ 力反馈配置设置失败: {e}")
return False
def set_friction_config(self, config: Dict[str, Any]) -> bool:
"""
设置摩擦配置
Args:
config: 配置字典
Returns:
是否设置成功
"""
try:
self.friction_config.update(config)
print(f"✓ 摩擦配置已更新: {self.friction_config}")
return True
except Exception as e:
print(f"✗ 摩擦配置设置失败: {e}")
return False
def set_material_config(self, config: Dict[str, Any]) -> bool:
"""
设置材质配置
Args:
config: 配置字典
Returns:
是否设置成功
"""
try:
self.material_config.update(config)
print(f"✓ 材质配置已更新: {self.material_config}")
return True
except Exception as e:
print(f"✗ 材质配置设置失败: {e}")
return False
def get_collision_config(self) -> Dict[str, Any]:
"""
获取碰撞配置
Returns:
配置字典
"""
return self.collision_config.copy()
def get_force_config(self) -> Dict[str, Any]:
"""
获取力反馈配置
Returns:
配置字典
"""
return self.force_config.copy()
def get_friction_config(self) -> Dict[str, Any]:
"""
获取摩擦配置
Returns:
配置字典
"""
return self.friction_config.copy()
def get_material_config(self) -> Dict[str, Any]:
"""
获取材质配置
Returns:
配置字典
"""
return self.material_config.copy()
def get_stats(self) -> Dict[str, int]:
"""
获取统计信息
Returns:
统计信息字典
"""
return self.stats.copy()
def reset_stats(self):
"""重置统计信息"""
try:
self.stats = {
'collisions_detected': 0,
'forces_processed': 0,
'friction_effects': 0,
'material_effects': 0,
'haptic_effects_generated': 0
}
print("✓ 物理引擎集成统计信息已重置")
except Exception as e:
print(f"✗ 物理引擎集成统计信息重置失败: {e}")