""" 地形图层系统 提供完整的地形图层管理功能,支持多层纹理混合、Alpha混合等高级功能 """ from panda3d.core import Texture, TextureStage, PNMImage, Filename import os class TerrainLayerSystem: """ 地形图层系统类 提供完整的地形图层管理功能 """ def __init__(self, world): self.world = world self.terrain_layers = {} # 存储地形图层信息 def create_layered_terrain(self, terrain_node, layer_configs): """ 创建分层地形 layer_configs: 图层配置列表,每个配置包含纹理路径、混合贴图等信息 """ try: # 清除现有的地形纹理 terrain_node.clearTexture() # 为每个图层创建纹理阶段 for i, layer_config in enumerate(layer_configs): # 加载漫反射纹理 if 'diffuse' in layer_config: diffuse_texture = self._load_texture(layer_config['diffuse']) if diffuse_texture: diffuse_stage = TextureStage(f"diffuse_{i}") diffuse_stage.setSort(i * 10) # 设置排序 terrain_node.setTexture(diffuse_stage, diffuse_texture) # 加载法线纹理 if 'normal' in layer_config: normal_texture = self._load_texture(layer_config['normal']) if normal_texture: normal_stage = TextureStage(f"normal_{i}") normal_stage.setMode(TextureStage.M_normal) # 设置为法线贴图模式 normal_stage.setSort(i * 10 + 1) terrain_node.setTexture(normal_stage, normal_texture) # 加载高光纹理 if 'specular' in layer_config: specular_texture = self._load_texture(layer_config['specular']) if specular_texture: specular_stage = TextureStage(f"specular_{i}") specular_stage.setMode(TextureStage.M_specular) # 设置为高光贴图模式 specular_stage.setSort(i * 10 + 2) terrain_node.setTexture(specular_stage, specular_texture) # 加载混合纹理(控制图层混合) if 'blend' in layer_config: blend_texture = self._load_texture(layer_config['blend']) if blend_texture: blend_stage = TextureStage(f"blend_{i}") blend_stage.setMode(TextureStage.M_blend) # 设置为混合模式 blend_stage.setSort(i * 10 + 3) terrain_node.setTexture(blend_stage, blend_texture) # 加载Alpha纹理(控制透明度) if 'alpha' in layer_config: alpha_texture = self._load_texture(layer_config['alpha']) if alpha_texture: alpha_stage = TextureStage(f"alpha_{i}") alpha_stage.setMode(TextureStage.M_modulate) # 设置为调制模式 alpha_stage.setSort(i * 10 + 4) terrain_node.setTexture(alpha_stage, alpha_texture) # 保存图层信息 self.terrain_layers[terrain_node] = layer_configs print(f"为地形创建 {len(layer_configs)} 个图层系统") return True except Exception as e: print(f"创建分层地形时出错: {e}") return False def add_layer(self, terrain_node, layer_config, layer_index=None): """ 为地形添加新图层 """ try: if terrain_node not in self.terrain_layers: # 如果地形还没有图层系统,创建一个新的 self.terrain_layers[terrain_node] = [] layers = self.terrain_layers[terrain_node] # 确定插入位置 if layer_index is None: layer_index = len(layers) # 插入新图层 layers.insert(layer_index, layer_config) # 重新应用所有图层 return self.create_layered_terrain(terrain_node, layers) except Exception as e: print(f"添加图层时出错: {e}") return False def remove_layer(self, terrain_node, layer_index): """ 移除地形的指定图层 """ try: if terrain_node not in self.terrain_layers: print("地形没有图层系统") return False layers = self.terrain_layers[terrain_node] if layer_index < 0 or layer_index >= len(layers): print("图层索引超出范围") return False # 移除图层 layers.pop(layer_index) # 重新应用所有图层 return self.create_layered_terrain(terrain_node, layers) except Exception as e: print(f"移除图层时出错: {e}") return False def update_layer(self, terrain_node, layer_index, layer_config): """ 更新地形图层 """ try: if terrain_node not in self.terrain_layers: print("地形没有图层系统") return False layers = self.terrain_layers[terrain_node] if layer_index < 0 or layer_index >= len(layers): print("图层索引超出范围") return False # 更新图层配置 layers[layer_index] = layer_config # 重新应用所有图层 return self.create_layered_terrain(terrain_node, layers) except Exception as e: print(f"更新图层时出错: {e}") return False def get_layer_info(self, terrain_node, layer_index): """ 获取图层信息 """ try: if terrain_node not in self.terrain_layers: print("地形没有图层系统") return None layers = self.terrain_layers[terrain_node] if layer_index < 0 or layer_index >= len(layers): print("图层索引超出范围") return None return layers[layer_index] except Exception as e: print(f"获取图层信息时出错: {e}") return None def blend_layers(self, terrain_node, blend_map_path): """ 使用混合图混合所有图层 """ try: if terrain_node not in self.terrain_layers: print("地形没有图层系统") return False # 加载混合图 blend_texture = self._load_texture(blend_map_path) if not blend_texture: print("无法加载混合图") return False # 应用混合图到所有图层 blend_stage = TextureStage("global_blend") blend_stage.setMode(TextureStage.M_blend) blend_stage.setSort(1000) # 确保在最后应用 terrain_node.setTexture(blend_stage, blend_texture) print(f"应用全局混合图: {blend_map_path}") return True except Exception as e: print(f"混合图层时出错: {e}") return False def generate_blend_map(self, terrain_info, layer_weights, output_path): """ 生成图层混合图 layer_weights: 每个图层的权重列表 """ try: heightfield = terrain_info['heightfield'] if not heightfield: print("无法获取地形高度图数据") return False width = heightfield.getXSize() height = heightfield.getYSize() # 创建混合图 blend_image = PNMImage(width, height, 4) # RGBA格式 # 根据高度和权重生成混合图 for y in range(height): for x in range(width): height_value = heightfield.getRed(x, y) # 根据高度值分配权重 weights = self._calculate_layer_weights(height_value, layer_weights) # 设置RGBA值 blend_image.setRed(x, y, weights[0] if len(weights) > 0 else 0) blend_image.setGreen(x, y, weights[1] if len(weights) > 1 else 0) blend_image.setBlue(x, y, weights[2] if len(weights) > 2 else 0) blend_image.setAlpha(x, y, weights[3] if len(weights) > 3 else 0) # 保存混合图 output_dir = os.path.dirname(output_path) if not os.path.exists(output_dir): os.makedirs(output_dir) success = blend_image.write(Filename.fromOsSpecific(output_path)) if success: print(f"混合图生成成功: {output_path}") return True else: print(f"混合图生成失败: {output_path}") return False except Exception as e: print(f"生成混合图时出错: {e}") return False def _calculate_layer_weights(self, height_value, layer_weights): """ 根据高度值计算图层权重 """ # 简单的高度分区方法 weights = [0.0] * len(layer_weights) if height_value < 0.3: # 低地 weights[0] = 1.0 elif height_value < 0.6: # 中等地 weights[1] = 1.0 elif height_value < 0.8: # 高地 weights[2] = 1.0 else: # 山峰 weights[3] = 1.0 if len(weights) > 3 else 0 return weights def _load_texture(self, texture_path): """ 加载纹理 """ try: if not os.path.exists(texture_path): print(f"纹理文件不存在: {texture_path}") return None texture = self.world.loader.loadTexture(texture_path) if texture: print(f"纹理加载成功: {texture_path}") return texture else: print(f"纹理加载失败: {texture_path}") return None except Exception as e: print(f"加载纹理时出错: {e}") return None def create_texture_array(self, texture_paths, array_name): """ 创建纹理数组 """ try: # 加载所有纹理 textures = [] for path in texture_paths: texture = self._load_texture(path) if texture: textures.append(texture) if not textures: print("没有成功加载任何纹理") return None # 创建纹理数组 # 注意:Panda3D的纹理数组创建比较复杂,这里只是一个概念实现 print(f"创建纹理数组: {array_name},包含 {len(textures)} 个纹理") return textures # 临时返回纹理列表 except Exception as e: print(f"创建纹理数组时出错: {e}") return None def apply_texture_array(self, terrain_node, texture_array, array_name): """ 应用纹理数组到地形 """ try: if not texture_array: print("纹理数组为空") return False # 为每个纹理创建纹理阶段 for i, texture in enumerate(texture_array): texture_stage = TextureStage(f"{array_name}_{i}") texture_stage.setSort(i) terrain_node.setTexture(texture_stage, texture) print(f"应用纹理数组: {array_name}") return True except Exception as e: print(f"应用纹理数组时出错: {e}") return False def save_layer_config(self, terrain_node, config_path): """ 保存图层配置到文件 """ try: if terrain_node not in self.terrain_layers: print("地形没有图层系统") return False import json # 保存图层配置 layers = self.terrain_layers[terrain_node] # 确保输出目录存在 output_dir = os.path.dirname(config_path) if not os.path.exists(output_dir): os.makedirs(output_dir) with open(config_path, 'w', encoding='utf-8') as f: json.dump(layers, f, indent=2, ensure_ascii=False) print(f"图层配置保存成功: {config_path}") return True except Exception as e: print(f"保存图层配置时出错: {e}") return False def load_layer_config(self, terrain_node, config_path): """ 从文件加载图层配置 """ try: if not os.path.exists(config_path): print(f"图层配置文件不存在: {config_path}") return False import json # 加载图层配置 with open(config_path, 'r', encoding='utf-8') as f: layers = json.load(f) # 应用图层配置 self.terrain_layers[terrain_node] = layers return self.create_layered_terrain(terrain_node, layers) except Exception as e: print(f"加载图层配置时出错: {e}") return False