EG/plugins/user/terrain_editor/optimization/terrain_optimization.py
2025-12-12 16:16:15 +08:00

382 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
地形优化和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