""" 地形渲染器 负责渲染程序化生成的地形 """ import numpy as np import math from typing import Dict, Any, List, Tuple class TerrainRenderer: """ 地形渲染器 负责渲染程序化生成的地形,包括网格生成、纹理映射、光照计算等 """ def __init__(self, plugin): """ 初始化地形渲染器 Args: plugin: 程序化地形生成插件实例 """ self.plugin = plugin self.enabled = False self.initialized = False # 渲染配置 self.render_params = { 'resolution': plugin.config.get('terrain_size', 512), 'lod_levels': plugin.config.get('lod_levels', 5), 'chunk_size': plugin.config.get('chunk_size', 32), 'max_distance': 1000.0, 'lod_distance_factor': 2.0 } # 光照参数 self.lighting_params = { 'ambient_light': 0.3, 'diffuse_light': 0.7, 'specular_light': 0.2, 'light_direction': [0.5, 0.5, 0.5], 'light_color': [1.0, 1.0, 1.0] } # 材质参数 self.material_params = { 'diffuse_texture': True, 'normal_mapping': True, 'specular_mapping': False, 'texture_scale': 1.0, 'tessellation_factor': 1.0 } # 着色器参数 self.shader_params = { 'vertex_shader': 'terrain_vertex.glsl', 'fragment_shader': 'terrain_fragment.glsl', 'geometry_shader': None, 'tessellation_control_shader': None, 'tessellation_evaluation_shader': None } # 渲染状态 self.render_buffers = {} self.vertex_arrays = {} self.textures = {} self.shaders = {} # LOD管理 self.lod_chunks = {} self.visible_chunks = set() # 统计信息 self.stats = { 'chunks_rendered': 0, 'vertices_rendered': 0, 'triangles_rendered': 0, 'render_time': 0.0, 'average_render_time': 0.0, 'lod_switches': 0 } print("✓ 地形渲染器已创建") def initialize(self) -> bool: """ 初始化地形渲染器 Returns: 是否初始化成功 """ try: # 初始化渲染资源(在实际实现中会初始化GPU资源) self._initialize_render_resources() 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._cleanup_render_resources() 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 # 更新LOD self._update_lod() # 更新可见区块 self._update_visible_chunks() except Exception as e: print(f"✗ 地形渲染器更新失败: {e}") import traceback traceback.print_exc() def _initialize_render_resources(self): """初始化渲染资源""" try: # 在实际实现中,这里会初始化GPU缓冲区、纹理、着色器等 print(" → 初始化渲染缓冲区...") print(" → 初始化着色器...") print(" → 初始化纹理...") # 模拟创建一些基本的渲染资源 self.render_buffers['terrain_vertices'] = [] self.render_buffers['terrain_indices'] = [] self.vertex_arrays['terrain_vao'] = [] self.textures['terrain_diffuse'] = [] self.textures['terrain_normal'] = [] self.shaders['terrain_shader'] = [] except Exception as e: print(f"✗ 渲染资源初始化失败: {e}") def _cleanup_render_resources(self): """清理渲染资源""" try: # 在实际实现中,这里会清理GPU资源 self.render_buffers.clear() self.vertex_arrays.clear() self.textures.clear() self.shaders.clear() self.lod_chunks.clear() self.visible_chunks.clear() except Exception as e: print(f"✗ 渲染资源清理失败: {e}") def render_terrain(self, camera_position: List[float], view_matrix: np.ndarray, projection_matrix: np.ndarray) -> bool: """ 渲染地形 Args: camera_position: 摄像机位置 view_matrix: 视图矩阵 projection_matrix: 投影矩阵 Returns: 是否渲染成功 """ try: if not self.enabled: print("✗ 地形渲染器未启用") return False import time render_start_time = time.time() print("✓ 开始渲染地形...") # 更新摄像机相关数据 self._update_camera_data(camera_position, view_matrix, projection_matrix) # 准备渲染数据 self._prepare_render_data() # 执行渲染 self._execute_rendering() # 更新统计信息 render_time = time.time() - render_start_time self.stats['render_time'] = render_time self.stats['chunks_rendered'] += len(self.visible_chunks) if self.stats['chunks_rendered'] > 0: self.stats['average_render_time'] = ( self.stats['average_render_time'] * (self.stats['chunks_rendered'] - 1) + render_time ) / self.stats['chunks_rendered'] print(f"✓ 地形渲染完成,耗时: {render_time:.3f}秒") return True except Exception as e: print(f"✗ 地形渲染失败: {e}") import traceback traceback.print_exc() return False def _update_camera_data(self, camera_position: List[float], view_matrix: np.ndarray, projection_matrix: np.ndarray): """更新摄像机相关数据""" try: # 在实际实现中,这里会更新着色器中的摄像机参数 pass except Exception as e: print(f"✗ 摄像机数据更新失败: {e}") def _prepare_render_data(self): """准备渲染数据""" try: # 在实际实现中,这里会准备顶点缓冲区、索引缓冲区等 pass except Exception as e: print(f"✗ 渲染数据准备失败: {e}") def _execute_rendering(self): """执行渲染""" try: # 在实际实现中,这里会调用GPU渲染命令 print(" → 绑定着色器程序...") print(" → 设置光照参数...") print(" → 绑定纹理...") print(" → 渲染可见区块...") # 模拟渲染过程 for chunk_key in self.visible_chunks: print(f" → 渲染区块 {chunk_key}") except Exception as e: print(f"✗ 渲染执行失败: {e}") def _update_lod(self): """更新LOD级别""" try: # 在实际实现中,这里会根据摄像机距离更新每个区块的LOD级别 pass except Exception as e: print(f"✗ LOD更新失败: {e}") def _update_visible_chunks(self): """更新可见区块""" try: # 在实际实现中,这里会根据视锥体剔除确定可见区块 if self.plugin.terrain_manager: terrain_data = self.plugin.terrain_manager.get_terrain_data() if terrain_data.get('is_generating', False): # 如果地形正在生成,暂时不更新可见区块 return # 获取可见区块列表 visible_chunk_keys = self.plugin.terrain_manager.get_visible_chunks() self.visible_chunks = set(visible_chunk_keys) except Exception as e: print(f"✗ 可见区块更新失败: {e}") def set_render_parameters(self, params: Dict[str, Any]): """ 设置渲染参数 Args: params: 渲染参数字典 """ self.render_params.update(params) print(f"✓ 渲染参数已更新: {self.render_params}") def set_lighting_parameters(self, params: Dict[str, Any]): """ 设置光照参数 Args: params: 光照参数字典 """ self.lighting_params.update(params) print(f"✓ 光照参数已更新: {self.lighting_params}") def set_material_parameters(self, params: Dict[str, Any]): """ 设置材质参数 Args: params: 材质参数字典 """ self.material_params.update(params) print(f"✓ 材质参数已更新: {self.material_params}") def set_shader_parameters(self, params: Dict[str, Any]): """ 设置着色器参数 Args: params: 着色器参数字典 """ self.shader_params.update(params) print(f"✓ 着色器参数已更新: {self.shader_params}") def get_stats(self) -> Dict[str, Any]: """ 获取统计信息 Returns: 统计信息字典 """ return self.stats.copy() def reset_stats(self): """重置统计信息""" self.stats = { 'chunks_rendered': 0, 'vertices_rendered': 0, 'triangles_rendered': 0, 'render_time': 0.0, 'average_render_time': 0.0, 'lod_switches': 0 } print("✓ 地形渲染器统计信息已重置") def generate_terrain_mesh(self, heightmap: np.ndarray, resolution: int = None) -> Dict[str, np.ndarray]: """ 生成地形网格 Args: heightmap: 高度图数据 resolution: 网格分辨率 Returns: 包含顶点、法线、纹理坐标和索引的字典 """ try: if resolution is None: resolution = self.render_params['resolution'] print(f"✓ 开始生成 {resolution}x{resolution} 地形网格...") # 创建网格数据 vertices = [] normals = [] texcoords = [] indices = [] # 生成顶点数据 height, width = heightmap.shape scale_x = 1.0 / (width - 1) scale_y = 1.0 / (height - 1) # 生成顶点 for y in range(height): for x in range(width): # 顶点位置 vertex_x = (x / (width - 1)) * 2.0 - 1.0 # -1 到 1 vertex_y = heightmap[y, x] # 高度值 vertex_z = (y / (height - 1)) * 2.0 - 1.0 # -1 到 1 vertices.extend([vertex_x, vertex_y, vertex_z]) # 纹理坐标 texcoord_u = x / (width - 1) texcoord_v = 1.0 - y / (height - 1) # 翻转V坐标 texcoords.extend([texcoord_u, texcoord_v]) # 计算法线 normals = self._calculate_normals(heightmap) # 生成索引(三角形列表) for y in range(height - 1): for x in range(width - 1): # 第一个三角形 indices.append(y * width + x) indices.append(y * width + x + 1) indices.append((y + 1) * width + x) # 第二个三角形 indices.append((y + 1) * width + x) indices.append(y * width + x + 1) indices.append((y + 1) * width + x + 1) # 转换为numpy数组 vertices_array = np.array(vertices, dtype=np.float32) normals_array = np.array(normals, dtype=np.float32) texcoords_array = np.array(texcoords, dtype=np.float32) indices_array = np.array(indices, dtype=np.uint32) # 更新统计信息 self.stats['vertices_rendered'] = len(vertices) // 3 self.stats['triangles_rendered'] = len(indices) // 3 print(f"✓ 地形网格生成完成: {len(vertices)//3} 顶点, {len(indices)//3} 三角形") return { 'vertices': vertices_array, 'normals': normals_array, 'texcoords': texcoords_array, 'indices': indices_array } except Exception as e: print(f"✗ 地形网格生成失败: {e}") import traceback traceback.print_exc() return { 'vertices': np.array([], dtype=np.float32), 'normals': np.array([], dtype=np.float32), 'texcoords': np.array([], dtype=np.float32), 'indices': np.array([], dtype=np.uint32) } def _calculate_normals(self, heightmap: np.ndarray) -> List[float]: """ 计算法线 Args: heightmap: 高度图数据 Returns: 法线数据列表 """ try: height, width = heightmap.shape normals = [] for y in range(height): for x in range(width): # 计算相邻点的高度 h_left = heightmap[y, max(0, x-1)] h_right = heightmap[y, min(width-1, x+1)] h_up = heightmap[max(0, y-1), x] h_down = heightmap[min(height-1, y+1), x] # 计算梯度 dx = (h_right - h_left) * width / 2.0 dy = (h_down - h_up) * height / 2.0 dz = 2.0 # 计算法线 normal = [-dx, -dy, dz] norm = math.sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]) if norm > 0: normal = [n/norm for n in normal] else: normal = [0.0, 0.0, 1.0] normals.extend(normal) return normals except Exception as e: print(f"✗ 法线计算失败: {e}") # 返回默认法线 height, width = heightmap.shape return [0.0, 0.0, 1.0] * height * width def generate_terrain_texture(self, heightmap: np.ndarray, biome_map: np.ndarray = None, moisture_map: np.ndarray = None, temperature_map: np.ndarray = None) -> np.ndarray: """ 生成地形纹理 Args: heightmap: 高度图数据 biome_map: 生物群落图数据(可选) moisture_map: 湿度图数据(可选) temperature_map: 温度图数据(可选) Returns: 纹理数据 (RGBA格式) """ try: height, width = heightmap.shape print(f"✓ 开始生成 {width}x{height} 地形纹理...") # 创建RGBA纹理数据 texture_data = np.zeros((height, width, 4), dtype=np.uint8) # 如果有生物群落数据,基于生物群落生成纹理 if biome_map is not None and biome_map.shape == heightmap.shape: texture_data = self._generate_biome_based_texture(biome_map) else: # 基于高度生成基础纹理 texture_data = self._generate_height_based_texture(heightmap) # 如果有湿度和温度数据,添加细节 if moisture_map is not None and moisture_map.shape == heightmap.shape: texture_data = self._apply_moisture_effects(texture_data, moisture_map) if temperature_map is not None and temperature_map.shape == heightmap.shape: texture_data = self._apply_temperature_effects(texture_data, temperature_map) print("✓ 地形纹理生成完成") return texture_data except Exception as e: print(f"✗ 地形纹理生成失败: {e}") import traceback traceback.print_exc() # 返回默认纹理(蓝色) height, width = heightmap.shape return np.zeros((height, width, 4), dtype=np.uint8) def _generate_biome_based_texture(self, biome_map: np.ndarray) -> np.ndarray: """ 基于生物群落生成纹理 Args: biome_map: 生物群落图数据 Returns: 纹理数据 """ try: height, width = biome_map.shape texture_data = np.zeros((height, width, 4), dtype=np.uint8) # 生物群落颜色映射 biome_colors = { 0: [0, 0, 128, 255], # ocean - 深蓝色 1: [255, 255, 0, 255], # beach - 黄色 2: [144, 238, 144, 255], # plains - 浅绿色 3: [34, 139, 34, 255], # forest - 绿色 4: [0, 100, 0, 255], # jungle - 深绿色 5: [255, 165, 0, 255], # desert - 橙色 6: [139, 137, 137, 255], # mountain - 灰色 7: [255, 255, 255, 255], # snow - 白色 8: [0, 128, 128, 255], # taiga - 青色 9: [173, 216, 230, 255], # tundra - 淡蓝色 10: [128, 128, 0, 255], # swamp - 橄榄色 11: [255, 215, 0, 255] # savanna - 金色 } # 为每个像素分配颜色 for y in range(height): for x in range(width): biome_id = biome_map[y, x] color = biome_colors.get(biome_id, [128, 128, 128, 255]) # 默认灰色 texture_data[y, x] = color return texture_data except Exception as e: print(f"✗ 生物群落纹理生成失败: {e}") height, width = biome_map.shape return np.zeros((height, width, 4), dtype=np.uint8) def _generate_height_based_texture(self, heightmap: np.ndarray) -> np.ndarray: """ 基于高度生成纹理 Args: heightmap: 高度图数据 Returns: 纹理数据 """ try: height, width = heightmap.shape texture_data = np.zeros((height, width, 4), dtype=np.uint8) # 为每个像素根据高度分配颜色 for y in range(height): for x in range(width): height_value = heightmap[y, x] # 根据高度选择颜色 if height_value < 0.2: # 水域 - 蓝色 r, g, b = 0, 0, int(128 + height_value * 127) elif height_value < 0.3: # 浅水/海滩 - 浅蓝色 r, g, b = int(height_value * 255), int(height_value * 255), 255 elif height_value < 0.5: # 平原 - 绿色 r, g, b = 0, int(100 + height_value * 155), 0 elif height_value < 0.7: # 丘陵 - 棕色 r, g, b = int(139 * height_value), int(69 * height_value), int(19 * height_value) elif height_value < 0.9: # 山地 - 灰色 r, g, b = int(100 + height_value * 155), int(100 + height_value * 155), int(100 + height_value * 155) else: # 雪山 - 白色 r, g, b = 255, 255, 255 texture_data[y, x] = [r, g, b, 255] return texture_data except Exception as e: print(f"✗ 高度纹理生成失败: {e}") height, width = heightmap.shape return np.zeros((height, width, 4), dtype=np.uint8) def _apply_moisture_effects(self, texture_data: np.ndarray, moisture_map: np.ndarray) -> np.ndarray: """ 应用湿度效果到纹理 Args: texture_data: 原始纹理数据 moisture_map: 湿度图数据 Returns: 处理后的纹理数据 """ try: processed_texture = texture_data.copy() height, width = moisture_map.shape # 根据湿度调整颜色 for y in range(height): for x in range(width): moisture_value = moisture_map[y, x] # 增加蓝色调表示湿润 if moisture_value > 0.6: processed_texture[y, x, 2] = min(255, processed_texture[y, x, 2] + int(50 * moisture_value)) # 减少红色和绿色通道表示湿润 if moisture_value > 0.5: processed_texture[y, x, 0] = max(0, processed_texture[y, x, 0] - int(30 * moisture_value)) processed_texture[y, x, 1] = max(0, processed_texture[y, x, 1] - int(30 * moisture_value)) return processed_texture except Exception as e: print(f"✗ 湿度效果应用失败: {e}") return texture_data def _apply_temperature_effects(self, texture_data: np.ndarray, temperature_map: np.ndarray) -> np.ndarray: """ 应用温度效果到纹理 Args: texture_data: 原始纹理数据 temperature_map: 温度图数据 Returns: 处理后的纹理数据 """ try: processed_texture = texture_data.copy() height, width = temperature_map.shape # 根据温度调整颜色 for y in range(height): for x in range(width): temperature_value = temperature_map[y, x] # 增加热色调表示温暖 if temperature_value > 0.7: processed_texture[y, x, 0] = min(255, processed_texture[y, x, 0] + int(50 * (temperature_value - 0.7) / 0.3)) # 增加冷色调表示寒冷 if temperature_value < 0.3: processed_texture[y, x, 2] = min(255, processed_texture[y, x, 2] + int(50 * (0.3 - temperature_value) / 0.3)) return processed_texture except Exception as e: print(f"✗ 温度效果应用失败: {e}") return texture_data def generate_normal_map(self, heightmap: np.ndarray, strength: float = 1.0) -> np.ndarray: """ 生成法线贴图 Args: heightmap: 高度图数据 strength: 法线强度 Returns: 法线贴图数据 (RGB格式) """ try: height, width = heightmap.shape print(f"✓ 开始生成 {width}x{height} 法线贴图...") # 创建法线贴图数据 normal_map = np.zeros((height, width, 3), dtype=np.uint8) # 计算每个像素的法线 for y in range(height): for x in range(width): # 计算相邻点的高度 h_left = heightmap[y, max(0, x-1)] h_right = heightmap[y, min(width-1, x+1)] h_up = heightmap[max(0, y-1), x] h_down = heightmap[min(height-1, y+1), x] # 计算梯度 dx = (h_right - h_left) * strength dy = (h_down - h_up) * strength # 计算法线 (转换到0-1范围再转为0-255) normal_x = (dx + 1.0) * 0.5 normal_y = (dy + 1.0) * 0.5 normal_z = 1.0 # 假设主要朝向摄像机 normal_z = normal_z / math.sqrt(normal_x*normal_x + normal_y*normal_y + normal_z*normal_z) normal_z = (normal_z + 1.0) * 0.5 # 转换为8位值 normal_map[y, x] = [ int(normal_x * 255), int(normal_y * 255), int(normal_z * 255) ] print("✓ 法线贴图生成完成") return normal_map except Exception as e: print(f"✗ 法线贴图生成失败: {e}") import traceback traceback.print_exc() # 返回默认法线贴图(正面法线) height, width = heightmap.shape return np.full((height, width, 3), [128, 128, 255], dtype=np.uint8) def generate_splat_map(self, biome_map: np.ndarray, num_textures: int = 4) -> np.ndarray: """ 生成混合贴图(用于多重纹理混合) Args: biome_map: 生物群落图数据 num_textures: 纹理数量 Returns: 混合贴图数据 (RGBA格式,每个通道代表一种纹理的权重) """ try: height, width = biome_map.shape print(f"✓ 开始生成 {width}x{height} 混合贴图...") # 创建混合贴图数据 splat_map = np.zeros((height, width, 4), dtype=np.uint8) # 简化的混合贴图生成 # 在实际实现中,这里会根据生物群落类型和地形特征生成更复杂的混合 for y in range(height): for x in range(width): biome_id = biome_map[y, x] # 根据生物群落ID分配到不同的纹理通道 channel = biome_id % 4 splat_map[y, x, channel] = 255 print("✓ 混合贴图生成完成") return splat_map except Exception as e: print(f"✗ 混合贴图生成失败: {e}") import traceback traceback.print_exc() # 返回默认混合贴图 height, width = biome_map.shape return np.zeros((height, width, 4), dtype=np.uint8) def update_chunk_mesh(self, chunk_x: int, chunk_y: int, lod_level: int, heightmap: np.ndarray) -> bool: """ 更新区块网格 Args: chunk_x: 区块X坐标 chunk_y: 区块Y坐标 lod_level: LOD级别 heightmap: 高度图数据 Returns: 是否更新成功 """ try: chunk_key = f"{chunk_x},{chunk_y},{lod_level}" # 生成区块网格数据 mesh_data = self.generate_terrain_mesh(heightmap) # 存储到LOD区块中 if chunk_key not in self.lod_chunks: self.lod_chunks[chunk_key] = {} self.lod_chunks[chunk_key]['mesh_data'] = mesh_data self.lod_chunks[chunk_key]['last_update'] = time.time() print(f"✓ 区块 [{chunk_x}, {chunk_y}] LOD {lod_level} 网格已更新") return True except Exception as e: print(f"✗ 区块网格更新失败: {e}") import traceback traceback.print_exc() return False def get_chunk_mesh(self, chunk_x: int, chunk_y: int, lod_level: int) -> Dict[str, np.ndarray]: """ 获取区块网格数据 Args: chunk_x: 区块X坐标 chunk_y: 区块Y坐标 lod_level: LOD级别 Returns: 网格数据字典 """ try: chunk_key = f"{chunk_x},{chunk_y},{lod_level}" if chunk_key in self.lod_chunks: return self.lod_chunks[chunk_key].get('mesh_data', {}) else: return {} except Exception as e: print(f"✗ 区块网格获取失败: {e}") return {} def set_lod_distances(self, distances: List[float]): """ 设置LOD距离 Args: distances: LOD距离列表 """ self.render_params['lod_distances'] = distances print(f"✓ LOD距离已设置: {distances}") def get_lod_level(self, distance: float) -> int: """ 根据距离确定LOD级别 Args: distance: 距离 Returns: LOD级别 """ try: lod_distances = self.render_params.get('lod_distances', []) if not lod_distances: # 使用默认距离计算 base_distance = 100.0 for i in range(self.render_params['lod_levels']): if distance < base_distance * (i + 1): return i return self.render_params['lod_levels'] - 1 else: # 使用自定义距离 for i, lod_distance in enumerate(lod_distances): if distance < lod_distance: return i return len(lod_distances) - 1 except Exception as e: print(f"✗ LOD级别计算失败: {e}") return 0 def frustum_cull(self, camera_position: List[float], view_matrix: np.ndarray, projection_matrix: np.ndarray) -> List[Tuple[int, int]]: """ 视锥体剔除 Args: camera_position: 摄像机位置 view_matrix: 视图矩阵 projection_matrix: 投影矩阵 Returns: 可见区块列表 [(chunk_x, chunk_y), ...] """ try: # 在实际实现中,这里会进行复杂的视锥体剔除计算 # 简化实现:返回所有区块 visible_chunks = [] if self.plugin.terrain_manager: terrain_data = self.plugin.terrain_manager.get_terrain_data() terrain_size = terrain_data.get('stats', {}).get('chunks_generated', 0) if terrain_size > 0: # 模拟一些可见区块 for i in range(min(10, terrain_size)): visible_chunks.append((i, i)) return visible_chunks except Exception as e: print(f"✗ 视锥体剔除失败: {e}") return [] def occlusion_cull(self, visible_chunks: List[Tuple[int, int]]) -> List[Tuple[int, int]]: """ 遮挡剔除 Args: visible_chunks: 可见区块列表 Returns: 未被遮挡的区块列表 """ try: # 在实际实现中,这里会进行遮挡剔除计算 # 简化实现:返回所有可见区块 return visible_chunks except Exception as e: print(f"✗ 遮挡剔除失败: {e}") return visible_chunks def generate_terrain_materials(self, biome_map: np.ndarray) -> Dict[str, Any]: """ 生成地形材质 Args: biome_map: 生物群落图数据 Returns: 材质数据字典 """ try: print("✓ 开始生成地形材质...") # 在实际实现中,这里会生成多种材质纹理和属性 materials = { 'diffuse_textures': [], 'normal_textures': [], 'specular_textures': [], 'biome_mapping': {} } # 为每种生物群落生成材质ID unique_biomes = np.unique(biome_map) for biome_id in unique_biomes: materials['biome_mapping'][biome_id] = f"material_{biome_id}" print("✓ 地形材质生成完成") return materials except Exception as e: print(f"✗ 地形材质生成失败: {e}") import traceback traceback.print_exc() return {} def apply_tessellation(self, vertices: np.ndarray, tessellation_factor: float) -> np.ndarray: """ 应用细分曲面 Args: vertices: 顶点数据 tessellation_factor: 细分因子 Returns: 细分后的顶点数据 """ try: # 在实际实现中,这里会使用GPU细分着色器 # 简化实现:返回原始顶点 print(f"✓ 应用细分曲面 (因子: {tessellation_factor})") return vertices except Exception as e: print(f"✗ 细分曲面应用失败: {e}") return vertices def apply_displacement_mapping(self, heightmap: np.ndarray, displacement_factor: float) -> np.ndarray: """ 应用置换贴图 Args: heightmap: 高度图数据 displacement_factor: 置换因子 Returns: 置换后的顶点数据 """ try: # 在实际实现中,这里会在细分着色器中应用置换贴图 # 简化实现:返回处理后的高度图 displaced_heightmap = heightmap * displacement_factor print(f"✓ 应用置换贴图 (因子: {displacement_factor})") return displaced_heightmap except Exception as e: print(f"✗ 置换贴图应用失败: {e}") return heightmap def calculate_shadow_map(self, light_direction: List[float], heightmap: np.ndarray) -> np.ndarray: """ 计算阴影贴图 Args: light_direction: 光照方向 heightmap: 高度图数据 Returns: 阴影贴图数据 """ try: height, width = heightmap.shape print(f"✓ 开始计算 {width}x{height} 阴影贴图...") # 创建阴影贴图数据 shadow_map = np.ones((height, width), dtype=np.float32) # 简化的阴影计算 light_x, light_y, light_z = light_direction # 根据光照方向计算阴影 for y in range(height): for x in range(width): # 简单的高度遮挡计算 current_height = heightmap[y, x] shadow_factor = 1.0 # 检查在光照方向上是否有更高的地形遮挡 step_x = int(light_x * 10) step_y = int(light_y * 10) check_x = x + step_x check_y = y + step_y if 0 <= check_x < width and 0 <= check_y < height: check_height = heightmap[check_y, check_x] if check_height > current_height: shadow_factor = 0.5 # 简单的半阴影 shadow_map[y, x] = shadow_factor print("✓ 阴影贴图计算完成") return shadow_map except Exception as e: print(f"✗ 阴影贴图计算失败: {e}") import traceback traceback.print_exc() # 返回默认阴影贴图(无阴影) height, width = heightmap.shape return np.ones((height, width), dtype=np.float32) def apply_atmospheric_effects(self, color_data: np.ndarray, camera_position: List[float], sun_direction: List[float]) -> np.ndarray: """ 应用大气效果 Args: color_data: 颜色数据 camera_position: 摄像机位置 sun_direction: 太阳方向 Returns: 处理后的颜色数据 """ try: processed_colors = color_data.copy() height, width = processed_colors.shape[:2] print("✓ 应用大气效果...") # 简化的雾效和光照计算 fog_density = 0.01 sun_r, sun_g, sun_b = sun_direction for y in range(height): for x in range(width): # 计算到摄像机的距离(简化) distance = math.sqrt((x - camera_position[0])**2 + (y - camera_position[1])**2) # 应用雾效 fog_factor = math.exp(-distance * fog_density) fog_factor = max(0.0, min(1.0, fog_factor)) # 混合雾颜色(白色) processed_colors[y, x, 0] = int(processed_colors[y, x, 0] * fog_factor + 255 * (1 - fog_factor)) processed_colors[y, x, 1] = int(processed_colors[y, x, 1] * fog_factor + 255 * (1 - fog_factor)) processed_colors[y, x, 2] = int(processed_colors[y, x, 2] * fog_factor + 255 * (1 - fog_factor)) print("✓ 大气效果应用完成") return processed_colors except Exception as e: print(f"✗ 大气效果应用失败: {e}") return color_data def optimize_rendering(self, target_fps: float = 60.0): """ 优化渲染性能 Args: target_fps: 目标帧率 """ try: print(f"✓ 开始优化渲染性能 (目标FPS: {target_fps})") # 根据目标FPS调整渲染参数 current_fps = 1.0 / max(0.001, self.stats['average_render_time']) if current_fps < target_fps * 0.8: # 如果FPS低于目标的80% # 降低渲染质量以提高性能 self.render_params['lod_levels'] = max(1, self.render_params['lod_levels'] - 1) self.render_params['chunk_size'] = min(64, self.render_params['chunk_size'] * 2) print(" → 降低LOD级别和增加区块大小以提高性能") elif current_fps > target_fps * 1.2: # 如果FPS高于目标的120% # 提高渲染质量 self.render_params['lod_levels'] = min(10, self.render_params['lod_levels'] + 1) self.render_params['chunk_size'] = max(8, self.render_params['chunk_size'] // 2) print(" → 提高LOD级别和减小区块大小以提高质量") print("✓ 渲染性能优化完成") except Exception as e: print(f"✗ 渲染性能优化失败: {e}") def export_render_settings(self, filename: str) -> bool: """ 导出渲染设置 Args: filename: 文件名 Returns: 是否导出成功 """ try: import json settings = { 'render_params': self.render_params, 'lighting_params': self.lighting_params, 'material_params': self.material_params, 'shader_params': self.shader_params, 'timestamp': time.time() } with open(filename, 'w', encoding='utf-8') as f: json.dump(settings, f, ensure_ascii=False, indent=2) print(f"✓ 渲染设置已导出到: {filename}") return True except Exception as e: print(f"✗ 渲染设置导出失败: {e}") return False def import_render_settings(self, filename: str) -> bool: """ 导入渲染设置 Args: filename: 文件名 Returns: 是否导入成功 """ try: import json with open(filename, 'r', encoding='utf-8') as f: settings = json.load(f) # 更新参数 if 'render_params' in settings: self.render_params.update(settings['render_params']) if 'lighting_params' in settings: self.lighting_params.update(settings['lighting_params']) if 'material_params' in settings: self.material_params.update(settings['material_params']) if 'shader_params' in settings: self.shader_params.update(settings['shader_params']) print(f"✓ 渲染设置已从 {filename} 导入") return True except Exception as e: print(f"✗ 渲染设置导入失败: {e}") return False def get_render_capabilities(self) -> Dict[str, Any]: """ 获取渲染能力信息 Returns: 渲染能力信息字典 """ return { 'max_texture_size': 8192, 'max_lod_levels': 10, 'supported_shaders': ['vertex', 'fragment', 'geometry', 'tessellation'], 'supports_normal_mapping': True, 'supports_displacement_mapping': True, 'supports_tessellation': True, 'supports_shadow_mapping': True, 'max_anisotropy': 16.0 } def set_render_quality(self, quality_level: str): """ 设置渲染质量级别 Args: quality_level: 质量级别 ('low', 'medium', 'high', 'ultra') """ quality_settings = { 'low': { 'lod_levels': 2, 'chunk_size': 64, 'normal_mapping': False, 'tessellation_factor': 0.5 }, 'medium': { 'lod_levels': 4, 'chunk_size': 32, 'normal_mapping': True, 'tessellation_factor': 1.0 }, 'high': { 'lod_levels': 6, 'chunk_size': 16, 'normal_mapping': True, 'tessellation_factor': 2.0 }, 'ultra': { 'lod_levels': 8, 'chunk_size': 8, 'normal_mapping': True, 'tessellation_factor': 4.0 } } if quality_level in quality_settings: settings = quality_settings[quality_level] self.render_params['lod_levels'] = settings['lod_levels'] self.render_params['chunk_size'] = settings['chunk_size'] self.material_params['normal_mapping'] = settings['normal_mapping'] self.material_params['tessellation_factor'] = settings['tessellation_factor'] print(f"✓ 渲染质量已设置为: {quality_level}") else: print(f"✗ 无效的质量级别: {quality_level}")