382 lines
14 KiB
Python
382 lines
14 KiB
Python
"""
|
||
地形优化和LOD系统
|
||
提供完整的地形优化功能,包括LOD控制、碰撞优化、渲染优化和性能监控
|
||
"""
|
||
|
||
from panda3d.core import BitMask32, GeoMipTerrain
|
||
import time
|
||
import psutil
|
||
import gc
|
||
|
||
class TerrainOptimization:
|
||
"""
|
||
地形优化和LOD系统类
|
||
提供完整的地形优化功能
|
||
"""
|
||
|
||
def __init__(self, world):
|
||
self.world = world
|
||
self.lod_enabled = True
|
||
self.lod_threshold = 50.0
|
||
self.min_block_size = 16
|
||
self.max_block_size = 64
|
||
self.auto_lod_enabled = True
|
||
self.performance_monitoring = True
|
||
self.last_optimization_time = 0
|
||
|
||
def enable_lod(self, enabled=True):
|
||
"""
|
||
启用或禁用LOD
|
||
"""
|
||
self.lod_enabled = enabled
|
||
print(f"LOD系统已{'启用' if enabled else '禁用'}")
|
||
|
||
def set_lod_threshold(self, threshold):
|
||
"""
|
||
设置LOD阈值
|
||
"""
|
||
self.lod_threshold = max(1.0, min(1000.0, float(threshold)))
|
||
print(f"LOD阈值设置为: {self.lod_threshold}")
|
||
|
||
def set_auto_lod(self, enabled=True):
|
||
"""
|
||
启用或禁用自动LOD调整
|
||
"""
|
||
self.auto_lod_enabled = enabled
|
||
print(f"自动LOD调整已{'启用' if enabled else '禁用'}")
|
||
|
||
def update_terrain_lod(self, terrain_info):
|
||
"""
|
||
更新单个地形的LOD
|
||
"""
|
||
if not self.lod_enabled:
|
||
return
|
||
|
||
try:
|
||
if terrain_info in self.world.terrain_manager.terrains:
|
||
terrain = terrain_info['terrain']
|
||
if hasattr(terrain, 'setNearFarThreshold'):
|
||
# 设置LOD阈值
|
||
near_threshold = self.lod_threshold
|
||
far_threshold = self.lod_threshold * 2
|
||
terrain.setNearFarThreshold(near_threshold, far_threshold)
|
||
|
||
# 如果启用自动LOD,根据距离动态调整
|
||
if self.auto_lod_enabled:
|
||
distance = self._calculate_terrain_distance(terrain_info)
|
||
if distance > 200:
|
||
# 远距离时使用更大的块
|
||
block_size = min(self.max_block_size, int(distance / 10))
|
||
else:
|
||
# 近距离时使用更小的块
|
||
block_size = max(self.min_block_size, int(64 - distance / 5))
|
||
|
||
self.set_terrain_block_size(terrain_info, block_size)
|
||
|
||
except Exception as e:
|
||
print(f"更新地形LOD时出错: {e}")
|
||
|
||
def update_all_terrains_lod(self):
|
||
"""
|
||
更新所有地形的LOD
|
||
"""
|
||
if not self.lod_enabled:
|
||
return
|
||
|
||
if hasattr(self.world, 'terrain_manager'):
|
||
for terrain_info in self.world.terrain_manager.terrains:
|
||
self.update_terrain_lod(terrain_info)
|
||
|
||
def optimize_terrain_collision(self, terrain_info):
|
||
"""
|
||
优化地形碰撞体
|
||
"""
|
||
try:
|
||
terrain_node = terrain_info['node']
|
||
if terrain_node:
|
||
# 清除现有的碰撞体
|
||
for child in terrain_node.getChildren():
|
||
if child.getName().startswith("terrain_collision_"):
|
||
child.removeNode()
|
||
|
||
# 设置地形节点的碰撞掩码
|
||
terrain_node.setCollideMask(BitMask32.bit(2))
|
||
|
||
# 为地形的所有子节点也设置碰撞掩码
|
||
for child in terrain_node.getChildren():
|
||
child.setCollideMask(BitMask32.bit(2))
|
||
|
||
# 如果地形很大,可以考虑创建简化的碰撞网格
|
||
if self._should_simplify_collision(terrain_info):
|
||
self._create_simplified_collision(terrain_info)
|
||
|
||
print("地形碰撞体已优化")
|
||
return True
|
||
except Exception as e:
|
||
print(f"优化地形碰撞体时出错: {e}")
|
||
return False
|
||
|
||
def _should_simplify_collision(self, terrain_info):
|
||
"""
|
||
判断是否需要简化碰撞体
|
||
"""
|
||
try:
|
||
heightfield = terrain_info.get('heightfield')
|
||
if heightfield:
|
||
width = heightfield.getXSize()
|
||
height = heightfield.getYSize()
|
||
# 如果地形分辨率很高,考虑简化碰撞
|
||
return width > 256 or height > 256
|
||
return False
|
||
except:
|
||
return False
|
||
|
||
def _create_simplified_collision(self, terrain_info):
|
||
"""
|
||
创建简化的碰撞体
|
||
"""
|
||
print("创建简化的地形碰撞体")
|
||
# 这里可以实现创建低分辨率碰撞网格的逻辑
|
||
|
||
def optimize_terrain_rendering(self, terrain_info):
|
||
"""
|
||
优化地形渲染
|
||
"""
|
||
try:
|
||
terrain_node = terrain_info['node']
|
||
if terrain_node:
|
||
# 如果使用RenderPipeline,应用优化效果
|
||
if hasattr(self.world, 'render_pipeline'):
|
||
try:
|
||
# 根据距离选择不同的效果
|
||
distance = self._calculate_terrain_distance(terrain_info)
|
||
if distance > 100:
|
||
# 远距离使用简化效果
|
||
effect_file = "effects/terrain_far.yaml"
|
||
else:
|
||
# 近距离使用高质量效果
|
||
effect_file = "effects/terrain_near.yaml"
|
||
|
||
self.world.render_pipeline.set_effect(
|
||
terrain_node,
|
||
effect_file,
|
||
{
|
||
"normal_mapping": distance < 50, # 近距离启用法线贴图
|
||
"parallax_mapping": distance < 30, # 很近距离启用视差贴图
|
||
"lod_rendering": self.lod_enabled,
|
||
"distance": distance
|
||
},
|
||
15 # 排序值
|
||
)
|
||
print(f"应用优化的地形渲染效果: {effect_file}")
|
||
except Exception as e:
|
||
print(f"应用优化渲染效果失败: {e}")
|
||
|
||
# 设置渲染优先级
|
||
terrain_node.setBin("background", 0)
|
||
terrain_node.setDepthWrite(True)
|
||
|
||
return True
|
||
except Exception as e:
|
||
print(f"优化地形渲染时出错: {e}")
|
||
return False
|
||
|
||
def get_terrain_performance_stats(self, terrain_info):
|
||
"""
|
||
获取地形性能统计信息
|
||
"""
|
||
stats = {
|
||
'lod_enabled': self.lod_enabled,
|
||
'lod_threshold': self.lod_threshold,
|
||
'vertices': 0,
|
||
'triangles': 0,
|
||
'memory_usage': 0,
|
||
'block_size': 32,
|
||
'distance': 0
|
||
}
|
||
|
||
try:
|
||
terrain = terrain_info['terrain']
|
||
if terrain:
|
||
# 获取地形几何信息
|
||
if hasattr(terrain, 'getRoot'):
|
||
root_node = terrain.getRoot()
|
||
if root_node:
|
||
# 估算顶点和三角形数量
|
||
heightfield = terrain_info.get('heightfield')
|
||
if heightfield:
|
||
width = heightfield.getXSize()
|
||
height = heightfield.getYSize()
|
||
stats['vertices'] = width * height
|
||
stats['triangles'] = (width - 1) * (height - 1) * 2
|
||
|
||
# 获取块大小
|
||
if hasattr(terrain, 'getBlockSize'):
|
||
stats['block_size'] = terrain.getBlockSize()
|
||
|
||
# 计算距离
|
||
stats['distance'] = self._calculate_terrain_distance(terrain_info)
|
||
|
||
except Exception as e:
|
||
print(f"获取地形性能统计时出错: {e}")
|
||
|
||
return stats
|
||
|
||
def auto_optimize_terrains(self):
|
||
"""
|
||
自动优化所有地形
|
||
"""
|
||
if not hasattr(self.world, 'terrain_manager'):
|
||
return
|
||
|
||
# 检查是否需要优化(避免过于频繁的优化)
|
||
current_time = time.time()
|
||
if current_time - self.last_optimization_time < 1.0: # 至少间隔1秒
|
||
return
|
||
|
||
self.last_optimization_time = current_time
|
||
|
||
optimized_count = 0
|
||
for terrain_info in self.world.terrain_manager.terrains:
|
||
# 优化碰撞体
|
||
if self.optimize_terrain_collision(terrain_info):
|
||
optimized_count += 1
|
||
|
||
# 优化渲染
|
||
if self.optimize_terrain_rendering(terrain_info):
|
||
optimized_count += 1
|
||
|
||
# 更新LOD
|
||
self.update_terrain_lod(terrain_info)
|
||
|
||
# 更新所有地形的LOD
|
||
self.update_all_terrains_lod()
|
||
|
||
# 执行垃圾回收
|
||
if optimized_count > 0:
|
||
gc.collect()
|
||
|
||
print(f"自动优化完成,优化了 {optimized_count} 个项目")
|
||
|
||
def set_terrain_block_size(self, terrain_info, block_size):
|
||
"""
|
||
设置地形块大小(影响LOD效果)
|
||
"""
|
||
try:
|
||
# 限制块大小范围
|
||
block_size = max(self.min_block_size, min(self.max_block_size, int(block_size)))
|
||
|
||
terrain = terrain_info['terrain']
|
||
if hasattr(terrain, 'setBlockSize'):
|
||
terrain.setBlockSize(block_size)
|
||
print(f"地形块大小设置为: {block_size}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"设置地形块大小时出错: {e}")
|
||
return False
|
||
return False
|
||
|
||
def set_block_size_range(self, min_size, max_size):
|
||
"""
|
||
设置块大小范围
|
||
"""
|
||
self.min_block_size = max(8, min(128, int(min_size)))
|
||
self.max_block_size = max(8, min(128, int(max_size)))
|
||
print(f"地形块大小范围设置为: {self.min_block_size} - {self.max_block_size}")
|
||
|
||
def _calculate_terrain_distance(self, terrain_info):
|
||
"""
|
||
计算地形到相机的距离
|
||
"""
|
||
try:
|
||
terrain_node = terrain_info['node']
|
||
if terrain_node and hasattr(self.world, 'cam'):
|
||
terrain_pos = terrain_node.getPos()
|
||
camera_pos = self.world.cam.getPos()
|
||
distance = (terrain_pos - camera_pos).length()
|
||
return distance
|
||
return 50.0 # 默认距离
|
||
except:
|
||
return 50.0
|
||
|
||
def enable_performance_monitoring(self, enabled=True):
|
||
"""
|
||
启用或禁用性能监控
|
||
"""
|
||
self.performance_monitoring = enabled
|
||
print(f"性能监控已{'启用' if enabled else '禁用'}")
|
||
|
||
def get_system_performance_stats(self):
|
||
"""
|
||
获取系统性能统计信息
|
||
"""
|
||
try:
|
||
# 获取内存使用情况
|
||
process = psutil.Process()
|
||
memory_info = process.memory_info()
|
||
|
||
# 获取CPU使用率
|
||
cpu_percent = process.cpu_percent()
|
||
|
||
return {
|
||
'memory_rss': memory_info.rss,
|
||
'memory_vms': memory_info.vms,
|
||
'cpu_percent': cpu_percent,
|
||
'terrain_count': len(self.world.terrain_manager.terrains) if hasattr(self.world, 'terrain_manager') else 0
|
||
}
|
||
except Exception as e:
|
||
print(f"获取系统性能统计时出错: {e}")
|
||
return {}
|
||
|
||
def optimize_memory_usage(self):
|
||
"""
|
||
优化内存使用
|
||
"""
|
||
try:
|
||
# 执行垃圾回收
|
||
collected = gc.collect()
|
||
print(f"执行垃圾回收,清理了 {collected} 个对象")
|
||
|
||
# 优化纹理内存使用
|
||
if hasattr(self.world, 'texture_cache'):
|
||
self.world.texture_cache.clear_unused()
|
||
|
||
return True
|
||
except Exception as e:
|
||
print(f"优化内存使用时出错: {e}")
|
||
return False
|
||
|
||
def set_render_distance(self, distance):
|
||
"""
|
||
设置渲染距离
|
||
"""
|
||
try:
|
||
if hasattr(self.world, 'camLens'):
|
||
self.world.camLens.setNearFar(0.1, float(distance))
|
||
print(f"渲染距离设置为: {distance}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"设置渲染距离时出错: {e}")
|
||
return False
|
||
return False
|
||
|
||
def enable_frustum_culling(self, enabled=True):
|
||
"""
|
||
启用或禁用视锥体剔除
|
||
"""
|
||
try:
|
||
if hasattr(self.world, 'terrain_manager'):
|
||
for terrain_info in self.world.terrain_manager.terrains:
|
||
terrain_node = terrain_info['node']
|
||
if terrain_node:
|
||
if enabled:
|
||
terrain_node.setAttrib(CullFaceAttrib.makePanda())
|
||
else:
|
||
terrain_node.clearAttrib(CullFaceAttrib.getClassType())
|
||
|
||
print(f"视锥体剔除已{'启用' if enabled else '禁用'}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"设置视锥体剔除时出错: {e}")
|
||
return False
|
||
return False |