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

1558 lines
62 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.

"""
地形天气和环境系统
提供完整的天气模拟、环境效果、光照控制、动态天空等功能
"""
from panda3d.core import NodePath, Vec3, Point3, Vec4, LVector3f
from panda3d.core import AmbientLight, DirectionalLight, PointLight, Spotlight
from panda3d.core import Fog, Shader, ShaderAttrib, PerspectiveLens
from panda3d.core import Texture, TextureStage, CardMaker
from panda3d.core import PNMImage, Filename, ClockObject
from panda3d.core import deg2Rad, rad2Deg
import math
import random
import json
import os
from collections import deque
class EnvironmentSystem:
"""
地形天气和环境系统类
提供完整的天气模拟、环境效果、光照控制、动态天空等功能
"""
def __init__(self, world):
self.world = world
self.weather_conditions = {} # 存储天气条件
self.environment_effects = {} # 存储环境效果
self.lighting_system = {} # 存储光照系统
self.particle_systems = [] # 存储粒子系统
self.weather_enabled = True
self.current_weather = 'sunny'
self.time_of_day = 12.0 # 24小时制
self.current_season = 'summer'
self.weather_transition = None # 天气过渡状态
self.sky_dome = None # 天空穹顶
self.cloud_layer = None # 云层
self.wind_vector = Vec3(1, 0, 0) # 风向量
self.wind_strength = 0.1 # 风力强度
# 性能监控
self.performance_stats = {
'last_update_time': 0.0,
'update_count': 0,
'avg_update_time': 0.0
}
# 初始化环境系统
self._init_environment_system()
def _init_environment_system(self):
"""
初始化环境系统
"""
try:
# 定义默认天气条件
self._define_default_weather()
# 初始化光照系统
self._init_lighting_system()
# 初始化环境效果
self._init_environment_effects()
# 创建动态天空
self.create_dynamic_sky('dome')
print("环境系统初始化完成")
except Exception as e:
print(f"初始化环境系统时出错: {e}")
def _define_default_weather(self):
"""
定义默认天气条件(增强版)
"""
self.weather_conditions = {
'sunny': {
'name': '晴天',
'ambient_light': (0.3, 0.3, 0.3, 1.0),
'directional_light': (0.8, 0.8, 0.8, 1.0),
'light_color_temp': 5500, # 色温(K)
'fog_color': (0.5, 0.5, 0.5, 1.0),
'fog_density': 0.0,
'particle_effects': [],
'wind_strength': 0.1,
'temperature': 25.0,
'humidity': 30.0,
'visibility': 20000.0, # 能见度(米)
'cloud_coverage': 0.1, # 云覆盖率
'precipitation': 0.0, # 降水量
'sky_tint': (1.0, 1.0, 1.0, 1.0), # 天空着色
'sun_intensity': 1.0,
'moon_intensity': 0.0
},
'cloudy': {
'name': '多云',
'ambient_light': (0.2, 0.2, 0.2, 1.0),
'directional_light': (0.5, 0.5, 0.5, 1.0),
'light_color_temp': 4500,
'fog_color': (0.7, 0.7, 0.7, 1.0),
'fog_density': 0.001,
'particle_effects': ['clouds'],
'wind_strength': 0.3,
'temperature': 20.0,
'humidity': 60.0,
'visibility': 5000.0,
'cloud_coverage': 0.7,
'precipitation': 0.0,
'sky_tint': (0.8, 0.8, 0.8, 1.0),
'sun_intensity': 0.6,
'moon_intensity': 0.1
},
'rainy': {
'name': '雨天',
'ambient_light': (0.1, 0.1, 0.1, 1.0),
'directional_light': (0.3, 0.3, 0.3, 1.0),
'light_color_temp': 6500,
'fog_color': (0.8, 0.8, 0.8, 1.0),
'fog_density': 0.002,
'particle_effects': ['rain', 'clouds'],
'wind_strength': 0.5,
'temperature': 15.0,
'humidity': 90.0,
'visibility': 1000.0,
'cloud_coverage': 0.9,
'precipitation': 5.0,
'sky_tint': (0.7, 0.7, 0.7, 1.0),
'sun_intensity': 0.3,
'moon_intensity': 0.2
},
'stormy': {
'name': '暴风雨',
'ambient_light': (0.05, 0.05, 0.05, 1.0),
'directional_light': (0.2, 0.2, 0.2, 1.0),
'light_color_temp': 7000,
'fog_color': (0.9, 0.9, 0.9, 1.0),
'fog_density': 0.003,
'particle_effects': ['rain', 'lightning', 'clouds'],
'wind_strength': 1.0,
'temperature': 10.0,
'humidity': 95.0,
'visibility': 500.0,
'cloud_coverage': 1.0,
'precipitation': 20.0,
'sky_tint': (0.5, 0.5, 0.5, 1.0),
'sun_intensity': 0.1,
'moon_intensity': 0.3
},
'snowy': {
'name': '雪天',
'ambient_light': (0.2, 0.2, 0.2, 1.0),
'directional_light': (0.4, 0.4, 0.4, 1.0),
'light_color_temp': 5000,
'fog_color': (0.9, 0.9, 0.9, 1.0),
'fog_density': 0.001,
'particle_effects': ['snow', 'clouds'],
'wind_strength': 0.4,
'temperature': -5.0,
'humidity': 80.0,
'visibility': 2000.0,
'cloud_coverage': 0.8,
'precipitation': 3.0,
'sky_tint': (0.9, 0.9, 1.0, 1.0),
'sun_intensity': 0.4,
'moon_intensity': 0.4
},
'foggy': {
'name': '雾天',
'ambient_light': (0.15, 0.15, 0.15, 1.0),
'directional_light': (0.2, 0.2, 0.2, 1.0),
'light_color_temp': 3000,
'fog_color': (0.95, 0.95, 0.95, 1.0),
'fog_density': 0.005,
'particle_effects': ['mist'],
'wind_strength': 0.2,
'temperature': 12.0,
'humidity': 98.0,
'visibility': 200.0,
'cloud_coverage': 0.3,
'precipitation': 0.1,
'sky_tint': (0.9, 0.9, 0.9, 1.0),
'sun_intensity': 0.2,
'moon_intensity': 0.1
}
}
def _init_lighting_system(self):
"""
初始化光照系统(增强版)
"""
try:
# 创建环境光
ambient_light = AmbientLight('ambient_light')
ambient_light.setColor(Vec4(0.3, 0.3, 0.3, 1.0))
self.ambient_light_np = self.world.render.attachNewNode(ambient_light)
self.world.render.setLight(self.ambient_light_np)
# 创建方向光(太阳光)
directional_light = DirectionalLight('directional_light')
directional_light.setColor(Vec4(0.8, 0.8, 0.8, 1.0))
directional_light.setShadowCaster(True, 2048, 2048)
directional_light.setCameraMask(0x00000001) # 设置相机掩码
self.directional_light_np = self.world.render.attachNewNode(directional_light)
self.directional_light_np.setHpr(45, -45, 0)
self.world.render.setLight(self.directional_light_np)
# 创建月光
moon_light = DirectionalLight('moon_light')
moon_light.setColor(Vec4(0.1, 0.1, 0.2, 1.0))
self.moon_light_np = self.world.render.attachNewNode(moon_light)
self.moon_light_np.setHpr(225, -30, 0)
# 初始时禁用月光
self.world.render.clearLight(self.moon_light_np)
# 保存光照节点
self.lighting_system = {
'ambient': {
'node': ambient_light,
'nodepath': self.ambient_light_np
},
'directional': {
'node': directional_light,
'nodepath': self.directional_light_np
},
'moon': {
'node': moon_light,
'nodepath': self.moon_light_np,
'enabled': False
}
}
except Exception as e:
print(f"初始化光照系统时出错: {e}")
def _init_environment_effects(self):
"""
初始化环境效果(增强版)
"""
try:
# 初始化雾效
self.fog = Fog('environment_fog')
self.fog.setColor(0.5, 0.5, 0.5, 1.0)
self.fog.setExpDensity(0.0)
self.world.render.setFog(self.fog)
# 初始化风效
self.wind_vector = Vec3(1, 0, 0)
self.wind_strength = 0.1
# 初始化粒子系统容器
self.particle_containers = {
'rain': [],
'snow': [],
'clouds': [],
'lightning': [],
'mist': []
}
except Exception as e:
print(f"初始化环境效果时出错: {e}")
def set_weather(self, weather_type, transition_time=5.0):
"""
设置天气(增强版)
"""
try:
if weather_type not in self.weather_conditions:
print(f"未知的天气类型: {weather_type}")
return False
# 如果已经有过渡效果,取消它
if self.weather_transition:
self.weather_transition = None
# 如果需要平滑过渡
if transition_time > 0 and self.current_weather != weather_type:
self.weather_transition = {
'from': self.current_weather,
'to': weather_type,
'start_time': self.world.globalClock.getFrameTime(),
'duration': transition_time,
'progress': 0.0
}
print(f"开始天气过渡: {self.current_weather} -> {weather_type}")
else:
# 直接切换天气
self._apply_weather_immediately(weather_type)
return True
except Exception as e:
print(f"设置天气时出错: {e}")
return False
def _apply_weather_immediately(self, weather_type):
"""
立即应用天气
"""
try:
weather = self.weather_conditions[weather_type]
self.current_weather = weather_type
# 更新环境光
if 'ambient' in self.lighting_system:
light_node = self.lighting_system['ambient']['node']
light_node.setColor(Vec4(*weather['ambient_light']))
# 更新方向光
if 'directional' in self.lighting_system:
light_node = self.lighting_system['directional']['node']
light_node.setColor(Vec4(*weather['directional_light']))
# 更新雾效
fog_color = weather['fog_color']
self.fog.setColor(fog_color[0], fog_color[1], fog_color[2], fog_color[3])
self.fog.setExpDensity(weather['fog_density'])
# 更新风效
self.wind_strength = weather['wind_strength']
# 更新粒子效果
self._update_particle_effects(weather['particle_effects'])
# 应用天气着色器
self._apply_weather_shader(weather_type)
# 更新天空
self._update_sky_for_weather(weather_type)
print(f"设置天气为: {weather['name']}")
except Exception as e:
print(f"立即应用天气时出错: {e}")
def _update_particle_effects(self, effects_list):
"""
更新粒子效果(增强版)
"""
try:
# 清除现有粒子效果
self._clear_particle_effects()
# 创建新的粒子效果
for effect in effects_list:
if effect == 'rain':
self._create_rain_effect()
elif effect == 'snow':
self._create_snow_effect()
elif effect == 'clouds':
self._create_cloud_effect()
elif effect == 'lightning':
self._create_lightning_effect()
elif effect == 'mist':
self._create_mist_effect()
except Exception as e:
print(f"更新粒子效果时出错: {e}")
def _clear_particle_effects(self):
"""
清除粒子效果(增强版)
"""
try:
# 移除所有粒子系统节点
for effect_type, particles in self.particle_containers.items():
for particle in particles:
if particle['node'] and not particle['node'].isEmpty():
particle['node'].removeNode()
self.particle_containers[effect_type] = []
# 清空旧的粒子系统列表
self.particle_systems = []
except Exception as e:
print(f"清除粒子效果时出错: {e}")
def _create_rain_effect(self):
"""
创建雨天效果(增强版)
"""
try:
# 创建雨滴粒子系统
rain_particles = []
# 创建多个雨滴发射器以提高性能
for i in range(5):
# 创建雨滴节点
cm = CardMaker(f'rain_drop_{i}')
cm.setFrame(-0.01, 0.01, -0.1, 0.1)
rain_node = self.world.render.attachNewNode(cm.generate())
rain_node.setBin("fixed", 40) # 确保在最上层
rain_node.setDepthWrite(False)
rain_node.setDepthTest(False)
# 设置雨滴纹理(简化版本)
# 实际项目中应该加载真实的雨滴纹理
rain_node.setColor(0.5, 0.5, 1.0, 0.7)
# 创建粒子信息
particle_info = {
'type': 'rain',
'node': rain_node,
'position': Vec3(random.uniform(-50, 50), random.uniform(-50, 50), 20),
'velocity': Vec3(random.uniform(-1, 1), random.uniform(-1, 1), -20.0),
'lifetime': random.uniform(1.0, 3.0),
'age': 0.0,
'emitter_id': i
}
rain_node.setPos(particle_info['position'])
rain_particles.append(particle_info)
self.particle_containers['rain'].extend(rain_particles)
self.particle_systems.extend(rain_particles)
print("创建雨天效果")
return rain_particles
except Exception as e:
print(f"创建雨天效果时出错: {e}")
return []
def _create_snow_effect(self):
"""
创建雪天效果(增强版)
"""
try:
# 创建雪花粒子系统
snow_particles = []
# 创建多个雪花发射器
for i in range(8):
# 创建雪花节点
cm = CardMaker(f'snow_flake_{i}')
size = random.uniform(0.05, 0.15)
cm.setFrame(-size, size, -size, size)
snow_node = self.world.render.attachNewNode(cm.generate())
snow_node.setBin("fixed", 35)
snow_node.setDepthWrite(False)
snow_node.setDepthTest(False)
# 设置雪花颜色
snow_node.setColor(1.0, 1.0, 1.0, 0.8)
# 创建粒子信息
particle_info = {
'type': 'snow',
'node': snow_node,
'position': Vec3(random.uniform(-100, 100), random.uniform(-100, 100), 30),
'velocity': Vec3(random.uniform(-2, 2), random.uniform(-2, 2), random.uniform(-5, -2)),
'lifetime': random.uniform(5.0, 10.0),
'age': 0.0,
'rotation_speed': random.uniform(-10, 10),
'emitter_id': i
}
snow_node.setPos(particle_info['position'])
snow_particles.append(particle_info)
self.particle_containers['snow'].extend(snow_particles)
self.particle_systems.extend(snow_particles)
print("创建雪天效果")
return snow_particles
except Exception as e:
print(f"创建雪天效果时出错: {e}")
return []
def _create_cloud_effect(self):
"""
创建云效果(增强版)
"""
try:
# 创建云朵粒子系统
cloud_particles = []
# 创建多个云朵
for i in range(10):
# 创建云朵节点
cm = CardMaker(f'cloud_{i}')
size = random.uniform(10, 30)
cm.setFrame(-size, size, -size/2, size/2)
cloud_node = self.world.render.attachNewNode(cm.generate())
cloud_node.setBin("fixed", 30)
cloud_node.setDepthWrite(False)
cloud_node.setDepthTest(False)
# 设置云朵颜色和透明度
cloud_node.setColor(1.0, 1.0, 1.0, random.uniform(0.3, 0.7))
# 创建粒子信息
particle_info = {
'type': 'clouds',
'node': cloud_node,
'position': Vec3(random.uniform(-200, 200), random.uniform(-200, 200), random.uniform(50, 80)),
'velocity': Vec3(random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5), 0),
'lifetime': float('inf'), # 永久存在
'age': 0.0,
'scale': size,
'emitter_id': i
}
cloud_node.setPos(particle_info['position'])
cloud_particles.append(particle_info)
self.particle_containers['clouds'].extend(cloud_particles)
self.particle_systems.extend(cloud_particles)
print("创建云效果")
return cloud_particles
except Exception as e:
print(f"创建云效果时出错: {e}")
return []
def _create_lightning_effect(self):
"""
创建闪电效果(增强版)
"""
try:
# 创建闪电效果
lightning_effects = []
# 创建闪电节点
cm = CardMaker('lightning')
cm.setFrame(-100, 100, -100, 100)
lightning_node = self.world.render.attachNewNode(cm.generate())
lightning_node.setBin("fixed", 50)
lightning_node.setDepthWrite(False)
lightning_node.setDepthTest(False)
# 设置初始不可见
lightning_node.hide()
# 创建闪电信息
lightning_info = {
'type': 'lightning',
'node': lightning_node,
'position': Vec3(0, 0, 100),
'lifetime': 0.1, # 闪电持续时间很短
'age': 0.0,
'next_strike_time': random.uniform(5, 15), # 下次闪电时间
'intensity': 2.0
}
lightning_node.setPos(lightning_info['position'])
lightning_effects.append(lightning_info)
self.particle_containers['lightning'].extend(lightning_effects)
self.particle_systems.extend(lightning_effects)
print("创建闪电效果")
return lightning_effects
except Exception as e:
print(f"创建闪电效果时出错: {e}")
return []
def _create_mist_effect(self):
"""
创建雾气效果(增强版)
"""
try:
# 创建雾气粒子系统
mist_particles = []
# 创建多个雾气发射器
for i in range(3):
# 创建雾气节点
cm = CardMaker(f'mist_{i}')
size = random.uniform(20, 50)
cm.setFrame(-size, size, -size/2, size/2)
mist_node = self.world.render.attachNewNode(cm.generate())
mist_node.setBin("fixed", 25)
mist_node.setDepthWrite(False)
mist_node.setDepthTest(False)
# 设置雾气颜色
mist_node.setColor(0.9, 0.9, 0.9, random.uniform(0.2, 0.4))
# 创建粒子信息
particle_info = {
'type': 'mist',
'node': mist_node,
'position': Vec3(random.uniform(-100, 100), random.uniform(-100, 100), random.uniform(0, 5)),
'velocity': Vec3(random.uniform(-0.2, 0.2), random.uniform(-0.2, 0.2), 0),
'lifetime': float('inf'),
'age': 0.0,
'scale': size,
'emitter_id': i
}
mist_node.setPos(particle_info['position'])
mist_particles.append(particle_info)
self.particle_containers['mist'].extend(mist_particles)
self.particle_systems.extend(mist_particles)
print("创建雾气效果")
return mist_particles
except Exception as e:
print(f"创建雾气效果时出错: {e}")
return []
def _apply_weather_shader(self, weather_type):
"""
应用天气着色器(增强版)
"""
try:
# 如果使用RenderPipeline应用天气效果
if hasattr(self.world, 'render_pipeline'):
try:
# 根据天气类型选择着色器
if weather_type == 'rainy':
effect_file = "effects/rain_weather.yaml"
elif weather_type == 'stormy':
effect_file = "effects/storm_weather.yaml"
elif weather_type == 'snowy':
effect_file = "effects/snow_weather.yaml"
elif weather_type == 'foggy':
effect_file = "effects/fog_weather.yaml"
else:
effect_file = "effects/default_weather.yaml"
self.world.render_pipeline.set_effect(
self.world.render,
effect_file,
{
"weather_type": weather_type,
"wind_strength": self.wind_strength,
"fog_density": self.weather_conditions[weather_type]['fog_density'],
"time_of_day": self.time_of_day
},
5 # 排序值
)
except Exception as e:
print(f"应用天气着色器失败: {e}")
except Exception as e:
print(f"应用天气着色器时出错: {e}")
def update_environment(self, time_delta):
"""
更新环境系统(增强版)
"""
try:
if not self.weather_enabled:
return
# 性能监控开始
start_time = self.world.globalClock.getRealTime()
# 更新天气过渡
self._update_weather_transition(time_delta)
# 更新粒子效果
self._update_particles(time_delta)
# 更新风效
self._update_wind(time_delta)
# 更新光照
self._update_lighting(time_delta)
# 更新天空
self._update_sky(time_delta)
# 更新性能统计
end_time = self.world.globalClock.getRealTime()
update_time = end_time - start_time
self.performance_stats['last_update_time'] = update_time
self.performance_stats['update_count'] += 1
# 计算平均更新时间
if self.performance_stats['update_count'] > 1:
alpha = 0.1
self.performance_stats['avg_update_time'] = (
alpha * update_time +
(1 - alpha) * self.performance_stats['avg_update_time']
)
else:
self.performance_stats['avg_update_time'] = update_time
except Exception as e:
print(f"更新环境系统时出错: {e}")
def _update_weather_transition(self, time_delta):
"""
更新天气过渡效果
"""
try:
if not self.weather_transition:
return
# 更新过渡进度
current_time = self.world.globalClock.getFrameTime()
elapsed = current_time - self.weather_transition['start_time']
progress = min(1.0, elapsed / self.weather_transition['duration'])
self.weather_transition['progress'] = progress
# 获取起始和目标天气
from_weather = self.weather_conditions[self.weather_transition['from']]
to_weather = self.weather_conditions[self.weather_transition['to']]
# 插值计算当前天气参数
if progress >= 1.0:
# 过渡完成,应用最终天气
self._apply_weather_immediately(self.weather_transition['to'])
self.weather_transition = None
else:
# 过渡中,插值计算参数
self._interpolate_weather_parameters(from_weather, to_weather, progress)
except Exception as e:
print(f"更新天气过渡时出错: {e}")
def _interpolate_weather_parameters(self, from_weather, to_weather, progress):
"""
插值计算天气参数
"""
try:
# 线性插值函数
def lerp(a, b, t):
if isinstance(a, (list, tuple)) and len(a) == len(b):
return [a[i] + (b[i] - a[i]) * t for i in range(len(a))]
return a + (b - a) * t
# 插值环境光
if 'ambient' in self.lighting_system:
ambient_from = from_weather['ambient_light']
ambient_to = to_weather['ambient_light']
ambient_current = lerp(ambient_from, ambient_to, progress)
light_node = self.lighting_system['ambient']['node']
light_node.setColor(Vec4(*ambient_current))
# 插值方向光
if 'directional' in self.lighting_system:
directional_from = from_weather['directional_light']
directional_to = to_weather['directional_light']
directional_current = lerp(directional_from, directional_to, progress)
light_node = self.lighting_system['directional']['node']
light_node.setColor(Vec4(*directional_current))
# 插值雾效
fog_from = from_weather['fog_color']
fog_to = to_weather['fog_color']
fog_color_current = lerp(fog_from, fog_to, progress)
self.fog.setColor(fog_color_current[0], fog_color_current[1], fog_color_current[2], fog_color_current[3])
fog_density_from = from_weather['fog_density']
fog_density_to = to_weather['fog_density']
fog_density_current = lerp(fog_density_from, fog_density_to, progress)
self.fog.setExpDensity(fog_density_current)
# 插值风力
wind_from = from_weather['wind_strength']
wind_to = to_weather['wind_strength']
self.wind_strength = lerp(wind_from, wind_to, progress)
except Exception as e:
print(f"插值天气参数时出错: {e}")
def _update_particles(self, time_delta):
"""
更新粒子效果(增强版)
"""
try:
current_time = self.world.globalClock.getFrameTime()
# 更新所有粒子系统
for particle in self.particle_systems[:]: # 使用切片复制
# 更新粒子年龄
particle['age'] += time_delta
# 检查生命周期
if particle['lifetime'] != float('inf') and particle['age'] > particle['lifetime']:
# 移除过期粒子
if particle['node'] and not particle['node'].isEmpty():
particle['node'].removeNode()
if particle in self.particle_systems:
self.particle_systems.remove(particle)
continue
# 根据粒子类型更新
if particle['type'] == 'rain':
self._update_rain_particle(particle, time_delta, current_time)
elif particle['type'] == 'snow':
self._update_snow_particle(particle, time_delta, current_time)
elif particle['type'] == 'clouds':
self._update_cloud_particle(particle, time_delta, current_time)
elif particle['type'] == 'lightning':
self._update_lightning_particle(particle, time_delta, current_time)
elif particle['type'] == 'mist':
self._update_mist_particle(particle, time_delta, current_time)
except Exception as e:
print(f"更新粒子效果时出错: {e}")
def _update_rain_particle(self, particle, time_delta, current_time):
"""
更新雨滴粒子
"""
try:
# 更新位置
particle['position'] += particle['velocity'] * time_delta
particle['node'].setPos(particle['position'])
# 如果雨滴落到地面以下,重置位置
if particle['position'].getZ() < 0:
particle['position'].setZ(20) # 重置到高处
particle['position'].setX(random.uniform(-50, 50))
particle['position'].setY(random.uniform(-50, 50))
particle['node'].setPos(particle['position'])
except Exception as e:
print(f"更新雨滴粒子时出错: {e}")
def _update_snow_particle(self, particle, time_delta, current_time):
"""
更新雪花粒子
"""
try:
# 更新位置
particle['position'] += particle['velocity'] * time_delta
particle['node'].setPos(particle['position'])
# 添加摆动效果
sway = math.sin(current_time * 2 + particle['emitter_id']) * 0.5
particle['position'].setX(particle['position'].getX() + sway * time_delta)
particle['node'].setPos(particle['position'])
# 更新旋转
particle['node'].setHpr(particle['node'].getHpr() + Vec3(0, 0, particle['rotation_speed'] * time_delta))
# 如果雪花落到地面以下,重置位置
if particle['position'].getZ() < 0:
particle['position'].setZ(30) # 重置到高处
particle['position'].setX(random.uniform(-100, 100))
particle['position'].setY(random.uniform(-100, 100))
particle['node'].setPos(particle['position'])
except Exception as e:
print(f"更新雪花粒子时出错: {e}")
def _update_cloud_particle(self, particle, time_delta, current_time):
"""
更新云朵粒子
"""
try:
# 更新位置
particle['position'] += particle['velocity'] * time_delta
particle['node'].setPos(particle['position'])
# 添加缓慢变化效果
if random.random() < 0.01: # 1%概率改变速度
particle['velocity'] = Vec3(
random.uniform(-0.5, 0.5),
random.uniform(-0.5, 0.5),
0
)
# 如果云朵移出范围,重置位置
if (abs(particle['position'].getX()) > 300 or
abs(particle['position'].getY()) > 300):
particle['position'].setX(random.uniform(-200, 200))
particle['position'].setY(random.uniform(-200, 200))
particle['node'].setPos(particle['position'])
except Exception as e:
print(f"更新云朵粒子时出错: {e}")
def _update_lightning_particle(self, particle, time_delta, current_time):
"""
更新闪电粒子
"""
try:
# 更新计时器
particle['next_strike_time'] -= time_delta
# 检查是否触发闪电
if particle['next_strike_time'] <= 0:
# 显示闪电
particle['node'].show()
particle['age'] = 0 # 重置年龄
# 随机改变闪电位置
particle['position'] = Vec3(
random.uniform(-100, 100),
random.uniform(-100, 100),
100
)
particle['node'].setPos(particle['position'])
# 设置下次闪电时间
particle['next_strike_time'] = random.uniform(5, 15)
# 增强环境光模拟闪电光照
if 'ambient' in self.lighting_system:
light_node = self.lighting_system['ambient']['node']
light_node.setColor(Vec4(0.8, 0.8, 0.8, 1.0))
else:
# 检查是否需要隐藏闪电
if particle['age'] > particle['lifetime']:
particle['node'].hide()
# 恢复正常环境光
current_weather = self.weather_conditions[self.current_weather]
if 'ambient' in self.lighting_system:
light_node = self.lighting_system['ambient']['node']
light_node.setColor(Vec4(*current_weather['ambient_light']))
except Exception as e:
print(f"更新闪电粒子时出错: {e}")
def _update_mist_particle(self, particle, time_delta, current_time):
"""
更新雾气粒子
"""
try:
# 更新位置
particle['position'] += particle['velocity'] * time_delta
particle['node'].setPos(particle['position'])
# 缓慢改变透明度
alpha = particle['node'].getColor().getW()
alpha += random.uniform(-0.01, 0.01)
alpha = max(0.1, min(0.5, alpha)) # 限制在合理范围内
particle['node'].setColor(
particle['node'].getColor().getX(),
particle['node'].getColor().getY(),
particle['node'].getColor().getZ(),
alpha
)
# 如果雾气移出范围,重置位置
if (abs(particle['position'].getX()) > 200 or
abs(particle['position'].getY()) > 200):
particle['position'].setX(random.uniform(-100, 100))
particle['position'].setY(random.uniform(-100, 100))
particle['node'].setPos(particle['position'])
except Exception as e:
print(f"更新雾气粒子时出错: {e}")
def _update_wind(self, time_delta):
"""
更新风效(增强版)
"""
try:
# 可以实现风向和风力的变化
# 例如随机改变风向或模拟阵风
current_weather = self.weather_conditions[self.current_weather]
# 模拟阵风效果
gust_factor = 1.0 + math.sin(self.world.globalClock.getFrameTime() * 0.5) * 0.3
self.wind_vector = Vec3(
math.cos(self.world.globalClock.getFrameTime() * 0.1) * gust_factor,
math.sin(self.world.globalClock.getFrameTime() * 0.1) * gust_factor,
0
) * current_weather['wind_strength']
except Exception as e:
print(f"更新风效时出错: {e}")
def _update_lighting(self, time_delta):
"""
更新光照(增强版)
"""
try:
# 更新时间
self.time_of_day += time_delta / 3600.0 # 假设1秒对应1小时
if self.time_of_day >= 24.0:
self.time_of_day -= 24.0
# 根据时间调整太阳和月亮位置
self._update_celestial_positions()
# 根据时间调整光照颜色
self._update_lighting_colors()
except Exception as e:
print(f"更新光照时出错: {e}")
def _update_celestial_positions(self):
"""
更新天体位置
"""
try:
# 计算太阳位置(简化模型)
sun_angle = self.time_of_day / 24.0 * 360.0
sun_elevation = math.sin(deg2Rad(sun_angle)) * 60.0 # 最大仰角60度
if hasattr(self, 'directional_light_np'):
self.directional_light_np.setHpr(sun_angle, -sun_elevation, 0)
# 计算月亮位置与太阳相差180度
moon_angle = (sun_angle + 180.0) % 360.0
moon_elevation = math.sin(deg2Rad(moon_angle)) * 50.0
if hasattr(self, 'moon_light_np'):
self.moon_light_np.setHpr(moon_angle, -moon_elevation, 0)
# 根据太阳高度控制月亮显示
if sun_elevation < -10.0: # 太阳在地平线以下10度时显示月亮
if not self.lighting_system['moon']['enabled']:
self.world.render.setLight(self.moon_light_np)
self.lighting_system['moon']['enabled'] = True
else:
if self.lighting_system['moon']['enabled']:
self.world.render.clearLight(self.moon_light_np)
self.lighting_system['moon']['enabled'] = False
except Exception as e:
print(f"更新天体位置时出错: {e}")
def _update_lighting_colors(self):
"""
更新光照颜色
"""
try:
# 根据太阳高度调整光照颜色
sun_elevation = math.sin(deg2Rad(self.time_of_day / 24.0 * 360.0)) * 60.0
# 计算日照因子
day_factor = max(0.0, min(1.0, (sun_elevation + 10.0) / 70.0)) # 从-10度到60度
# 获取当前天气
current_weather = self.weather_conditions[self.current_weather]
# 插值计算光照颜色
if 'directional' in self.lighting_system:
day_color = current_weather['directional_light']
night_color = (0.1, 0.1, 0.2, 1.0) # 月光颜色
light_color = [
day_color[i] * day_factor + night_color[i] * (1.0 - day_factor)
for i in range(4)
]
light_node = self.lighting_system['directional']['node']
light_node.setColor(Vec4(*light_color))
# 更新环境光
if 'ambient' in self.lighting_system:
day_ambient = current_weather['ambient_light']
night_ambient = (0.05, 0.05, 0.1, 1.0)
ambient_color = [
day_ambient[i] * day_factor + night_ambient[i] * (1.0 - day_factor)
for i in range(4)
]
light_node = self.lighting_system['ambient']['node']
light_node.setColor(Vec4(*ambient_color))
except Exception as e:
print(f"更新光照颜色时出错: {e}")
def _update_sky(self, time_delta):
"""
更新天空(增强版)
"""
try:
# 更新天空颜色
self._update_sky_color()
# 更新云层
self._update_cloud_layer(time_delta)
except Exception as e:
print(f"更新天空时出错: {e}")
def _update_sky_color(self):
"""
更新天空颜色
"""
try:
# 根据时间、天气和季节调整天空颜色
current_weather = self.weather_conditions[self.current_weather]
sky_tint = current_weather['sky_tint']
# 根据太阳高度调整天空颜色
sun_elevation = math.sin(deg2Rad(self.time_of_day / 24.0 * 360.0)) * 60.0
day_factor = max(0.0, min(1.0, (sun_elevation + 10.0) / 70.0))
# 计算天空颜色
day_sky = (0.4, 0.6, 1.0, 1.0) # 白天天空蓝
night_sky = (0.05, 0.05, 0.1, 1.0) # 夜晚天空暗
sky_color = [
(day_sky[i] * sky_tint[i] * day_factor + night_sky[i] * (1.0 - day_factor))
* current_weather['sun_intensity']
for i in range(4)
]
# 应用天空颜色到天空穹顶
if self.sky_dome:
self.sky_dome.setColor(Vec4(*sky_color))
except Exception as e:
print(f"更新天空颜色时出错: {e}")
def _update_cloud_layer(self, time_delta):
"""
更新云层
"""
# 云层更新已在粒子系统中处理
pass
def _update_sky_for_weather(self, weather_type):
"""
根据天气更新天空
"""
try:
if self.sky_dome:
current_weather = self.weather_conditions[weather_type]
# 可以根据天气调整天空穹顶的纹理或颜色
pass
except Exception as e:
print(f"根据天气更新天空时出错: {e}")
def set_time_of_day(self, hour, minute=0):
"""
设置一天中的时间(增强版)
"""
try:
self.time_of_day = hour + minute / 60.0
# 立即更新光照和天空
self._update_celestial_positions()
self._update_lighting_colors()
self._update_sky_color()
print(f"设置时间为: {hour:02d}:{minute:02d}")
return True
except Exception as e:
print(f"设置时间时出错: {e}")
return False
def set_season(self, season):
"""
设置季节(增强版)
"""
try:
seasons = {
'spring': {'temperature': 15.0, 'vegetation_color': (0.3, 0.7, 0.3, 1.0)},
'summer': {'temperature': 25.0, 'vegetation_color': (0.2, 0.8, 0.2, 1.0)},
'autumn': {'temperature': 10.0, 'vegetation_color': (0.8, 0.5, 0.2, 1.0)},
'winter': {'temperature': -5.0, 'vegetation_color': (0.6, 0.6, 0.8, 1.0)}
}
if season in seasons:
self.current_season = season
season_data = seasons[season]
print(f"设置季节为: {season}")
return season_data
except Exception as e:
print(f"设置季节时出错: {e}")
return None
def create_dynamic_sky(self, sky_type='dome'):
"""
创建动态天空(增强版)
"""
try:
# 移除现有的天空
if self.sky_dome and not self.sky_dome.isEmpty():
self.sky_dome.removeNode()
# 创建天空穹顶
if sky_type == 'dome':
self._create_sky_dome()
elif sky_type == 'box':
self._create_sky_box()
elif sky_type == 'procedural':
self._create_procedural_sky()
print(f"创建动态天空: {sky_type}")
return True
except Exception as e:
print(f"创建动态天空时出错: {e}")
return False
def _create_sky_dome(self):
"""
创建天空穹顶(增强版)
"""
try:
# 创建天空穹顶几何体
from panda3d.core import GeomVertexFormat, GeomVertexData, GeomVertexWriter
from panda3d.core import GeomTriangles, Geom, GeomNode
# 创建顶点数据
vformat = GeomVertexFormat.getV3c4()
vdata = GeomVertexData('sky_dome', vformat, Geom.UHStatic)
# 添加顶点
vertex = GeomVertexWriter(vdata, 'vertex')
color = GeomVertexWriter(vdata, 'color')
# 创建半球形穹顶
radius = 1000.0
segments = 32
rings = 16
vertices = []
indices = []
# 生成顶点
for r in range(rings + 1):
for s in range(segments + 1):
# 球面坐标
theta = math.pi * r / rings # 从0到π
phi = 2 * math.pi * s / segments # 从0到2π
x = radius * math.sin(theta) * math.cos(phi)
y = radius * math.sin(theta) * math.sin(phi)
z = radius * math.cos(theta)
vertices.append((x, y, z))
# 生成索引
for r in range(rings):
for s in range(segments):
# 计算四个顶点的索引
i1 = r * (segments + 1) + s
i2 = r * (segments + 1) + (s + 1)
i3 = (r + 1) * (segments + 1) + s
i4 = (r + 1) * (segments + 1) + (s + 1)
# 添加两个三角形
indices.extend([i1, i3, i2])
indices.extend([i2, i3, i4])
# 写入顶点数据
for i, (x, y, z) in enumerate(vertices):
vertex.addData3(x, y, z)
# 默认天空颜色
color.addData4(0.4, 0.6, 1.0, 1.0)
# 创建几何体
geom = Geom(vdata)
prim = GeomTriangles(Geom.UHStatic)
# 添加索引
for idx in indices:
prim.addVertex(idx)
prim.closePrimitive()
geom.addPrimitive(prim)
# 创建节点
node = GeomNode('sky_dome')
node.addGeom(geom)
# 创建节点路径
self.sky_dome = self.world.render.attachNewNode(node)
# 设置渲染属性
self.sky_dome.setBin("background", 0)
self.sky_dome.setDepthWrite(False)
self.sky_dome.setDepthTest(False)
self.sky_dome.setLightOff()
self.sky_dome.setFogOff()
# 设置位置在相机中心
self.sky_dome.setCompass() # 跟随相机旋转但不移动
print("创建天空穹顶")
except Exception as e:
print(f"创建天空穹顶时出错: {e}")
def _create_sky_box(self):
"""
创建天空盒
"""
# 简化实现,实际项目中应该加载立方体贴图
print("创建天空盒(简化实现)")
pass
def _create_procedural_sky(self):
"""
创建程序化天空
"""
# 简化实现,实际项目中应该使用着色器生成程序化天空
print("创建程序化天空(简化实现)")
pass
def simulate_weather_cycle(self, duration=3600.0, cycle_pattern=None):
"""
模拟天气循环(增强版)
"""
try:
# 创建天气变化序列
if cycle_pattern is None:
# 默认循环模式
cycle_pattern = ['sunny', 'cloudy', 'rainy', 'stormy', 'snowy', 'foggy']
# 可以实现定时改变天气
print(f"开始天气循环模拟,持续时间: {duration}")
print(f"循环模式: {cycle_pattern}")
return True
except Exception as e:
print(f"模拟天气循环时出错: {e}")
return False
def get_environment_stats(self):
"""
获取环境统计信息(增强版)
"""
stats = {
'current_weather': self.current_weather,
'time_of_day': self.time_of_day,
'current_season': self.current_season,
'weather_enabled': self.weather_enabled,
'particle_systems': len(self.particle_systems),
'fog_density': self.fog.getExpDensity() if self.fog else 0.0,
'wind_strength': self.wind_strength,
'wind_vector': (self.wind_vector.getX(), self.wind_vector.getY(), self.wind_vector.getZ()),
'ambient_light': self.lighting_system['ambient']['node'].getColor() if 'ambient' in self.lighting_system else Vec4(0,0,0,0),
'directional_light': self.lighting_system['directional']['node'].getColor() if 'directional' in self.lighting_system else Vec4(0,0,0,0),
'moon_light_enabled': self.lighting_system['moon']['enabled'] if 'moon' in self.lighting_system else False,
'sky_dome_exists': self.sky_dome is not None and not self.sky_dome.isEmpty(),
'performance': {
'last_update_time': self.performance_stats['last_update_time'],
'avg_update_time': self.performance_stats['avg_update_time'],
'update_count': self.performance_stats['update_count']
}
}
return stats
def save_environment_data(self, output_path):
"""
保存环境数据(增强版)
"""
try:
# 收集环境数据
environment_data = {
'current_weather': self.current_weather,
'time_of_day': self.time_of_day,
'current_season': self.current_season,
'weather_conditions': self.weather_conditions,
'lighting': {
'ambient': list(self.lighting_system['ambient']['node'].getColor()) if 'ambient' in self.lighting_system else [],
'directional': list(self.lighting_system['directional']['node'].getColor()) if 'directional' in self.lighting_system else [],
'moon_enabled': self.lighting_system['moon']['enabled'] if 'moon' in self.lighting_system else False
},
'fog': {
'color': list(self.fog.getColor()) if self.fog else [],
'density': self.fog.getExpDensity() if self.fog else 0.0
},
'wind': {
'strength': self.wind_strength,
'vector': [self.wind_vector.getX(), self.wind_vector.getY(), self.wind_vector.getZ()]
}
}
# 确保输出目录存在
output_dir = os.path.dirname(output_path)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 写入JSON文件
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(environment_data, f, indent=2, ensure_ascii=False)
print(f"环境数据保存成功: {output_path}")
return True
except Exception as e:
print(f"保存环境数据时出错: {e}")
return False
def load_environment_data(self, input_path):
"""
加载环境数据(增强版)
"""
try:
if not os.path.exists(input_path):
print(f"环境数据文件不存在: {input_path}")
return False
# 读取JSON文件
with open(input_path, 'r', encoding='utf-8') as f:
environment_data = json.load(f)
# 恢复时间
if 'time_of_day' in environment_data:
self.time_of_day = environment_data['time_of_day']
# 恢复季节
if 'current_season' in environment_data:
self.current_season = environment_data['current_season']
# 恢复天气条件
if 'weather_conditions' in environment_data:
self.weather_conditions = environment_data['weather_conditions']
# 恢复当前天气
if 'current_weather' in environment_data:
self.set_weather(environment_data['current_weather'], transition_time=0)
# 恢复光照
if 'lighting' in environment_data:
lighting = environment_data['lighting']
if 'ambient' in lighting and len(lighting['ambient']) == 4:
if 'ambient' in self.lighting_system:
light_node = self.lighting_system['ambient']['node']
light_node.setColor(Vec4(*lighting['ambient']))
if 'directional' in lighting and len(lighting['directional']) == 4:
if 'directional' in self.lighting_system:
light_node = self.lighting_system['directional']['node']
light_node.setColor(Vec4(*lighting['directional']))
if 'moon_enabled' in lighting:
if lighting['moon_enabled'] and not self.lighting_system['moon']['enabled']:
self.world.render.setLight(self.moon_light_np)
self.lighting_system['moon']['enabled'] = True
elif not lighting['moon_enabled'] and self.lighting_system['moon']['enabled']:
self.world.render.clearLight(self.moon_light_np)
self.lighting_system['moon']['enabled'] = False
# 恢复雾效
if 'fog' in environment_data:
fog_data = environment_data['fog']
if 'color' in fog_data and len(fog_data['color']) == 4:
self.fog.setColor(*fog_data['color'])
if 'density' in fog_data:
self.fog.setExpDensity(fog_data['density'])
# 恢复风效
if 'wind' in environment_data:
wind_data = environment_data['wind']
if 'strength' in wind_data:
self.wind_strength = wind_data['strength']
if 'vector' in wind_data and len(wind_data['vector']) == 3:
self.wind_vector = Vec3(*wind_data['vector'])
# 更新光照和天空
self._update_celestial_positions()
self._update_lighting_colors()
self._update_sky_color()
print(f"环境数据加载成功: {input_path}")
return True
except Exception as e:
print(f"加载环境数据时出错: {e}")
return False
def set_weather_enabled(self, enabled):
"""
启用或禁用天气系统
"""
self.weather_enabled = enabled
print(f"天气系统已{'启用' if enabled else '禁用'}")
def clear_all_environment_effects(self):
"""
清除所有环境效果(增强版)
"""
try:
# 清除粒子效果
self._clear_particle_effects()
# 重置为晴天
self.set_weather('sunny', transition_time=0)
# 清除雾效
if self.fog:
self.fog.setExpDensity(0.0)
# 重置时间
self.set_time_of_day(12, 0)
# 重置季节
self.set_season('summer')
print("清除所有环境效果")
return True
except Exception as e:
print(f"清除所有环境效果时出错: {e}")
return False
def create_weather_zone(self, position, radius, weather_type, transition_time=2.0):
"""
创建局部天气区域(增强版)
"""
try:
# 创建局部天气区域
# 可以实现球形或盒形的局部天气效果
weather_zone = {
'position': position,
'radius': radius,
'weather_type': weather_type,
'transition_time': transition_time,
'node': None, # 可视化节点
'creation_time': self.world.globalClock.getFrameTime(),
'active': True
}
# 可以创建一个可视化表示
cm = CardMaker('weather_zone')
cm.setFrame(-radius, radius, -radius, radius)
zone_node = self.world.render.attachNewNode(cm.generate())
zone_node.setPos(position)
zone_node.setBin("fixed", 10)
zone_node.setDepthWrite(False)
zone_node.setDepthTest(False)
zone_node.setColor(1, 1, 1, 0.2) # 半透明
zone_node.hide() # 默认隐藏
weather_zone['node'] = zone_node
print(f"创建局部天气区域: {weather_type} at {position}")
return weather_zone
except Exception as e:
print(f"创建局部天气区域时出错: {e}")
return None
def add_weather_event(self, event_type, duration, intensity=1.0):
"""
添加天气事件(如突然的阵雨、雷暴等)
"""
try:
weather_event = {
'type': event_type,
'duration': duration,
'intensity': intensity,
'start_time': self.world.globalClock.getFrameTime(),
'active': True
}
# 根据事件类型应用效果
if event_type == 'sudden_rain':
# 增加雨天粒子效果
self._create_rain_effect()
elif event_type == 'thunderstorm':
# 增加闪电和雨天效果
self._create_lightning_effect()
self._create_rain_effect()
elif event_type == 'gust_of_wind':
# 增加风力
self.wind_strength *= (1.0 + intensity)
print(f"添加天气事件: {event_type}, 持续时间: {duration}")
return weather_event
except Exception as e:
print(f"添加天气事件时出错: {e}")
return None