935 lines
37 KiB
Python
935 lines
37 KiB
Python
"""
|
||
地形水体系统
|
||
提供完整的水体模拟、渲染、交互、流体动力学等功能
|
||
"""
|
||
|
||
from panda3d.core import NodePath, Vec3, Point3, BitMask32
|
||
from panda3d.core import CardMaker, Plane, PlaneNode
|
||
from panda3d.core import Texture, TextureStage, Material
|
||
from panda3d.core import Shader, ShaderAttrib, Filename
|
||
from panda3d.core import PNMImage
|
||
import math
|
||
import random
|
||
import numpy as np
|
||
|
||
class WaterSystem:
|
||
"""
|
||
地形水体系统类
|
||
提供水体创建、流体动力学模拟、高级渲染和交互功能
|
||
"""
|
||
|
||
def __init__(self, world):
|
||
self.world = world
|
||
self.water_bodies = [] # 存储水体实例
|
||
self.wave_parameters = {
|
||
'amplitude': 0.5,
|
||
'frequency': 1.0,
|
||
'speed': 1.0,
|
||
'direction': Vec3(1, 0, 0)
|
||
}
|
||
self.fluid_parameters = {
|
||
'viscosity': 0.01, # 粘度
|
||
'density': 1000.0, # 密度
|
||
'surface_tension': 0.07, # 表面张力
|
||
'gravity': 9.81 # 重力
|
||
}
|
||
self.reflection_enabled = True
|
||
self.refraction_enabled = True
|
||
self.foam_enabled = True
|
||
self.caustics_enabled = True # 焦散效果
|
||
self.flow_enabled = True # 水流效果
|
||
|
||
def create_water_body(self, position, size, depth=5.0, water_type='ocean'):
|
||
"""
|
||
创建水体
|
||
position: 水体位置
|
||
size: 水体尺寸 (width, height)
|
||
depth: 水体深度
|
||
water_type: 水体类型 ('ocean', 'lake', 'river', 'pool')
|
||
"""
|
||
try:
|
||
# 创建水体节点
|
||
water_node = self.world.render.attachNewNode(f"water_body_{len(self.water_bodies)}")
|
||
water_node.setPos(position)
|
||
|
||
# 创建水面几何体
|
||
cm = CardMaker('water_surface')
|
||
cm.setFrame(-size[0]/2, size[0]/2, -size[1]/2, size[1]/2)
|
||
surface_node = water_node.attachNewNode(cm.generate())
|
||
surface_node.setP(-90) # 使平面水平
|
||
|
||
# 初始化流体动力学网格
|
||
resolution_x = max(32, int(size[0] / 2)) # 根据水体大小调整分辨率
|
||
resolution_y = max(32, int(size[1] / 2))
|
||
|
||
# 创建高度场用于流体模拟
|
||
height_field = np.zeros((resolution_x, resolution_y))
|
||
|
||
# 设置水体属性
|
||
water_info = {
|
||
'node': water_node,
|
||
'surface_node': surface_node,
|
||
'position': position,
|
||
'size': size,
|
||
'depth': depth,
|
||
'type': water_type,
|
||
'waves': [],
|
||
'objects': [], # 水中物体
|
||
'height_field': height_field,
|
||
'velocity_field': np.zeros((resolution_x, resolution_y, 2)), # 2D速度场
|
||
'pressure_field': np.zeros((resolution_x, resolution_y)), # 压力场
|
||
'resolution_x': resolution_x,
|
||
'resolution_y': resolution_y,
|
||
'last_update_time': self.world.globalClock.getFrameTime(),
|
||
'reflection_camera': None,
|
||
'refraction_camera': None
|
||
}
|
||
|
||
# 应用水面材质和着色器
|
||
self._setup_water_material(water_info)
|
||
|
||
# 设置碰撞体
|
||
self._setup_water_collision(water_info)
|
||
|
||
# 设置标签
|
||
water_node.setTag("water_type", water_type)
|
||
water_node.setTag("is_scene_element", "1")
|
||
water_node.setTag("tree_item_type", "WATER_NODE")
|
||
|
||
# 添加到水体列表
|
||
self.water_bodies.append(water_info)
|
||
|
||
print(f"创建水体: {water_type} at {position} (分辨率: {resolution_x}x{resolution_y})")
|
||
return water_info
|
||
|
||
except Exception as e:
|
||
print(f"创建水体时出错: {e}")
|
||
return None
|
||
|
||
def _setup_water_material(self, water_info):
|
||
"""
|
||
设置水体材质和高级着色器
|
||
"""
|
||
try:
|
||
surface_node = water_info['surface_node']
|
||
|
||
# 创建水体材质
|
||
water_material = Material()
|
||
water_material.setAmbient((0.1, 0.1, 0.3, 1.0)) # 深蓝色环境光
|
||
water_material.setDiffuse((0.2, 0.2, 0.8, 0.8)) # 半透明蓝色漫反射
|
||
water_material.setSpecular((0.8, 0.8, 0.9, 1.0)) # 白色高光
|
||
water_material.setShininess(100.0) # 高光强度
|
||
water_material.setEmission((0.0, 0.05, 0.1, 1.0)) # 微弱自发光
|
||
|
||
surface_node.setMaterial(water_material)
|
||
|
||
# 启用透明度
|
||
surface_node.setTransparency(True)
|
||
|
||
# 创建水体法线贴图用于更好的光照效果
|
||
self._create_water_normal_map(water_info)
|
||
|
||
# 如果支持RenderPipeline,应用高级水体着色器
|
||
if hasattr(self.world, 'render_pipeline'):
|
||
try:
|
||
effect_options = {
|
||
"normal_mapping": True,
|
||
"reflection": self.reflection_enabled,
|
||
"refraction": self.refraction_enabled,
|
||
"foam": self.foam_enabled,
|
||
"caustics": self.caustics_enabled,
|
||
"wave_frequency": self.wave_parameters['frequency'],
|
||
"wave_amplitude": self.wave_parameters['amplitude'],
|
||
"wave_speed": self.wave_parameters['speed']
|
||
}
|
||
|
||
self.world.render_pipeline.set_effect(
|
||
surface_node,
|
||
"effects/water_advanced.yaml",
|
||
effect_options,
|
||
20 # 排序值,确保水体在适当层级渲染
|
||
)
|
||
except Exception as e:
|
||
print(f"应用高级水体着色器失败: {e}")
|
||
# 回退到基本着色器
|
||
self._setup_basic_water_shader(surface_node)
|
||
else:
|
||
# 使用基本的水体着色器
|
||
self._setup_basic_water_shader(surface_node)
|
||
|
||
except Exception as e:
|
||
print(f"设置水体材质时出错: {e}")
|
||
|
||
def _create_water_normal_map(self, water_info):
|
||
"""
|
||
创建水体法线贴图
|
||
"""
|
||
try:
|
||
# 创建法线贴图用于更好的光照效果
|
||
size_x, size_y = water_info['resolution_x'], water_info['resolution_y']
|
||
|
||
# 创建法线贴图
|
||
normal_map = PNMImage(size_x, size_y, 3) # RGB格式
|
||
normal_map.fill(0.5, 0.5, 1.0) # 初始法线为(0,0,1)
|
||
|
||
# 保存法线贴图
|
||
water_info['normal_map'] = normal_map
|
||
|
||
# 应用法线贴图到材质
|
||
surface_node = water_info['surface_node']
|
||
if 'normal_map' in water_info:
|
||
# 这里可以应用法线贴图到纹理阶段
|
||
pass
|
||
|
||
except Exception as e:
|
||
print(f"创建水体法线贴图时出错: {e}")
|
||
|
||
def _setup_basic_water_shader(self, surface_node):
|
||
"""
|
||
设置高级水体着色器(包含流体效果)
|
||
"""
|
||
try:
|
||
# 创建高级水体着色器
|
||
vertex_shader = """
|
||
#version 130
|
||
|
||
uniform float time;
|
||
uniform float wave_amplitude;
|
||
uniform float wave_frequency;
|
||
uniform float wave_speed;
|
||
uniform vec2 wave_direction;
|
||
|
||
varying vec3 v_normal;
|
||
varying vec3 v_world_pos;
|
||
varying vec2 v_uv;
|
||
|
||
void main() {
|
||
vec4 pos = gl_Vertex;
|
||
v_uv = gl_MultiTexCoord0.xy;
|
||
|
||
// 添加多层波浪效果
|
||
float wave1 = sin(pos.x * wave_frequency + time * wave_speed) *
|
||
cos(pos.y * wave_frequency + time * wave_speed) *
|
||
wave_amplitude;
|
||
|
||
float wave2 = sin(pos.x * wave_frequency * 2.0 + time * wave_speed * 1.5) *
|
||
cos(pos.y * wave_frequency * 1.5 + time * wave_speed * 1.2) *
|
||
wave_amplitude * 0.5;
|
||
|
||
float wave3 = sin(pos.x * wave_frequency * 0.5 + pos.y * wave_frequency * 0.5 + time * wave_speed * 0.8) *
|
||
wave_amplitude * 0.3;
|
||
|
||
pos.z += wave1 + wave2 + wave3;
|
||
|
||
gl_Position = gl_ModelViewProjectionMatrix * pos;
|
||
v_normal = gl_NormalMatrix * gl_Normal;
|
||
v_world_pos = (gl_ModelViewMatrix * pos).xyz;
|
||
}
|
||
"""
|
||
|
||
fragment_shader = """
|
||
#version 130
|
||
|
||
uniform float time;
|
||
uniform sampler2D normal_map;
|
||
uniform bool use_foam;
|
||
uniform bool use_caustics;
|
||
|
||
varying vec3 v_normal;
|
||
varying vec3 v_world_pos;
|
||
varying vec2 v_uv;
|
||
|
||
void main() {
|
||
// 基础水体颜色
|
||
vec3 water_color = vec3(0.1, 0.3, 0.6);
|
||
|
||
// 添加深度颜色变化
|
||
float depth_factor = clamp(v_world_pos.z * 0.1, 0.0, 1.0);
|
||
vec3 deep_color = vec3(0.05, 0.15, 0.3);
|
||
water_color = mix(water_color, deep_color, depth_factor);
|
||
|
||
// 计算光照
|
||
vec3 light_dir = normalize(vec3(0.5, 0.5, 0.7));
|
||
vec3 normal = normalize(v_normal);
|
||
float diffuse = max(dot(normal, light_dir), 0.0);
|
||
|
||
// 添加高光
|
||
vec3 view_dir = normalize(-v_world_pos);
|
||
vec3 reflect_dir = reflect(-light_dir, normal);
|
||
float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32.0);
|
||
|
||
// 泡沫效果
|
||
float foam = 0.0;
|
||
if (use_foam) {
|
||
foam = sin(v_uv.x * 20.0 + time) * sin(v_uv.y * 20.0 + time) * 0.5 + 0.5;
|
||
foam = pow(foam, 8.0);
|
||
}
|
||
|
||
// 焦散效果
|
||
float caustics = 0.0;
|
||
if (use_caustics) {
|
||
caustics = sin(v_uv.x * 10.0 + time * 2.0) * sin(v_uv.y * 10.0 + time * 2.0);
|
||
caustics = caustics * 0.3 + 0.3;
|
||
}
|
||
|
||
vec3 result = water_color * (0.3 + 0.7 * diffuse) + vec3(0.8) * spec;
|
||
result += vec3(foam * 0.8);
|
||
result += vec3(caustics * 0.4);
|
||
|
||
// 设置透明度
|
||
float alpha = 0.7 + foam * 0.3;
|
||
gl_FragColor = vec4(result, alpha);
|
||
}
|
||
"""
|
||
|
||
# 创建着色器
|
||
shader = Shader.make(Shader.SL_GLSL, vertex_shader, fragment_shader)
|
||
if shader:
|
||
surface_node.setShader(shader)
|
||
|
||
# 设置着色器参数
|
||
surface_node.setShaderInput("wave_amplitude", self.wave_parameters['amplitude'])
|
||
surface_node.setShaderInput("wave_frequency", self.wave_parameters['frequency'])
|
||
surface_node.setShaderInput("wave_speed", self.wave_parameters['speed'])
|
||
surface_node.setShaderInput("wave_direction", self.wave_parameters['direction'])
|
||
surface_node.setShaderInput("use_foam", self.foam_enabled)
|
||
surface_node.setShaderInput("use_caustics", self.caustics_enabled)
|
||
|
||
except Exception as e:
|
||
print(f"设置高级水体着色器时出错: {e}")
|
||
|
||
def _setup_water_collision(self, water_info):
|
||
"""
|
||
设置水体碰撞体
|
||
"""
|
||
try:
|
||
water_node = water_info['node']
|
||
size = water_info['size']
|
||
|
||
# 创建碰撞平面
|
||
plane = Plane(Vec3(0, 0, 1), Point3(0, 0, 0))
|
||
plane_node = PlaneNode('water_collision', plane)
|
||
collision_node = water_node.attachNewNode(plane_node)
|
||
|
||
# 设置碰撞掩码
|
||
collision_node.setCollideMask(BitMask32.bit(4)) # 使用第4位作为水体碰撞掩码
|
||
|
||
# 保存碰撞节点
|
||
water_info['collision_node'] = collision_node
|
||
|
||
except Exception as e:
|
||
print(f"设置水体碰撞体时出错: {e}")
|
||
|
||
def update_water_animation(self, time_delta):
|
||
"""
|
||
更新水体动画和流体模拟
|
||
"""
|
||
try:
|
||
current_time = self.world.globalClock.getFrameTime()
|
||
|
||
for water_info in self.water_bodies:
|
||
surface_node = water_info['surface_node']
|
||
|
||
# 更新着色器时间参数
|
||
if surface_node.hasShader():
|
||
surface_node.setShaderInput("time", current_time)
|
||
|
||
# 更新流体动力学
|
||
self._update_fluid_dynamics(water_info, time_delta)
|
||
|
||
# 更新波浪效果
|
||
self._update_water_waves(water_info, current_time)
|
||
|
||
# 更新反射和折射效果
|
||
self._update_water_reflection(water_info)
|
||
|
||
except Exception as e:
|
||
print(f"更新水体动画时出错: {e}")
|
||
|
||
def _update_fluid_dynamics(self, water_info, time_delta):
|
||
"""
|
||
更新流体动力学模拟
|
||
"""
|
||
try:
|
||
# Navier-Stokes方程的简化实现
|
||
height_field = water_info['height_field']
|
||
velocity_field = water_info['velocity_field']
|
||
pressure_field = water_info['pressure_field']
|
||
resolution_x = water_info['resolution_x']
|
||
resolution_y = water_info['resolution_y']
|
||
|
||
# 获取流体参数
|
||
viscosity = self.fluid_parameters['viscosity']
|
||
gravity = self.fluid_parameters['gravity']
|
||
|
||
# 更新速度场
|
||
for i in range(1, resolution_x - 1):
|
||
for j in range(1, resolution_y - 1):
|
||
# 粘性扩散
|
||
laplacian_u = (velocity_field[i+1, j, 0] + velocity_field[i-1, j, 0] +
|
||
velocity_field[i, j+1, 0] + velocity_field[i, j-1, 0] -
|
||
4 * velocity_field[i, j, 0])
|
||
laplacian_v = (velocity_field[i+1, j, 1] + velocity_field[i-1, j, 1] +
|
||
velocity_field[i, j+1, 1] + velocity_field[i, j-1, 1] -
|
||
4 * velocity_field[i, j, 1])
|
||
|
||
# 更新速度
|
||
velocity_field[i, j, 0] += viscosity * laplacian_u * time_delta
|
||
velocity_field[i, j, 1] += viscosity * laplacian_v * time_delta
|
||
|
||
# 重力影响
|
||
velocity_field[i, j, 1] -= gravity * time_delta
|
||
|
||
# 更新高度场
|
||
for i in range(1, resolution_x - 1):
|
||
for j in range(1, resolution_y - 1):
|
||
# 连续性方程
|
||
divergence = (velocity_field[i+1, j, 0] - velocity_field[i-1, j, 0] +
|
||
velocity_field[i, j+1, 1] - velocity_field[i, j-1, 1]) * 0.5
|
||
|
||
# 更新高度
|
||
height_field[i, j] -= divergence * time_delta
|
||
|
||
# 应用边界条件
|
||
self._apply_boundary_conditions(water_info)
|
||
|
||
# 更新水体表面几何
|
||
self._update_water_surface_geometry(water_info)
|
||
|
||
except Exception as e:
|
||
print(f"更新流体动力学时出错: {e}")
|
||
|
||
def _apply_boundary_conditions(self, water_info):
|
||
"""
|
||
应用流体边界条件
|
||
"""
|
||
try:
|
||
height_field = water_info['height_field']
|
||
velocity_field = water_info['velocity_field']
|
||
resolution_x = water_info['resolution_x']
|
||
resolution_y = water_info['resolution_y']
|
||
|
||
# 固定边界条件:边缘速度为0
|
||
velocity_field[0, :, :] = 0
|
||
velocity_field[resolution_x-1, :, :] = 0
|
||
velocity_field[:, 0, :] = 0
|
||
velocity_field[:, resolution_y-1, :] = 0
|
||
|
||
# 高度场边界反射
|
||
height_field[0, :] = height_field[1, :]
|
||
height_field[resolution_x-1, :] = height_field[resolution_x-2, :]
|
||
height_field[:, 0] = height_field[:, 1]
|
||
height_field[:, resolution_y-1] = height_field[:, resolution_y-2]
|
||
|
||
except Exception as e:
|
||
print(f"应用边界条件时出错: {e}")
|
||
|
||
def _update_water_surface_geometry(self, water_info):
|
||
"""
|
||
更新水体表面几何形状
|
||
"""
|
||
try:
|
||
# 这里可以实现动态更新水体表面顶点位置
|
||
# 基于高度场数据调整顶点Z坐标
|
||
pass
|
||
|
||
except Exception as e:
|
||
print(f"更新水体表面几何时出错: {e}")
|
||
|
||
def _update_water_waves(self, water_info, current_time):
|
||
"""
|
||
更新水体波浪(多层波浪系统)
|
||
"""
|
||
try:
|
||
# 生成更复杂的波浪系统
|
||
wave_system = water_info.get('wave_system', [])
|
||
|
||
# 如果还没有初始化波浪系统,创建多层波浪
|
||
if not wave_system:
|
||
wave_system = []
|
||
# 创建不同频率和振幅的波浪层
|
||
for i in range(5): # 5层波浪
|
||
wave = {
|
||
'frequency': self.wave_parameters['frequency'] * (0.5 + i * 0.5),
|
||
'amplitude': self.wave_parameters['amplitude'] * (1.0 - i * 0.15),
|
||
'speed': self.wave_parameters['speed'] * (0.8 + i * 0.2),
|
||
'direction': Vec3(random.uniform(-1, 1), random.uniform(-1, 1), 0).normalized()
|
||
}
|
||
wave_system.append(wave)
|
||
water_info['wave_system'] = wave_system
|
||
|
||
# 更新波浪参数
|
||
water_info['waves'] = wave_system
|
||
|
||
except Exception as e:
|
||
print(f"更新水体波浪时出错: {e}")
|
||
|
||
def _update_water_reflection(self, water_info):
|
||
"""
|
||
更新水体反射效果
|
||
"""
|
||
try:
|
||
if not self.reflection_enabled:
|
||
return
|
||
|
||
# 这里可以实现反射相机的更新逻辑
|
||
# 包括相机位置的镜像计算等
|
||
pass
|
||
|
||
except Exception as e:
|
||
print(f"更新水体反射时出错: {e}")
|
||
|
||
def set_wave_parameters(self, amplitude=None, frequency=None, speed=None, direction=None):
|
||
"""
|
||
设置波浪参数
|
||
"""
|
||
if amplitude is not None:
|
||
self.wave_parameters['amplitude'] = amplitude
|
||
if frequency is not None:
|
||
self.wave_parameters['frequency'] = frequency
|
||
if speed is not None:
|
||
self.wave_parameters['speed'] = speed
|
||
if direction is not None:
|
||
self.wave_parameters['direction'] = direction
|
||
|
||
# 更新所有水体的着色器参数
|
||
for water_info in self.water_bodies:
|
||
surface_node = water_info['surface_node']
|
||
if surface_node.hasShader():
|
||
if amplitude is not None:
|
||
surface_node.setShaderInput("wave_amplitude", amplitude)
|
||
if frequency is not None:
|
||
surface_node.setShaderInput("wave_frequency", frequency)
|
||
if speed is not None:
|
||
surface_node.setShaderInput("wave_speed", speed)
|
||
if direction is not None:
|
||
surface_node.setShaderInput("wave_direction", direction)
|
||
|
||
print(f"更新波浪参数: {self.wave_parameters}")
|
||
|
||
def set_fluid_parameters(self, viscosity=None, density=None, surface_tension=None, gravity=None):
|
||
"""
|
||
设置流体参数
|
||
"""
|
||
if viscosity is not None:
|
||
self.fluid_parameters['viscosity'] = viscosity
|
||
if density is not None:
|
||
self.fluid_parameters['density'] = density
|
||
if surface_tension is not None:
|
||
self.fluid_parameters['surface_tension'] = surface_tension
|
||
if gravity is not None:
|
||
self.fluid_parameters['gravity'] = gravity
|
||
|
||
print(f"更新流体参数: {self.fluid_parameters}")
|
||
|
||
def simulate_water_physics(self, time_delta):
|
||
"""
|
||
模拟水体物理效果
|
||
"""
|
||
try:
|
||
for water_info in self.water_bodies:
|
||
# 模拟水流
|
||
self._simulate_water_flow(water_info, time_delta)
|
||
|
||
# 模拟水花
|
||
self._simulate_water_splash(water_info, time_delta)
|
||
|
||
# 模拟波纹
|
||
self._simulate_water_ripples(water_info, time_delta)
|
||
|
||
except Exception as e:
|
||
print(f"模拟水体物理时出错: {e}")
|
||
|
||
def _simulate_water_flow(self, water_info, time_delta):
|
||
"""
|
||
模拟水流效果
|
||
"""
|
||
try:
|
||
if not self.flow_enabled:
|
||
return
|
||
|
||
# 模拟水流方向和速度
|
||
# 可以基于地形坡度或外力计算水流
|
||
pass
|
||
|
||
except Exception as e:
|
||
print(f"模拟水流效果时出错: {e}")
|
||
|
||
def _simulate_water_splash(self, water_info, time_delta):
|
||
"""
|
||
模拟水花效果
|
||
"""
|
||
try:
|
||
# 模拟物体落入水中时产生的水花效果
|
||
# 可以创建粒子系统或动态几何体
|
||
pass
|
||
|
||
except Exception as e:
|
||
print(f"模拟水花效果时出错: {e}")
|
||
|
||
def _simulate_water_ripples(self, water_info, time_delta):
|
||
"""
|
||
模拟波纹效果
|
||
"""
|
||
try:
|
||
# 模拟水面波纹传播
|
||
# 基于波动方程的简化实现
|
||
pass
|
||
|
||
except Exception as e:
|
||
print(f"模拟波纹效果时出错: {e}")
|
||
|
||
def add_object_to_water(self, water_info, object_node, buoyancy=1.0):
|
||
"""
|
||
将物体添加到水中
|
||
"""
|
||
try:
|
||
# 计算物体的水中位置
|
||
water_pos = object_node.getPos(water_info['node'])
|
||
|
||
object_info = {
|
||
'node': object_node,
|
||
'buoyancy': buoyancy,
|
||
'water_position': water_pos,
|
||
'velocity': Vec3(0, 0, 0),
|
||
'volume': self._calculate_object_volume(object_node),
|
||
'density': 1000.0, # 默认密度
|
||
'submerged_volume': 0.0,
|
||
'drag_coefficient': 0.5
|
||
}
|
||
|
||
water_info['objects'].append(object_info)
|
||
print(f"物体已添加到水中: {object_node.getName()}")
|
||
return object_info
|
||
|
||
except Exception as e:
|
||
print(f"添加物体到水中时出错: {e}")
|
||
return None
|
||
|
||
def _calculate_object_volume(self, object_node):
|
||
"""
|
||
计算物体体积(简化实现)
|
||
"""
|
||
try:
|
||
# 获取物体包围盒
|
||
bounds = object_node.getBounds()
|
||
if hasattr(bounds, 'getRadius'):
|
||
# 简化为球体体积计算
|
||
radius = bounds.getRadius()
|
||
volume = (4.0/3.0) * math.pi * (radius ** 3)
|
||
return volume
|
||
return 1.0 # 默认体积
|
||
except:
|
||
return 1.0
|
||
|
||
def update_water_physics(self, time_delta):
|
||
"""
|
||
更新水中物体的物理效果
|
||
"""
|
||
try:
|
||
for water_info in self.water_bodies:
|
||
water_height = water_info['position'].getZ()
|
||
fluid_density = self.fluid_parameters['density']
|
||
|
||
for object_info in water_info['objects']:
|
||
object_node = object_info['node']
|
||
if object_node and not object_node.isEmpty():
|
||
# 获取物体位置
|
||
object_pos = object_node.getPos()
|
||
|
||
# 计算浸入水中的体积
|
||
object_bounds = object_node.getBounds()
|
||
object_bottom = object_pos.getZ() - object_bounds.getRadius()
|
||
object_top = object_pos.getZ() + object_bounds.getRadius()
|
||
|
||
if object_bottom < water_height and object_top > water_height:
|
||
# 部分浸入水中
|
||
submerged_ratio = (water_height - object_bottom) / (object_top - object_bottom)
|
||
submerged_volume = object_info['volume'] * min(1.0, max(0.0, submerged_ratio))
|
||
elif object_top <= water_height:
|
||
# 完全浸入水中
|
||
submerged_volume = object_info['volume']
|
||
else:
|
||
# 完全在水上
|
||
submerged_volume = 0.0
|
||
|
||
object_info['submerged_volume'] = submerged_volume
|
||
|
||
# 计算浮力
|
||
buoyancy_force = Vec3(0, 0, submerged_volume * fluid_density * self.fluid_parameters['gravity'])
|
||
|
||
# 应用浮力
|
||
object_info['velocity'] += buoyancy_force * time_delta / object_info['density']
|
||
|
||
# 计算阻力
|
||
drag_force = -object_info['velocity'] * object_info['drag_coefficient'] * submerged_volume
|
||
object_info['velocity'] += drag_force * time_delta / object_info['density']
|
||
|
||
# 更新物体位置
|
||
new_pos = object_pos + object_info['velocity'] * time_delta
|
||
object_node.setPos(new_pos)
|
||
|
||
# 应用阻尼
|
||
object_info['velocity'] *= 0.98
|
||
|
||
except Exception as e:
|
||
print(f"更新水中物理时出错: {e}")
|
||
|
||
def create_water_foam(self, water_info, position, intensity=1.0):
|
||
"""
|
||
创建水花泡沫效果
|
||
"""
|
||
try:
|
||
# 创建泡沫粒子系统
|
||
print(f"在位置 {position} 创建水花泡沫 (强度: {intensity})")
|
||
|
||
# 这里可以实现创建粒子系统来模拟泡沫
|
||
# 包括泡沫的生命周期、扩散、消散等效果
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"创建水花泡沫时出错: {e}")
|
||
return False
|
||
|
||
def create_water_caustics(self, water_info, light_direction):
|
||
"""
|
||
创建焦散效果
|
||
"""
|
||
try:
|
||
if not self.caustics_enabled:
|
||
return False
|
||
|
||
# 创建焦散纹理或几何体
|
||
print(f"创建焦散效果 (光照方向: {light_direction})")
|
||
|
||
# 这里可以实现焦散效果的生成
|
||
# 包括光线追踪、纹理投影等技术
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"创建焦散效果时出错: {e}")
|
||
return False
|
||
|
||
def set_water_quality(self, quality_level):
|
||
"""
|
||
设置水体质量等级
|
||
"""
|
||
try:
|
||
# 根据质量等级调整水体效果
|
||
if quality_level == "low":
|
||
self.reflection_enabled = False
|
||
self.refraction_enabled = False
|
||
self.foam_enabled = False
|
||
self.caustics_enabled = False
|
||
self.flow_enabled = False
|
||
elif quality_level == "medium":
|
||
self.reflection_enabled = True
|
||
self.refraction_enabled = False
|
||
self.foam_enabled = True
|
||
self.caustics_enabled = False
|
||
self.flow_enabled = True
|
||
elif quality_level == "high":
|
||
self.reflection_enabled = True
|
||
self.refraction_enabled = True
|
||
self.foam_enabled = True
|
||
self.caustics_enabled = True
|
||
self.flow_enabled = True
|
||
|
||
# 更新所有水体
|
||
for water_info in self.water_bodies:
|
||
self._setup_water_material(water_info)
|
||
|
||
print(f"水体质量设置为: {quality_level}")
|
||
|
||
except Exception as e:
|
||
print(f"设置水体质量时出错: {e}")
|
||
|
||
def get_water_stats(self):
|
||
"""
|
||
获取水体统计信息
|
||
"""
|
||
stats = {
|
||
'total_bodies': len(self.water_bodies),
|
||
'total_surface_area': 0,
|
||
'water_types': {},
|
||
'fluid_stats': self.fluid_parameters,
|
||
'quality_settings': {
|
||
'reflection': self.reflection_enabled,
|
||
'refraction': self.refraction_enabled,
|
||
'foam': self.foam_enabled,
|
||
'caustics': self.caustics_enabled
|
||
}
|
||
}
|
||
|
||
for water_info in self.water_bodies:
|
||
# 计算表面积
|
||
area = water_info['size'][0] * water_info['size'][1]
|
||
stats['total_surface_area'] += area
|
||
|
||
# 统计水体类型
|
||
water_type = water_info['type']
|
||
if water_type in stats['water_types']:
|
||
stats['water_types'][water_type] += 1
|
||
else:
|
||
stats['water_types'][water_type] = 1
|
||
|
||
# 添加流体分辨率信息
|
||
stats[f"water_body_{len(stats['water_types'])}_resolution"] = (
|
||
water_info['resolution_x'],
|
||
water_info['resolution_y']
|
||
)
|
||
|
||
return stats
|
||
|
||
def remove_water_body(self, water_info):
|
||
"""
|
||
移除水体
|
||
"""
|
||
try:
|
||
if water_info in self.water_bodies:
|
||
# 移除节点
|
||
if water_info['node'] and not water_info['node'].isEmpty():
|
||
water_info['node'].removeNode()
|
||
|
||
# 从列表中移除
|
||
self.water_bodies.remove(water_info)
|
||
|
||
print("水体已移除")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"移除水体时出错: {e}")
|
||
return False
|
||
|
||
def clear_all_water(self):
|
||
"""
|
||
清除所有水体
|
||
"""
|
||
try:
|
||
for water_info in self.water_bodies[:]: # 使用切片复制列表
|
||
self.remove_water_body(water_info)
|
||
|
||
print("所有水体已清除")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"清除所有水体时出错: {e}")
|
||
return False
|
||
|
||
def save_water_data(self, output_path):
|
||
"""
|
||
保存水体数据
|
||
"""
|
||
try:
|
||
import json
|
||
import os
|
||
|
||
# 收集水体数据
|
||
water_data = {
|
||
'bodies': [],
|
||
'wave_parameters': self.wave_parameters,
|
||
'fluid_parameters': self.fluid_parameters,
|
||
'quality_settings': {
|
||
'reflection_enabled': self.reflection_enabled,
|
||
'refraction_enabled': self.refraction_enabled,
|
||
'foam_enabled': self.foam_enabled,
|
||
'caustics_enabled': self.caustics_enabled
|
||
}
|
||
}
|
||
|
||
for water_info in self.water_bodies:
|
||
body_data = {
|
||
'position': [water_info['position'].x,
|
||
water_info['position'].y,
|
||
water_info['position'].z],
|
||
'size': water_info['size'],
|
||
'depth': water_info['depth'],
|
||
'type': water_info['type'],
|
||
'resolution_x': water_info['resolution_x'],
|
||
'resolution_y': water_info['resolution_y']
|
||
}
|
||
water_data['bodies'].append(body_data)
|
||
|
||
# 确保输出目录存在
|
||
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(water_data, f, indent=2, ensure_ascii=False)
|
||
|
||
print(f"水体数据保存成功: {output_path}")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"保存水体数据时出错: {e}")
|
||
return False
|
||
|
||
def load_water_data(self, input_path):
|
||
"""
|
||
加载水体数据
|
||
"""
|
||
try:
|
||
import json
|
||
import os
|
||
|
||
if not os.path.exists(input_path):
|
||
print(f"水体数据文件不存在: {input_path}")
|
||
return False
|
||
|
||
# 读取JSON文件
|
||
with open(input_path, 'r', encoding='utf-8') as f:
|
||
water_data = json.load(f)
|
||
|
||
# 清除现有水体
|
||
self.clear_all_water()
|
||
|
||
# 恢复设置
|
||
if 'wave_parameters' in water_data:
|
||
self.wave_parameters = water_data['wave_parameters']
|
||
if 'fluid_parameters' in water_data:
|
||
self.fluid_parameters = water_data['fluid_parameters']
|
||
if 'quality_settings' in water_data:
|
||
qs = water_data['quality_settings']
|
||
self.reflection_enabled = qs.get('reflection_enabled', True)
|
||
self.refraction_enabled = qs.get('refraction_enabled', True)
|
||
self.foam_enabled = qs.get('foam_enabled', True)
|
||
self.caustics_enabled = qs.get('caustics_enabled', True)
|
||
|
||
# 创建水体
|
||
for body_data in water_data['bodies']:
|
||
position = Point3(body_data['position'][0],
|
||
body_data['position'][1],
|
||
body_data['position'][2])
|
||
|
||
self.create_water_body(
|
||
position=position,
|
||
size=body_data['size'],
|
||
depth=body_data['depth'],
|
||
water_type=body_data['type']
|
||
)
|
||
|
||
print(f"水体数据加载成功: {input_path}")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"加载水体数据时出错: {e}")
|
||
return False
|
||
|
||
def update_all_water_systems(self, time_delta):
|
||
"""
|
||
更新所有水体系统
|
||
"""
|
||
try:
|
||
# 更新水体动画
|
||
self.update_water_animation(time_delta)
|
||
|
||
# 更新水体物理
|
||
self.update_water_physics(time_delta)
|
||
|
||
# 更新流体动力学
|
||
self.simulate_water_physics(time_delta)
|
||
|
||
except Exception as e:
|
||
print(f"更新所有水体系统时出错: {e}") |