690 lines
23 KiB
Python
690 lines
23 KiB
Python
"""
|
||
生态系统可视化器
|
||
负责提供植被和生态系统的可视化表示
|
||
"""
|
||
|
||
import time
|
||
from typing import Dict, Any, List, Optional
|
||
import math
|
||
import random
|
||
|
||
class EcoVisualizer:
|
||
"""
|
||
生态系统可视化器
|
||
负责提供植被和生态系统的可视化表示,包括渲染、着色和特效
|
||
"""
|
||
|
||
def __init__(self, plugin):
|
||
"""
|
||
初始化生态系统可视化器
|
||
|
||
Args:
|
||
plugin: 植被和生态系统插件实例
|
||
"""
|
||
self.plugin = plugin
|
||
self.enabled = False
|
||
self.initialized = False
|
||
|
||
# 渲染配置
|
||
self.render_config = {
|
||
'render_distance': 100.0, # 渲染距离
|
||
'lod_levels': 5, # LOD级别数
|
||
'max_instances': 5000, # 最大实例数
|
||
'billboard_threshold': 50.0, # 公告牌阈值
|
||
'fade_distance': 80.0, # 淡出距离
|
||
'render_vegetation': True, # 渲染植被
|
||
'render_animals': True, # 渲染动物
|
||
'render_effects': True # 渲染特效
|
||
}
|
||
|
||
# 着色配置
|
||
self.shading_config = {
|
||
'use_dynamic_lighting': True, # 使用动态光照
|
||
'shadow_quality': 'medium', # 阴影质量
|
||
'wind_effect': 0.5, # 风效强度
|
||
'seasonal_tint': True, # 季节色调
|
||
'health_based_color': True, # 基于健康的颜色
|
||
'specular_intensity': 0.3 # 镜面反射强度
|
||
}
|
||
|
||
# 特效配置
|
||
self.effect_config = {
|
||
'particle_effects': True, # 粒子特效
|
||
'bloom_effect': True, # 泛光效果
|
||
'depth_of_field': False, # 景深效果
|
||
'motion_blur': False, # 运动模糊
|
||
'color_grading': 'natural', # 色彩分级
|
||
'fog_effect': True # 雾效
|
||
}
|
||
|
||
# LOD系统
|
||
self.lod_system = {
|
||
'levels': [
|
||
{'distance': 0, 'detail': 'high', 'polygon_count': 1000},
|
||
{'distance': 20, 'detail': 'medium', 'polygon_count': 500},
|
||
{'distance': 40, 'detail': 'low', 'polygon_count': 200},
|
||
{'distance': 60, 'detail': 'very_low', 'polygon_count': 50},
|
||
{'distance': 80, 'detail': 'billboard', 'polygon_count': 1}
|
||
],
|
||
'transition_smoothness': 0.5 # LOD过渡平滑度
|
||
}
|
||
|
||
# 颜色方案
|
||
self.color_schemes = {
|
||
'vegetation': {
|
||
'healthy': (0.2, 0.8, 0.2), # 健康绿色
|
||
'stressed': (0.8, 0.8, 0.2), # 压力黄色
|
||
'dying': (0.8, 0.2, 0.2), # 濒死红色
|
||
'dormant': (0.5, 0.5, 0.5) # 休眠灰色
|
||
},
|
||
'seasons': {
|
||
'spring': (1.0, 1.0, 0.8), # 春季色调
|
||
'summer': (1.0, 0.9, 0.7), # 夏季色调
|
||
'autumn': (1.0, 0.7, 0.5), # 秋季色调
|
||
'winter': (0.8, 0.8, 1.0) # 冬季色调
|
||
}
|
||
}
|
||
|
||
# 相机配置
|
||
self.camera_config = {
|
||
'position': (0, 0, 0),
|
||
'rotation': (0, 0, 0),
|
||
'fov': 60.0,
|
||
'near_clip': 0.1,
|
||
'far_clip': 1000.0
|
||
}
|
||
|
||
# 可视化统计
|
||
self.visualization_stats = {
|
||
'rendered_instances': 0,
|
||
'draw_calls': 0,
|
||
'render_time': 0.0,
|
||
'lod_transitions': 0,
|
||
'effects_applied': 0
|
||
}
|
||
|
||
# 缓存系统
|
||
self.render_cache = {}
|
||
self.cache_config = {
|
||
'max_cache_size': 100,
|
||
'cache_timeout': 300 # 5分钟
|
||
}
|
||
|
||
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.render_cache.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_camera(dt)
|
||
|
||
# 更新LOD系统
|
||
self._update_lod_system(dt)
|
||
|
||
# 更新特效
|
||
self._update_effects(dt)
|
||
|
||
# 清理缓存
|
||
self._cleanup_cache()
|
||
|
||
except Exception as e:
|
||
print(f"✗ 生态系统可视化器更新失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def _update_camera(self, dt: float):
|
||
"""更新相机状态"""
|
||
try:
|
||
# 在实际实现中,这里会根据用户输入或脚本更新相机位置
|
||
pass
|
||
except Exception as e:
|
||
print(f"✗ 相机更新失败: {e}")
|
||
|
||
def _update_lod_system(self, dt: float):
|
||
"""更新LOD系统"""
|
||
try:
|
||
# 在实际实现中,这里会根据相机距离更新LOD级别
|
||
pass
|
||
except Exception as e:
|
||
print(f"✗ LOD系统更新失败: {e}")
|
||
|
||
def _update_effects(self, dt: float):
|
||
"""更新特效系统"""
|
||
try:
|
||
# 在实际实现中,这里会更新各种视觉特效
|
||
pass
|
||
except Exception as e:
|
||
print(f"✗ 特效系统更新失败: {e}")
|
||
|
||
def _cleanup_cache(self):
|
||
"""清理渲染缓存"""
|
||
try:
|
||
current_time = time.time()
|
||
expired_keys = []
|
||
|
||
for key, (timestamp, _) in self.render_cache.items():
|
||
if current_time - timestamp > self.cache_config['cache_timeout']:
|
||
expired_keys.append(key)
|
||
|
||
for key in expired_keys:
|
||
del self.render_cache[key]
|
||
|
||
except Exception as e:
|
||
print(f"✗ 缓存清理失败: {e}")
|
||
|
||
def render_vegetation(self):
|
||
"""渲染植被"""
|
||
try:
|
||
if not self.enabled or not self.render_config['render_vegetation']:
|
||
return
|
||
|
||
if not self.plugin.vegetation_manager:
|
||
return
|
||
|
||
# 获取所有植被实例
|
||
instances = self.plugin.vegetation_manager.get_all_vegetation_instances()
|
||
|
||
rendered_count = 0
|
||
for instance_id, instance in instances.items():
|
||
if not instance['alive']:
|
||
continue
|
||
|
||
if rendered_count >= self.render_config['max_instances']:
|
||
break
|
||
|
||
# 计算LOD级别
|
||
lod_level = self._calculate_lod_level(instance['position'])
|
||
|
||
# 获取植被类型信息
|
||
veg_type = instance['type']
|
||
veg_info = self.plugin.vegetation_manager.get_vegetation_info(veg_type)
|
||
|
||
if not veg_info:
|
||
continue
|
||
|
||
# 计算颜色
|
||
color = self._calculate_vegetation_color(instance, veg_info)
|
||
|
||
# 应用季节色调
|
||
if self.shading_config['seasonal_tint'] and self.plugin.seasonal_effects:
|
||
seasonal_color = self.plugin.seasonal_effects.get_vegetation_change_factor('leaf_color')
|
||
if isinstance(seasonal_color, tuple) and len(seasonal_color) == 3:
|
||
color = tuple(color[i] * seasonal_color[i] for i in range(3))
|
||
|
||
# 应用风效
|
||
wind_effect = self.shading_config['wind_effect']
|
||
|
||
# 在实际实现中,这里会调用渲染API进行渲染
|
||
rendered_count += 1
|
||
|
||
self.visualization_stats['rendered_instances'] = rendered_count
|
||
self.visualization_stats['draw_calls'] += rendered_count
|
||
|
||
except Exception as e:
|
||
print(f"✗ 植被渲染失败: {e}")
|
||
|
||
def _calculate_lod_level(self, position: tuple) -> int:
|
||
"""
|
||
计算LOD级别
|
||
|
||
Args:
|
||
position: 位置坐标
|
||
|
||
Returns:
|
||
LOD级别索引
|
||
"""
|
||
try:
|
||
camera_pos = self.camera_config['position']
|
||
distance = math.sqrt(
|
||
(position[0] - camera_pos[0])**2 +
|
||
(position[1] - camera_pos[1])**2 +
|
||
(position[2] - camera_pos[2])**2
|
||
)
|
||
|
||
# 根据距离选择LOD级别
|
||
for i, level in enumerate(self.lod_system['levels']):
|
||
if distance <= level['distance']:
|
||
return min(i, len(self.lod_system['levels']) - 1)
|
||
|
||
return len(self.lod_system['levels']) - 1
|
||
|
||
except Exception as e:
|
||
print(f"✗ LOD级别计算失败: {e}")
|
||
return 0
|
||
|
||
def _calculate_vegetation_color(self, instance: Dict[str, Any], veg_info: Dict[str, Any]) -> tuple:
|
||
"""
|
||
计算植被颜色
|
||
|
||
Args:
|
||
instance: 植被实例
|
||
veg_info: 植被信息
|
||
|
||
Returns:
|
||
RGB颜色元组
|
||
"""
|
||
try:
|
||
base_color = veg_info.get('color', (0.2, 0.8, 0.2))
|
||
|
||
# 基于健康度调整颜色
|
||
if self.shading_config['health_based_color']:
|
||
health = instance['health']
|
||
if health > 0.7:
|
||
color = self.color_schemes['vegetation']['healthy']
|
||
elif health > 0.3:
|
||
color = self.color_schemes['vegetation']['stressed']
|
||
elif health > 0.1:
|
||
color = self.color_schemes['vegetation']['dying']
|
||
else:
|
||
color = self.color_schemes['vegetation']['dormant']
|
||
|
||
# 混合基础颜色和健康颜色
|
||
color = tuple((base_color[i] + color[i]) / 2 for i in range(3))
|
||
else:
|
||
color = base_color
|
||
|
||
return color
|
||
|
||
except Exception as e:
|
||
print(f"✗ 植被颜色计算失败: {e}")
|
||
return (0.2, 0.8, 0.2)
|
||
|
||
def render_animals(self):
|
||
"""渲染动物"""
|
||
try:
|
||
if not self.enabled or not self.render_config['render_animals']:
|
||
return
|
||
|
||
if not self.plugin.animal_simulator:
|
||
return
|
||
|
||
# 获取所有动物实例
|
||
instances = self.plugin.animal_simulator.get_all_animal_instances()
|
||
|
||
for instance_id, instance in instances.items():
|
||
if not instance['alive']:
|
||
continue
|
||
|
||
# 获取动物种类信息
|
||
species = instance['species']
|
||
species_info = self.plugin.animal_simulator.get_animal_info(species)
|
||
|
||
if not species_info:
|
||
continue
|
||
|
||
# 计算LOD级别
|
||
lod_level = self._calculate_lod_level(instance['position'])
|
||
|
||
# 在实际实现中,这里会调用渲染API进行渲染
|
||
|
||
self.visualization_stats['draw_calls'] += len(instances)
|
||
|
||
except Exception as e:
|
||
print(f"✗ 动物渲染失败: {e}")
|
||
|
||
def render_ecosystem_effects(self):
|
||
"""渲染生态系统特效"""
|
||
try:
|
||
if not self.enabled or not self.render_config['render_effects']:
|
||
return
|
||
|
||
# 在实际实现中,这里会渲染各种生态系统特效
|
||
# 如花粉飘散、落叶、动物足迹等
|
||
|
||
self.visualization_stats['effects_applied'] += 1
|
||
|
||
except Exception as e:
|
||
print(f"✗ 生态系统特效渲染失败: {e}")
|
||
|
||
def set_render_config(self, config: Dict[str, Any]):
|
||
"""
|
||
设置渲染配置
|
||
|
||
Args:
|
||
config: 渲染配置字典
|
||
"""
|
||
try:
|
||
self.render_config.update(config)
|
||
print(f"✓ 渲染配置已更新: {self.render_config}")
|
||
except Exception as e:
|
||
print(f"✗ 渲染配置更新失败: {e}")
|
||
|
||
def get_render_config(self) -> Dict[str, Any]:
|
||
"""
|
||
获取渲染配置
|
||
|
||
Returns:
|
||
渲染配置字典
|
||
"""
|
||
return self.render_config.copy()
|
||
|
||
def set_shading_config(self, config: Dict[str, Any]):
|
||
"""
|
||
设置着色配置
|
||
|
||
Args:
|
||
config: 着色配置字典
|
||
"""
|
||
try:
|
||
self.shading_config.update(config)
|
||
print(f"✓ 着色配置已更新: {self.shading_config}")
|
||
except Exception as e:
|
||
print(f"✗ 着色配置更新失败: {e}")
|
||
|
||
def get_shading_config(self) -> Dict[str, Any]:
|
||
"""
|
||
获取着色配置
|
||
|
||
Returns:
|
||
着色配置字典
|
||
"""
|
||
return self.shading_config.copy()
|
||
|
||
def set_effect_config(self, config: Dict[str, Any]):
|
||
"""
|
||
设置特效配置
|
||
|
||
Args:
|
||
config: 特效配置字典
|
||
"""
|
||
try:
|
||
self.effect_config.update(config)
|
||
print(f"✓ 特效配置已更新: {self.effect_config}")
|
||
except Exception as e:
|
||
print(f"✗ 特效配置更新失败: {e}")
|
||
|
||
def get_effect_config(self) -> Dict[str, Any]:
|
||
"""
|
||
获取特效配置
|
||
|
||
Returns:
|
||
特效配置字典
|
||
"""
|
||
return self.effect_config.copy()
|
||
|
||
def set_camera_config(self, config: Dict[str, Any]):
|
||
"""
|
||
设置相机配置
|
||
|
||
Args:
|
||
config: 相机配置字典
|
||
"""
|
||
try:
|
||
self.camera_config.update(config)
|
||
print(f"✓ 相机配置已更新: {self.camera_config}")
|
||
except Exception as e:
|
||
print(f"✗ 相机配置更新失败: {e}")
|
||
|
||
def get_camera_config(self) -> Dict[str, Any]:
|
||
"""
|
||
获取相机配置
|
||
|
||
Returns:
|
||
相机配置字典
|
||
"""
|
||
return self.camera_config.copy()
|
||
|
||
def get_lod_system(self) -> Dict[str, Any]:
|
||
"""
|
||
获取LOD系统配置
|
||
|
||
Returns:
|
||
LOD系统配置字典
|
||
"""
|
||
return self.lod_system.copy()
|
||
|
||
def set_lod_level(self, level: int, distance: float, detail: str, polygon_count: int):
|
||
"""
|
||
设置LOD级别
|
||
|
||
Args:
|
||
level: LOD级别索引
|
||
distance: 距离阈值
|
||
detail: 细节级别
|
||
polygon_count: 多边形数量
|
||
"""
|
||
try:
|
||
if 0 <= level < len(self.lod_system['levels']):
|
||
self.lod_system['levels'][level] = {
|
||
'distance': distance,
|
||
'detail': detail,
|
||
'polygon_count': polygon_count
|
||
}
|
||
print(f"✓ LOD级别 {level} 已更新")
|
||
else:
|
||
print(f"✗ 无效的LOD级别: {level}")
|
||
|
||
except Exception as e:
|
||
print(f"✗ LOD级别设置失败: {e}")
|
||
|
||
def get_color_schemes(self) -> Dict[str, Dict[str, tuple]]:
|
||
"""
|
||
获取颜色方案
|
||
|
||
Returns:
|
||
颜色方案字典
|
||
"""
|
||
return self.color_schemes.copy()
|
||
|
||
def set_color_scheme(self, category: str, scheme_name: str, color: tuple):
|
||
"""
|
||
设置颜色方案
|
||
|
||
Args:
|
||
category: 颜色类别
|
||
scheme_name: 方案名称
|
||
color: RGB颜色元组
|
||
"""
|
||
try:
|
||
if category in self.color_schemes:
|
||
self.color_schemes[category][scheme_name] = color
|
||
print(f"✓ 颜色方案已更新: {category}.{scheme_name}")
|
||
else:
|
||
print(f"✗ 无效的颜色类别: {category}")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 颜色方案设置失败: {e}")
|
||
|
||
def get_visualization_stats(self) -> Dict[str, Any]:
|
||
"""
|
||
获取可视化统计信息
|
||
|
||
Returns:
|
||
统计信息字典
|
||
"""
|
||
return self.visualization_stats.copy()
|
||
|
||
def reset_visualization_stats(self):
|
||
"""重置可视化统计信息"""
|
||
try:
|
||
self.visualization_stats = {
|
||
'rendered_instances': 0,
|
||
'draw_calls': 0,
|
||
'render_time': 0.0,
|
||
'lod_transitions': 0,
|
||
'effects_applied': 0
|
||
}
|
||
print("✓ 可视化统计信息已重置")
|
||
except Exception as e:
|
||
print(f"✗ 可视化统计信息重置失败: {e}")
|
||
|
||
def clear_render_cache(self):
|
||
"""清空渲染缓存"""
|
||
try:
|
||
self.render_cache.clear()
|
||
print("✓ 渲染缓存已清空")
|
||
except Exception as e:
|
||
print(f"✗ 渲染缓存清空失败: {e}")
|
||
|
||
def get_cache_info(self) -> Dict[str, Any]:
|
||
"""
|
||
获取缓存信息
|
||
|
||
Returns:
|
||
缓存信息字典
|
||
"""
|
||
try:
|
||
return {
|
||
'cache_size': len(self.render_cache),
|
||
'max_size': self.cache_config['max_cache_size'],
|
||
'timeout': self.cache_config['cache_timeout']
|
||
}
|
||
except Exception as e:
|
||
print(f"✗ 缓存信息获取失败: {e}")
|
||
return {}
|
||
|
||
def set_cache_config(self, config: Dict[str, Any]):
|
||
"""
|
||
设置缓存配置
|
||
|
||
Args:
|
||
config: 缓存配置字典
|
||
"""
|
||
try:
|
||
self.cache_config.update(config)
|
||
print(f"✓ 缓存配置已更新: {self.cache_config}")
|
||
except Exception as e:
|
||
print(f"✗ 缓存配置更新失败: {e}")
|
||
|
||
def capture_screenshot(self, filename: str = None) -> str:
|
||
"""
|
||
截取屏幕截图
|
||
|
||
Args:
|
||
filename: 文件名(如果为None则自动生成)
|
||
|
||
Returns:
|
||
截图文件路径
|
||
"""
|
||
try:
|
||
if filename is None:
|
||
timestamp = int(time.time())
|
||
filename = f"ecosystem_screenshot_{timestamp}.png"
|
||
|
||
# 在实际实现中,这里会调用渲染API截取屏幕
|
||
print(f"✓ 屏幕截图已保存: {filename}")
|
||
return filename
|
||
|
||
except Exception as e:
|
||
print(f"✗ 屏幕截图失败: {e}")
|
||
return ""
|
||
|
||
def render_heightmap(self) -> bool:
|
||
"""
|
||
渲染高度图
|
||
|
||
Returns:
|
||
是否渲染成功
|
||
"""
|
||
try:
|
||
# 在实际实现中,这里会渲染地形高度图
|
||
print("✓ 高度图渲染完成")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 高度图渲染失败: {e}")
|
||
return False
|
||
|
||
def render_vegetation_density_map(self) -> bool:
|
||
"""
|
||
渲染植被密度图
|
||
|
||
Returns:
|
||
是否渲染成功
|
||
"""
|
||
try:
|
||
# 在实际实现中,这里会渲染植被密度图
|
||
print("✓ 植被密度图渲染完成")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 植被密度图渲染失败: {e}")
|
||
return False
|
||
|
||
def toggle_wireframe_mode(self):
|
||
"""切换线框模式"""
|
||
try:
|
||
# 在实际实现中,这里会切换渲染模式
|
||
print("✓ 线框模式已切换")
|
||
except Exception as e:
|
||
print(f"✗ 线框模式切换失败: {e}")
|
||
|
||
def toggle_debug_info(self):
|
||
"""切换调试信息显示"""
|
||
try:
|
||
# 在实际实现中,这里会切换调试信息显示
|
||
print("✓ 调试信息显示已切换")
|
||
except Exception as e:
|
||
print(f"✗ 调试信息显示切换失败: {e}") |