EG/plugins/user/fluid_simulation/rendering/fluid_renderer.py
2025-12-12 16:16:15 +08:00

776 lines
25 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.

"""
流体渲染器模块
负责流体的可视化渲染和效果处理
"""
import time
from typing import Dict, Any, List, Optional
import math
import numpy as np
class FluidRenderer:
"""
流体渲染器
负责流体的可视化渲染和效果处理
"""
def __init__(self, plugin):
"""
初始化流体渲染器
Args:
plugin: 水体和流体模拟插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 渲染配置
self.render_config = {
'render_mode': 'volume', # 'volume', 'particles', 'surface'
'quality_level': 'medium', # 'low', 'medium', 'high', 'ultra'
'max_particles': 10000,
'particle_size': 0.1,
'render_distance': 100.0,
'lod_enabled': True,
'lod_distance': 50.0
}
# 着色器配置
self.shader_config = {
'fluid_shader': 'standard',
'lighting_model': 'blinn_phong',
'normal_mapping': True,
'specular_mapping': True,
'reflection_enabled': True,
'refraction_enabled': True,
'caustics_enabled': False,
'foam_enabled': True
}
# 材质属性
self.material_properties = {
'color': (0.0, 0.3, 0.8, 0.7), # RGBA
'specular_color': (1.0, 1.0, 1.0),
'shininess': 64.0,
'reflectivity': 0.8,
'refractive_index': 1.333,
'absorption_coefficient': 0.1,
'scattering_coefficient': 0.5
}
# 光照配置
self.lighting_config = {
'ambient_light': (0.2, 0.2, 0.2),
'diffuse_light': (0.8, 0.8, 0.8),
'specular_light': (1.0, 1.0, 1.0),
'light_direction': (0.5, 1.0, 0.3)
}
# 体积渲染配置
self.volume_config = {
'sampling_rate': 64,
'step_size': 0.1,
'density_scale': 1.0,
'gradient_factor': 1.0,
'shadow_enabled': True,
'shadow_steps': 16
}
# 粒子渲染配置
self.particle_config = {
'sprite_type': 'quad', # 'quad', 'billboard', 'sphere'
'blend_mode': 'additive', # 'alpha', 'additive', 'subtractive'
'size_variation': 0.5,
'velocity_scale': 1.0,
'life_scale': True
}
# 渲染状态
self.render_state = {
'last_render_time': 0.0,
'frames_rendered': 0,
'particles_rendered': 0,
'triangles_rendered': 0
}
# 性能统计
self.performance_stats = {
'render_calls': 0,
'render_time_total': 0.0,
'average_render_time': 0.0,
'particles_drawn': 0,
'volume_samples': 0
}
# 特效配置
self.effect_config = {
'motion_blur': False,
'motion_blur_samples': 8,
'anti_aliasing': 'fxaa', # 'none', 'fxaa', 'ssaa', 'msaa'
'bloom_enabled': True,
'bloom_intensity': 0.5,
'depth_of_field': False,
'dof_focus_distance': 10.0
}
# 相机和视图
self.camera_state = {
'position': (0.0, 0.0, 0.0),
'view_matrix': None,
'projection_matrix': None,
'fov': 60.0
}
print("✓ 流体渲染器已创建")
def initialize(self) -> bool:
"""
初始化流体渲染器
Returns:
是否初始化成功
"""
try:
# 初始化渲染资源
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
# 更新渲染状态
self.render_state['last_render_time'] += dt
self.render_state['frames_rendered'] += 1
except Exception as e:
print(f"✗ 流体渲染器更新失败: {e}")
import traceback
traceback.print_exc()
def _initialize_render_resources(self):
"""初始化渲染资源"""
try:
# 在实际实现中,这里会初始化着色器、纹理、缓冲区等
print("✓ 渲染资源初始化完成")
except Exception as e:
print(f"✗ 渲染资源初始化失败: {e}")
raise
def _cleanup_render_resources(self):
"""清理渲染资源"""
try:
# 在实际实现中,这里会释放着色器、纹理、缓冲区等资源
print("✓ 渲染资源清理完成")
except Exception as e:
print(f"✗ 渲染资源清理失败: {e}")
def render_fluid(self, fluid_data: Dict[str, Any], camera_position: tuple):
"""
渲染流体
Args:
fluid_data: 流体数据字典
camera_position: 相机位置
"""
try:
start_time = time.time()
# 更新相机状态
self.camera_state['position'] = camera_position
# 根据渲染模式选择渲染方法
render_mode = self.render_config['render_mode']
if render_mode == 'volume':
self._render_volume_fluid(fluid_data)
elif render_mode == 'particles':
self._render_particle_fluid(fluid_data)
elif render_mode == 'surface':
self._render_surface_fluid(fluid_data)
else:
# 默认使用体积渲染
self._render_volume_fluid(fluid_data)
# 更新性能统计
render_time = time.time() - start_time
self.performance_stats['render_calls'] += 1
self.performance_stats['render_time_total'] += render_time
if self.performance_stats['render_calls'] > 0:
self.performance_stats['average_render_time'] = (
self.performance_stats['render_time_total'] /
self.performance_stats['render_calls']
)
# 更新渲染状态
self.render_state['frames_rendered'] += 1
except Exception as e:
print(f"✗ 流体渲染失败: {e}")
import traceback
traceback.print_exc()
def _render_volume_fluid(self, fluid_data: Dict[str, Any]):
"""
体积渲染流体
Args:
fluid_data: 流体数据
"""
try:
# 获取流体场数据
velocity_field = fluid_data.get('velocity_field')
density_field = fluid_data.get('density_field')
temperature_field = fluid_data.get('temperature_field')
if not density_field:
return
# 获取体积渲染配置
sampling_rate = self.volume_config['sampling_rate']
step_size = self.volume_config['step_size']
density_scale = self.volume_config['density_scale']
# 在实际实现中,这里会:
# 1. 设置体积着色器参数
# 2. 绑定体积纹理
# 3. 执行光线行进算法
# 4. 应用光照和材质属性
# 5. 渲染到屏幕
# 更新统计信息
self.performance_stats['volume_samples'] += sampling_rate
print("✓ 体积流体渲染完成")
except Exception as e:
print(f"✗ 体积流体渲染失败: {e}")
def _render_particle_fluid(self, fluid_data: Dict[str, Any]):
"""
粒子渲染流体
Args:
fluid_data: 流体数据
"""
try:
# 获取粒子数据
particles = fluid_data.get('particles', [])
if not particles:
return
# 获取粒子渲染配置
sprite_type = self.particle_config['sprite_type']
blend_mode = self.particle_config['blend_mode']
particle_size = self.render_config['particle_size']
# 在实际实现中,这里会:
# 1. 设置粒子着色器参数
# 2. 准备粒子顶点数据
# 3. 应用材质属性
# 4. 执行粒子渲染
# 更新统计信息
particles_count = len(particles)
self.performance_stats['particles_drawn'] += particles_count
self.render_state['particles_rendered'] += particles_count
print(f"✓ 粒子流体渲染完成 ({particles_count} 粒子)")
except Exception as e:
print(f"✗ 粒子流体渲染失败: {e}")
def _render_surface_fluid(self, fluid_data: Dict[str, Any]):
"""
表面渲染流体
Args:
fluid_data: 流体数据
"""
try:
# 获取表面网格数据
vertices = fluid_data.get('vertices', [])
normals = fluid_data.get('normals', [])
indices = fluid_data.get('indices', [])
if not vertices or not indices:
return
# 在实际实现中,这里会:
# 1. 设置表面着色器参数
# 2. 上传网格数据到GPU
# 3. 应用材质和光照
# 4. 执行网格渲染
# 更新统计信息
triangle_count = len(indices) // 3
self.render_state['triangles_rendered'] += triangle_count
print(f"✓ 表面流体渲染完成 ({triangle_count} 三角形)")
except Exception as e:
print(f"✗ 表面流体渲染失败: {e}")
def set_render_config(self, config: Dict[str, Any]):
"""
设置渲染配置
Args:
config: 渲染配置字典
"""
try:
self.render_config.update(config)
print(f"✓ 渲染配置已更新: {self.render_config}")
except Exception as e:
print(f"✗ 渲染配置设置失败: {e}")
def get_render_config(self) -> Dict[str, Any]:
"""
获取渲染配置
Returns:
渲染配置字典
"""
return self.render_config.copy()
def set_shader_config(self, config: Dict[str, Any]):
"""
设置着色器配置
Args:
config: 着色器配置字典
"""
try:
self.shader_config.update(config)
print(f"✓ 着色器配置已更新: {self.shader_config}")
except Exception as e:
print(f"✗ 着色器配置设置失败: {e}")
def get_shader_config(self) -> Dict[str, Any]:
"""
获取着色器配置
Returns:
着色器配置字典
"""
return self.shader_config.copy()
def set_material_properties(self, properties: Dict[str, Any]):
"""
设置材质属性
Args:
properties: 材质属性字典
"""
try:
self.material_properties.update(properties)
print(f"✓ 材质属性已更新: {self.material_properties}")
except Exception as e:
print(f"✗ 材质属性设置失败: {e}")
def get_material_properties(self) -> Dict[str, Any]:
"""
获取材质属性
Returns:
材质属性字典
"""
return self.material_properties.copy()
def set_lighting_config(self, config: Dict[str, Any]):
"""
设置光照配置
Args:
config: 光照配置字典
"""
try:
self.lighting_config.update(config)
print(f"✓ 光照配置已更新: {self.lighting_config}")
except Exception as e:
print(f"✗ 光照配置设置失败: {e}")
def get_lighting_config(self) -> Dict[str, Any]:
"""
获取光照配置
Returns:
光照配置字典
"""
return self.lighting_config.copy()
def set_volume_config(self, config: Dict[str, Any]):
"""
设置体积渲染配置
Args:
config: 体积渲染配置字典
"""
try:
self.volume_config.update(config)
print(f"✓ 体积渲染配置已更新: {self.volume_config}")
except Exception as e:
print(f"✗ 体积渲染配置设置失败: {e}")
def get_volume_config(self) -> Dict[str, Any]:
"""
获取体积渲染配置
Returns:
体积渲染配置字典
"""
return self.volume_config.copy()
def set_particle_config(self, config: Dict[str, Any]):
"""
设置粒子渲染配置
Args:
config: 粒子渲染配置字典
"""
try:
self.particle_config.update(config)
print(f"✓ 粒子渲染配置已更新: {self.particle_config}")
except Exception as e:
print(f"✗ 粒子渲染配置设置失败: {e}")
def get_particle_config(self) -> Dict[str, Any]:
"""
获取粒子渲染配置
Returns:
粒子渲染配置字典
"""
return self.particle_config.copy()
def set_effect_config(self, config: Dict[str, Any]):
"""
设置特效配置
Args:
config: 特效配置字典
"""
try:
self.effect_config.update(config)
print(f"✓ 特效配置已更新: {self.effect_config}")
except Exception as e:
print(f"✗ 特效配置设置失败: {e}")
def get_effect_config(self) -> Dict[str, Any]:
"""
获取特效配置
Returns:
特效配置字典
"""
return self.effect_config.copy()
def get_render_state(self) -> Dict[str, Any]:
"""
获取渲染状态
Returns:
渲染状态字典
"""
return self.render_state.copy()
def get_performance_stats(self) -> Dict[str, Any]:
"""
获取性能统计信息
Returns:
性能统计字典
"""
return self.performance_stats.copy()
def reset_performance_stats(self):
"""重置性能统计信息"""
try:
self.performance_stats = {
'render_calls': 0,
'render_time_total': 0.0,
'average_render_time': 0.0,
'particles_drawn': 0,
'volume_samples': 0
}
print("✓ 性能统计信息已重置")
except Exception as e:
print(f"✗ 性能统计信息重置失败: {e}")
def update_camera_state(self, position: tuple, view_matrix: Any = None,
projection_matrix: Any = None, fov: float = 60.0):
"""
更新相机状态
Args:
position: 相机位置
view_matrix: 视图矩阵
projection_matrix: 投影矩阵
fov: 视野角度
"""
try:
self.camera_state['position'] = position
self.camera_state['view_matrix'] = view_matrix
self.camera_state['projection_matrix'] = projection_matrix
self.camera_state['fov'] = fov
except Exception as e:
print(f"✗ 相机状态更新失败: {e}")
def apply_post_processing(self, render_target: Any) -> Any:
"""
应用后处理效果
Args:
render_target: 渲染目标
Returns:
处理后的渲染目标
"""
try:
# 在实际实现中,这里会应用各种后处理效果
# 如抗锯齿、泛光、景深、运动模糊等
if self.effect_config['anti_aliasing'] != 'none':
render_target = self._apply_anti_aliasing(render_target)
if self.effect_config['bloom_enabled']:
render_target = self._apply_bloom(render_target)
if self.effect_config['motion_blur']:
render_target = self._apply_motion_blur(render_target)
if self.effect_config['depth_of_field']:
render_target = self._apply_depth_of_field(render_target)
return render_target
except Exception as e:
print(f"✗ 后处理应用失败: {e}")
return render_target
def _apply_anti_aliasing(self, render_target: Any) -> Any:
"""
应用抗锯齿
Args:
render_target: 渲染目标
Returns:
处理后的渲染目标
"""
try:
# 在实际实现中这里会应用FXAA、SSAA或MSAA等抗锯齿技术
aa_type = self.effect_config['anti_aliasing']
print(f"✓ 应用抗锯齿: {aa_type}")
return render_target
except Exception as e:
print(f"✗ 抗锯齿应用失败: {e}")
return render_target
def _apply_bloom(self, render_target: Any) -> Any:
"""
应用泛光效果
Args:
render_target: 渲染目标
Returns:
处理后的渲染目标
"""
try:
# 在实际实现中,这里会应用泛光效果
intensity = self.effect_config['bloom_intensity']
print(f"✓ 应用泛光效果 (强度: {intensity})")
return render_target
except Exception as e:
print(f"✗ 泛光效果应用失败: {e}")
return render_target
def _apply_motion_blur(self, render_target: Any) -> Any:
"""
应用运动模糊
Args:
render_target: 渲染目标
Returns:
处理后的渲染目标
"""
try:
# 在实际实现中,这里会应用运动模糊效果
samples = self.effect_config['motion_blur_samples']
print(f"✓ 应用运动模糊 ({samples} 采样)")
return render_target
except Exception as e:
print(f"✗ 运动模糊应用失败: {e}")
return render_target
def _apply_depth_of_field(self, render_target: Any) -> Any:
"""
应用景深效果
Args:
render_target: 渲染目标
Returns:
处理后的渲染目标
"""
try:
# 在实际实现中,这里会应用景深效果
focus_distance = self.effect_config['dof_focus_distance']
print(f"✓ 应用景深效果 (焦点距离: {focus_distance})")
return render_target
except Exception as e:
print(f"✗ 景深效果应用失败: {e}")
return render_target
def calculate_fluid_lighting(self, position: tuple, normal: tuple) -> tuple:
"""
计算流体光照
Args:
position: 位置
normal: 法线
Returns:
光照颜色 (r, g, b)
"""
try:
# 获取光照配置
ambient = self.lighting_config['ambient_light']
diffuse = self.lighting_config['diffuse_light']
specular = self.lighting_config['specular_light']
light_dir = self.lighting_config['light_direction']
# 获取材质属性
material_color = self.material_properties['color'][:3] # RGB
specular_color = self.material_properties['specular_color']
shininess = self.material_properties['shininess']
# 简化的光照计算
# 环境光
ambient_contrib = (
ambient[0] * material_color[0],
ambient[1] * material_color[1],
ambient[2] * material_color[2]
)
# 漫反射光
# 归一化法线和光线方向
norm_normal = np.array(normal) / np.linalg.norm(normal)
norm_light_dir = np.array(light_dir) / np.linalg.norm(light_dir)
# 计算漫反射因子
diffuse_factor = max(0.0, np.dot(norm_normal, norm_light_dir))
diffuse_contrib = (
diffuse_factor * diffuse[0] * material_color[0],
diffuse_factor * diffuse[1] * material_color[1],
diffuse_factor * diffuse[2] * material_color[2]
)
# 镜面反射光
specular_contrib = (0.0, 0.0, 0.0)
if diffuse_factor > 0:
# 计算反射向量 R = 2(N·L)N - L
reflect_dir = 2 * diffuse_factor * norm_normal - norm_light_dir
# 计算视线方向(简化为从原点到点的方向)
view_dir = np.array(position) / np.linalg.norm(position)
# 计算镜面反射因子
specular_factor = max(0.0, np.dot(reflect_dir, view_dir)) ** shininess
specular_contrib = (
specular_factor * specular[0] * specular_color[0],
specular_factor * specular[1] * specular_color[1],
specular_factor * specular[2] * specular_color[2]
)
# 合成最终颜色
final_color = (
ambient_contrib[0] + diffuse_contrib[0] + specular_contrib[0],
ambient_contrib[1] + diffuse_contrib[1] + specular_contrib[1],
ambient_contrib[2] + diffuse_contrib[2] + specular_contrib[2]
)
# 确保颜色值在有效范围内
final_color = (
max(0.0, min(1.0, final_color[0])),
max(0.0, min(1.0, final_color[1])),
max(0.0, min(1.0, final_color[2]))
)
return final_color
except Exception as e:
print(f"✗ 流体光照计算失败: {e}")
return (0.5, 0.5, 0.5)