PyVista三维战场仿真实战

1. 内容概述与知识点设计

本篇博客将全面介绍使用PyVista进行三维战场仿真的完整技术栈。我们将从基础概念开始,逐步深入到高级特效实现,最终构建一个完整的动态海战仿真系统。

1.1 内容大纲

  • PyVista基础与环境配置

  • 真实感地形生成技术

  • 军事单位精细化建模

  • 动态海洋效果实现

  • 多视角相机控制系统

  • 完整战场仿真系统集成

1.2 核心知识点

通过本博客,您将掌握以下关键技术点:

  • PyVista网格数据处理与可视化

  • 基于噪声算法的地形生成

  • 军事单位三维建模与动画

  • 实时海洋波动模拟

  • 相机路径规划与视角控制

  • 大规模战场场景优化

2. PyVista技术深度解析

2.1 PyVista架构概述

PyVista是建立在VTK(Visualization Toolkit)之上的Python三维可视化库,它提供了简洁的API接口,同时保留了VTK的强大功能。PyVista的核心数据结构是网格(Mesh),它可以表示点云、曲面、体积等各种三维数据。

python 复制代码
import pyvista as pv
import numpy as np

class PyVistaCoreConcepts:
    """PyVista核心概念详解"""
    
    def demonstrate_mesh_concepts(self):
        """展示PyVista网格基本概念"""
        
        # 创建基本几何体
        sphere = pv.Sphere()
        print(f"球体网格信息:")
        print(f"点数: {sphere.n_points}")
        print(f"单元数: {sphere.n_cells}")
        print(f"边界范围: {sphere.bounds}")
        
        # 访问点数据
        points = sphere.points
        print(f"前5个点坐标:\n{points[:5]}")
        
        # 访问单元数据
        cells = sphere.cells
        print(f"单元连接信息:\n{cells[:10]}")
        
        return sphere

2.2 PyVista绘图系统深度解析

PyVista的绘图系统基于Plotter类,它提供了丰富的可视化选项和交互功能。

python 复制代码
class AdvancedPlotterSystem:
    """高级绘图器系统详解"""
    
    def __init__(self):
        self.plotter = None
        
    def create_advanced_plotter(self):
        """创建高级绘图器"""
        self.plotter = pv.Plotter(
            window_size=[1600, 900],
            lighting="three_lights",
            multi_samples=8,  # 多重采样抗锯齿
            polygon_smoothing=True,
            line_smoothing=True
        )
        
        # 设置高级渲染参数
        self.plotter.enable_anti_aliasing('ssaa')
        self.plotter.enable_depth_peeling()
        
        return self.plotter
    
    def setup_advanced_lighting(self):
        """设置高级光照系统"""
        # 添加多个光源
        self.plotter.add_light(pv.Light(
            position=(5, 5, 5),
            focal_point=(0, 0, 0),
            color='white',
            intensity=0.6
        ))
        
        self.plotter.add_light(pv.Light(
            position=(-5, -5, 5),
            focal_point=(0, 0, 0),
            color='blue',
            intensity=0.3
        ))

3. 地形生成技术

3.1 多频噪声地形生成

使用多频率Perlin噪声生成高度真实的地形。

python 复制代码
class RealisticTerrainGenerator:
    """真实感地形生成器"""
    
    def __init__(self, size=1000, resolution=256):
        self.size = size
        self.resolution = resolution
        self.terrain = None
        
    def generate_perlin_noise(self, x, y, frequency=1.0, octaves=4):
        """生成Perlin噪声"""
        value = 0.0
        amplitude = 1.0
        max_value = 0.0
        
        for _ in range(octaves):
            # 简化版Perlin噪声
            noise_val = np.sin(frequency * x * 0.01 + 
                             np.cos(frequency * y * 0.01)) * \
                       np.cos(frequency * y * 0.01 - 
                             np.sin(frequency * x * 0.01))
            value += amplitude * noise_val
            max_value += amplitude
            amplitude *= 0.5
            frequency *= 2.0
            
        return value / max_value
    
    def create_realistic_terrain(self):
        """创建真实感地形"""
        x = np.linspace(-self.size/2, self.size/2, self.resolution)
        y = np.linspace(-self.size/2, self.size/2, self.resolution)
        x, y = np.meshgrid(x, y)
        
        # 多频率噪声叠加
        z_low_freq = self.generate_perlin_noise(x, y, frequency=0.5, octaves=2)
        z_med_freq = self.generate_perlin_noise(x, y, frequency=2.0, octaves=3) * 0.5
        z_high_freq = self.generate_perlin_noise(x, y, frequency=8.0, octaves=4) * 0.2
        
        # 组合噪声
        z = z_low_freq * 200 + z_med_freq * 50 + z_high_freq * 10
        
        # 添加侵蚀效果
        z = self.apply_erosion_effect(z)
        
        # 创建地形网格
        self.terrain = pv.StructuredGrid(x, y, z)
        
        # 计算地形属性
        self.calculate_terrain_attributes()
        
        return self.terrain
    
    def apply_erosion_effect(self, z):
        """应用侵蚀效果"""
        from scipy import ndimage
        
        # 模拟水力侵蚀
        slope = np.gradient(z)
        erosion_mask = np.sqrt(slope[0]**2 + slope[1]**2) > 0.1
        z[erosion_mask] -= 2.0
        
        # 平滑处理
        z = ndimage.gaussian_filter(z, sigma=1.0)
        
        return z
    
    def calculate_terrain_attributes(self):
        """计算地形属性"""
        if self.terrain is None:
            return
            
        z = self.terrain.points[:, 2].reshape(self.resolution, self.resolution)
        
        # 计算坡度
        grad_x, grad_y = np.gradient(z)
        slope = np.sqrt(grad_x**2 + grad_y**2)
        self.terrain["slope"] = slope.flatten()
        
        # 计算朝向(用于军事分析)
        aspect = np.arctan2(grad_y, grad_x)
        self.terrain["aspect"] = aspect.flatten()
        
        # 计算通视性
        self.terrain["visibility"] = self.calculate_visibility(z)
    
    def calculate_visibility(self, elevation):
        """计算地形通视性"""
        visibility = np.ones_like(elevation)
        height, width = elevation.shape
        
        # 简化的通视性计算
        for i in range(10, height-10):
            for j in range(10, width-10):
                # 检查周围地形遮挡
                local_region = elevation[i-5:i+5, j-5:j+5]
                if elevation[i,j] < np.max(local_region) - 5:
                    visibility[i,j] = 0.3  # 低通视性
                elif elevation[i,j] > np.max(local_region) + 10:
                    visibility[i,j] = 1.5  # 高通视性(制高点)
                    
        return visibility.flatten()

3.2 纹理映射与材质系统

为地形添加真实的纹理和材质。

python 复制代码
class TerrainTextureSystem:
    """地形纹理系统"""
    
    def __init__(self, terrain):
        self.terrain = terrain
        self.textures = {}
        
    def create_texture_based_on_elevation(self):
        """基于高程创建纹理"""
        elevation = self.terrain["elevation"]
        slope = self.terrain["slope"]
        
        # 基于高程和坡度的纹理映射
        texture = np.zeros((len(elevation), 3))  # RGB纹理
        
        for i, (elev, slp) in enumerate(zip(elevation, slope)):
            if elev < 0:  # 水下
                texture[i] = [0.1, 0.2, 0.6]  # 深蓝色
            elif elev < 50:  # 海滩
                texture[i] = [0.9, 0.8, 0.6]  # 沙色
            elif slp > 0.3:  # 陡坡
                texture[i] = [0.4, 0.4, 0.4]  # 岩石灰色
            elif elev > 200:  # 高山
                texture[i] = [0.8, 0.8, 0.8]  # 雪白色
            else:  # 平原
                texture[i] = [0.3, 0.6, 0.3]  # 绿色
        
        self.terrain["texture"] = texture
        
    def add_satellite_texture(self, texture_file=None):
        """添加卫星纹理"""
        if texture_file is None:
            # 创建模拟卫星纹理
            self.create_simulated_satellite_texture()
        else:
            # 加载真实卫星纹理
            texture = pv.read_texture(texture_file)
            self.terrain.textures["satellite"] = texture
    
    def create_simulated_satellite_texture(self):
        """创建模拟卫星纹理"""
        # 基于地形属性生成模拟纹理
        elevation = self.terrain["elevation"]
        vegetation = np.sin(elevation * 0.1) * 0.5 + 0.5  # 模拟植被
        
        texture_rgb = np.zeros((len(elevation), 3))
        for i, (elev, veg) in enumerate(zip(elevation, vegetation)):
            if elev < 0:
                texture_rgb[i] = [0, 0, 0.5]  # 水体
            else:
                # 植被覆盖度影响颜色
                green = 0.3 + veg * 0.5
                texture_rgb[i] = [0.1, green, 0.1]
        
        self.terrain["satellite_texture"] = texture_rgb

4. 军事单位建模

4.1 海军舰船建模系统

创建各种类型的海军舰船模型。

python 复制代码
class NavalUnitFactory:
    """海军单位工厂"""
    
    @staticmethod
    def create_destroyer(position, scale=1.0):
        """创建驱逐舰模型"""
        # 舰体主体
        hull = pv.Cylinder(
            center=[0, 0, 0.1*scale], 
            direction=[1, 0, 0],
            radius=0.3*scale, 
            height=2.0*scale
        )
        
        # 舰桥
        bridge = pv.Cube(
            center=[0.5*scale, 0, 0.8*scale],
            x_length=0.4*scale,
            y_length=0.6*scale, 
            z_length=0.8*scale
        )
        
        # 炮塔
        turret = pv.Cylinder(
            center=[-0.5*scale, 0, 0.4*scale],
            direction=[0, 0, 1],
            radius=0.15*scale,
            height=0.2*scale
        )
        
        # 雷达
        radar = pv.Cone(
            center=[0, 0, 1.2*scale],
            direction=[0, 0, 1],
            height=0.3*scale,
            radius=0.1*scale
        )
        
        # 组合所有部件
        destroyer = hull + bridge + turret + radar
        destroyer.translate(position)
        
        return destroyer
    
    @staticmethod
    def create_aircraft_carrier(position, scale=1.0):
        """创建航空母舰模型"""
        # 甲板
        deck = pv.Cube(
            center=[0, 0, 0.2*scale],
            x_length=4.0*scale,
            y_length=1.0*scale,
            z_length=0.1*scale
        )
        
        # 岛式上层建筑
        island = pv.Cube(
            center=[1.0*scale, 0, 0.6*scale],
            x_length=0.8*scale,
            y_length=0.3*scale, 
            z_length=0.8*scale
        )
        
        # 飞行甲板标记
        runway_lines = []
        for i in range(5):
            line = pv.Cube(
                center=[-1.0*scale + i*0.5*scale, 0, 0.21*scale],
                x_length=0.02*scale,
                y_length=0.8*scale,
                z_length=0.02*scale
            )
            runway_lines.append(line)
        
        carrier = deck + island
        for line in runway_lines:
            carrier += line
            
        carrier.translate(position)
        return carrier
    
    @staticmethod
    def create_submarine(position, scale=1.0):
        """创建潜艇模型"""
        # 艇体(椭球体)
        hull = pv.ParametricEllipsoid(
            0.8*scale, 0.2*scale, 0.2*scale
        )
        
        # 指挥塔
        sail = pv.Cylinder(
            center=[0, 0, 0.15*scale],
            direction=[0, 0, 1],
            radius=0.1*scale,
            height=0.3*scale
        )
        
        submarine = hull + sail
        submarine.translate(position)
        return submarine

4.2 军事单位管理系统

实现军事单位的创建、管理和动画控制。

python 复制代码
class MilitaryUnitManager:
    """军事单位管理器"""
    
    def __init__(self, plotter):
        self.plotter = plotter
        self.units = []
        self.unit_meshes = {}
        self.animations = []
        
    def add_naval_unit(self, unit_type, position, faction="blue", scale=1.0):
        """添加海军单位"""
        if unit_type == "destroyer":
            unit_mesh = NavalUnitFactory.create_destroyer(position, scale)
        elif unit_type == "carrier":
            unit_mesh = NavalUnitFactory.create_aircraft_carrier(position, scale)
        elif unit_type == "submarine":
            unit_mesh = NavalUnitFactory.create_submarine(position, scale)
        else:
            unit_mesh = NavalUnitFactory.create_destroyer(position, scale)
        
        # 设置单位颜色
        color = "darkblue" if faction == "blue" else "darkred"
        actor = self.plotter.add_mesh(
            unit_mesh, 
            color=color,
            smooth_shading=True,
            metallic=0.3,
            roughness=0.7
        )
        
        unit_info = {
            'id': len(self.units),
            'type': unit_type,
            'faction': faction,
            'position': np.array(position),
            'mesh': unit_mesh,
            'actor': actor,
            'scale': scale,
            'waypoints': [],
            'current_speed': 0.0
        }
        
        self.units.append(unit_info)
        self.unit_meshes[unit_info['id']] = unit_mesh
        
        return unit_info
    
    def add_unit_waypoints(self, unit_id, waypoints):
        """为单位添加路径点"""
        if unit_id < len(self.units):
            self.units[unit_id]['waypoints'] = waypoints
    
    def update_units_movement(self, delta_time):
        """更新单位移动"""
        for unit in self.units:
            if len(unit['waypoints']) > 0:
                self.move_toward_waypoint(unit, delta_time)
    
    def move_toward_waypoint(self, unit, delta_time):
        """向路径点移动"""
        current_pos = unit['position']
        target_pos = unit['waypoints'][0]
        
        direction = target_pos - current_pos
        distance = np.linalg.norm(direction)
        
        if distance < 1.0:  # 到达路径点
            unit['waypoints'].pop(0)
            if len(unit['waypoints']) == 0:
                unit['current_speed'] = 0.0
            return
        
        # 标准化方向向量
        if distance > 0:
            direction = direction / distance
        
        # 根据单位类型设置速度
        max_speed = 10.0 if unit['type'] == 'destroyer' else 5.0
        acceleration = 2.0
        
        # 加速或减速
        if distance > 10.0:
            unit['current_speed'] = min(unit['current_speed'] + acceleration * delta_time, max_speed)
        else:
            unit['current_speed'] = max(unit['current_speed'] - acceleration * delta_time, 0)
        
        # 计算移动距离
        move_distance = unit['current_speed'] * delta_time
        if move_distance > distance:
            move_distance = distance
        
        # 更新位置
        new_position = current_pos + direction * move_distance
        unit['position'] = new_position
        
        # 更新网格位置
        translation = new_position - current_pos
        unit['mesh'].translate(translation, inplace=True)

5. 动态海洋效果实现

5.1 实时海面波动模拟

使用Gerstner波算法创建真实的海面波动效果。

python 复制代码
class DynamicOceanSystem:
    """动态海洋系统"""
    
    def __init__(self, size=2000, resolution=200):
        self.size = size
        self.resolution = resolution
        self.ocean_grid = None
        self.time = 0.0
        self.waves = []
        
        # 初始化波参数
        self.init_wave_parameters()
    
    def init_wave_parameters(self):
        """初始化波参数"""
        self.waves = [
            {'amplitude': 2.0, 'wavelength': 50.0, 'direction': [1.0, 0.5], 'speed': 2.0},
            {'amplitude': 1.5, 'wavelength': 30.0, 'direction': [0.7, -0.3], 'speed': 3.0},
            {'amplitude': 1.0, 'wavelength': 20.0, 'direction': [-0.5, 0.8], 'speed': 1.5}
        ]
        
        # 归一化方向向量
        for wave in self.waves:
            direction = np.array(wave['direction'])
            wave['direction'] = direction / np.linalg.norm(direction)
    
    def create_ocean_grid(self):
        """创建海洋网格"""
        x = np.linspace(-self.size/2, self.size/2, self.resolution)
        y = np.linspace(-self.size/2, self.size/2, self.resolution)
        x, y = np.meshgrid(x, y)
        z = np.zeros_like(x)
        
        self.ocean_grid = pv.StructuredGrid(x, y, z)
        self.ocean_grid["elevation"] = z.flatten()
        
        return self.ocean_grid
    
    def update_ocean_waves(self, delta_time):
        """更新海洋波动"""
        if self.ocean_grid is None:
            return
            
        self.time += delta_time
        
        x = self.ocean_grid.points[:, 0].reshape(self.resolution, self.resolution)
        y = self.ocean_grid.points[:, 1].reshape(self.resolution, self.resolution)
        z = np.zeros_like(x)
        
        # 叠加多个波
        for wave in self.waves:
            k = 2 * np.pi / wave['wavelength']  # 波数
            omega = wave['speed'] * k  # 角频率
            
            # 计算波方向上的位置
            dir_array = np.array(wave['direction'])
            dot_product = x * dir_array[0] + y * dir_array[1]
            
            # Gerstner波公式
            wave_height = wave['amplitude'] * np.sin(k * dot_product - omega * self.time)
            z += wave_height
            
            # 添加波峰尖锐效果
            steepness = 0.3
            z += steepness * wave['amplitude'] * np.cos(k * dot_product - omega * self.time)
        
        # 更新网格高度
        self.ocean_grid.points[:, 2] = z.flatten()
        self.ocean_grid["elevation"] = z.flatten()
    
    def create_foam_effect(self, threshold=0.5):
        """创建泡沫效果"""
        if self.ocean_grid is None:
            return
            
        elevation = np.abs(self.ocean_grid["elevation"])
        foam_mask = elevation > threshold
        
        # 创建泡沫纹理
        foam_texture = np.zeros((len(elevation), 3))
        foam_texture[foam_mask] = [1.0, 1.0, 1.0]  # 白色泡沫
        foam_texture[~foam_mask] = [0.1, 0.2, 0.8]  # 蓝色海水
        
        self.ocean_grid["foam_texture"] = foam_texture
    
    def add_ocean_to_plotter(self, plotter):
        """将海洋添加到绘图器"""
        if self.ocean_grid is not None:
            plotter.add_mesh(
                self.ocean_grid,
                scalars="elevation",
                cmap="ocean",
                opacity=0.8,
                smooth_shading=True,
                show_edges=False
            )

5.2 海洋材质与反射效果

增强海洋的视觉真实感。

python 复制代码
class OceanMaterialSystem:
    """海洋材质系统"""
    
    def __init__(self, ocean_grid):
        self.ocean_grid = ocean_grid
        
    def apply_advanced_material(self):
        """应用高级材质"""
        # 创建法线贴图效果
        self.create_normal_map()
        
        # 创建反射效果
        self.create_reflection_map()
    
    def create_normal_map(self):
        """创建法线贴图"""
        if self.ocean_grid is None:
            return
            
        elevation = self.ocean_grid["elevation"].reshape(-1, 1)
        
        # 简化法线计算
        points = self.ocean_grid.points
        normals = np.zeros_like(points)
        
        # 计算简单法线(实际应用需要更复杂的计算)
        for i in range(1, len(points)-1):
            if i % self.ocean_grid.dimensions[0] != 0:  # 不是左边界
                dx = points[i] - points[i-1]
            else:
                dx = points[i+1] - points[i]
                
            if i >= self.ocean_grid.dimensions[0]:  # 不是上边界
                dy = points[i] - points[i-self.ocean_grid.dimensions[0]]
            else:
                dy = points[i+self.ocean_grid.dimensions[0]] - points[i]
            
            # 计算法线
            normal = np.cross(dx, dy)
            if np.linalg.norm(normal) > 0:
                normal = normal / np.linalg.norm(normal)
            normals[i] = normal
        
        self.ocean_grid["normals"] = normals
    
    def create_reflection_map(self):
        """创建反射贴图"""
        # 基于视角和法线计算反射强度
        if hasattr(self.ocean_grid, 'normals'):
            normals = self.ocean_grid["normals"]
            
            # 简化反射计算
            reflection = np.zeros(len(normals))
            for i, normal in enumerate(normals):
                # 假设光源在摄像机位置
                reflection[i] = max(0, normal[2])  # 使用法线的Z分量
                
            self.ocean_grid["reflection"] = reflection

6. 相机控制系统

6.1 多视角相机设置

实现多种相机视角控制模式。

python 复制代码
class BattlefieldCameraSystem:
    """战场相机控制系统"""
    
    def __init__(self, plotter):
        self.plotter = plotter
        self.camera_modes = {
            'overview': self.set_overview_camera,
            'first_person': self.set_first_person_camera,
            'follow_unit': self.set_follow_unit_camera,
            'free_flight': self.set_free_flight_camera
        }
        self.current_mode = 'overview'
        self.follow_unit_id = None
        
    def set_overview_camera(self, terrain_bounds):
        """设置俯视视角"""
        # 计算地形中心
        center = [
            (terrain_bounds[0] + terrain_bounds[1]) / 2,
            (terrain_bounds[2] + terrain_bounds[3]) / 2,
            (terrain_bounds[4] + terrain_bounds[5]) / 2
        ]
        
        # 设置相机位置(高空俯视)
        camera_pos = [
            center[0],
            center[1], 
            terrain_bounds[5] * 3  # 高度的3倍
        ]
        
        self.plotter.camera_position = [
            camera_pos,
            center,
            (0, 0, 1)  # 上方向向量
        ]
    
    def set_first_person_camera(self, unit_position, unit_direction=None):
        """设置第一人称视角"""
        if unit_direction is None:
            unit_direction = [1, 0, 0]  # 默认朝X轴方向
        
        # 相机位置在单位上方
        camera_pos = unit_position + [0, 0, 2]  # 高度2米
        
        # 看向单位朝向方向
        focal_point = unit_position + unit_direction * 10
        
        self.plotter.camera_position = [
            camera_pos,
            focal_point,
            (0, 0, 1)
        ]
    
    def set_follow_unit_camera(self, unit_position, unit_velocity=None):
        """设置跟随单位视角"""
        if unit_velocity is None:
            unit_velocity = [1, 0, 0]
            
        # 归一化速度方向
        speed = np.linalg.norm(unit_velocity)
        if speed > 0:
            unit_direction = unit_velocity / speed
        else:
            unit_direction = [1, 0, 0]
        
        # 相机在单位后方上方
        camera_offset = np.array(unit_direction) * -10 + [0, 0, 5]
        camera_pos = unit_position + camera_offset
        
        self.plotter.camera_position = [
            camera_pos.tolist(),
            unit_position,
            (0, 0, 1)
        ]
    
    def set_free_flight_camera(self, position, focal_point):
        """设置自由飞行视角"""
        self.plotter.camera_position = [
            position,
            focal_point,
            (0, 0, 1)
        ]
    
    def create_camera_animation_path(self, start_pos, end_pos, num_points=100):
        """创建相机动画路径"""
        # 创建贝塞尔曲线路径
        t = np.linspace(0, 1, num_points)
        
        # 控制点(在中间位置添加高度)
        control_point = (start_pos + end_pos) / 2 + [0, 0, 50]
        
        # 二次贝塞尔曲线
        path_points = []
        for i in range(num_points):
            point = (1-t[i])**2 * start_pos + \
                   2*(1-t[i])*t[i] * control_point + \
                   t[i]**2 * end_pos
            path_points.append(point)
        
        return path_points
    
    def animate_camera_along_path(self, path_points, duration=10):
        """沿路径动画相机"""
        self.plotter.open_gif("camera_animation.gif", fps=30)
        
        num_frames = duration * 30
        frame_indices = np.linspace(0, len(path_points)-1, num_frames, dtype=int)
        
        for i, frame_idx in enumerate(frame_indices):
            if frame_idx < len(path_points):
                # 设置相机位置
                camera_pos = path_points[frame_idx]
                
                # 看向路径上的下一个点
                look_ahead_idx = min(frame_idx + 5, len(path_points)-1)
                focal_point = path_points[look_ahead_idx]
                
                self.set_free_flight_camera(camera_pos, focal_point)
                self.plotter.write_frame()
        
        self.plotter.close()

7. 战场仿真系统

7.1 主仿真引擎

集成所有组件的完整仿真系统。

python 复制代码
class BattlefieldSimulationEngine:
    """战场仿真引擎"""
    
    def __init__(self):
        self.plotter = None
        self.terrain = None
        self.ocean_system = None
        self.unit_manager = None
        self.camera_system = None
        self.is_running = False
        self.last_time = None
        
    def initialize_simulation(self):
        """初始化仿真系统"""
        print("初始化战场仿真系统...")
        
        # 创建高级绘图器
        self.plotter = pv.Plotter(window_size=[1920, 1080])
        self.plotter.set_background("skyblue", top="lightblue")
        
        # 创建地形系统
        terrain_gen = RealisticTerrainGenerator(size=2000, resolution=300)
        self.terrain = terrain_gen.create_realistic_terrain()
        
        # 创建海洋系统
        self.ocean_system = DynamicOceanSystem(size=2000, resolution=250)
        ocean_grid = self.ocean_system.create_ocean_grid()
        
        # 创建单位管理器
        self.unit_manager = MilitaryUnitManager(self.plotter)
        
        # 创建相机系统
        self.camera_system = BattlefieldCameraSystem(self.plotter)
        
        # 添加地形到场景
        self.plotter.add_mesh(
            self.terrain,
            scalars="elevation",
            cmap="gist_earth",
            opacity=0.9,
            smooth_shading=True
        )
        
        # 添加海洋到场景
        self.ocean_system.add_ocean_to_plotter(self.plotter)
        
        # 部署军事单位
        self.deploy_military_units()
        
        # 设置初始相机视角
        self.camera_system.set_overview_camera(self.terrain.bounds)
        
        print("仿真系统初始化完成!")
    
    def deploy_military_units(self):
        """部署军事单位"""
        # 蓝方舰队
        blue_fleet = [
            {"type": "carrier", "position": [-500, -200, 0], "faction": "blue"},
            {"type": "destroyer", "position": [-400, -100, 0], "faction": "blue"},
            {"type": "destroyer", "position": [-400, -300, 0], "faction": "blue"},
            {"type": "submarine", "position": [-600, -200, 0], "faction": "blue"}
        ]
        
        # 红方舰队
        red_fleet = [
            {"type": "carrier", "position": [500, 200, 0], "faction": "red"},
            {"type": "destroyer", "position": [400, 100, 0], "faction": "red"},
            {"type": "destroyer", "position": [400, 300, 0], "faction": "red"},
            {"type": "submarine", "position": [600, 200, 0], "faction": "red"}
        ]
        
        # 部署单位
        for unit_data in blue_fleet + red_fleet:
            self.unit_manager.add_naval_unit(
                unit_data["type"],
                unit_data["position"],
                unit_data["faction"],
                scale=10.0
            )
        
        # 设置单位移动路径
        self.set_unit_navigation_paths()
    
    def set_unit_navigation_paths(self):
        """设置单位导航路径"""
        # 蓝方单位路径
        blue_paths = [
            [(-500, -200, 0), (-300, -100, 0), (-100, -50, 0)],  # 航母路径
            [(-400, -100, 0), (-250, -50, 0), (-150, 0, 0)],     # 驱逐舰1路径
            [(-400, -300, 0), (-250, -200, 0), (-150, -100, 0)], # 驱逐舰2路径
        ]
        
        # 红方单位路径  
        red_paths = [
            [(500, 200, 0), (300, 150, 0), (100, 100, 0)],       # 航母路径
            [(400, 100, 0), (250, 50, 0), (150, 0, 0)],          # 驱逐舰1路径
            [(400, 300, 0), (250, 250, 0), (150, 200, 0)],       # 驱逐舰2路径
        ]
        
        # 为每个单位设置路径
        for i, path in enumerate(blue_paths + red_paths):
            if i < len(self.unit_manager.units):
                self.unit_manager.add_unit_waypoints(i, path)
    
    def run_simulation(self, duration=60):
        """运行仿真"""
        print(f"开始仿真,持续时间: {duration}秒")
        self.is_running = True
        self.last_time = time.time()
        
        start_time = time.time()
        
        while self.is_running and (time.time() - start_time) < duration:
            # 计算时间增量
            current_time = time.time()
            delta_time = current_time - self.last_time
            self.last_time = current_time
            
            # 更新系统
            self.update_simulation(delta_time)
            
            # 限制帧率
            time.sleep(0.016)  # 约60FPS
            
            # 检查用户输入(退出条件)
            if not self.plotter.iren.running:
                self.is_running = False
        
        print("仿真结束")
    
    def update_simulation(self, delta_time):
        """更新仿真状态"""
        # 更新海洋波动
        self.ocean_system.update_ocean_waves(delta_time)
        
        # 更新单位移动
        self.unit_manager.update_units_movement(delta_time)
        
        # 更新相机(如果处于跟随模式)
        self.update_camera_follow()
        
        # 刷新显示
        self.plotter.update()
    
    def update_camera_follow(self):
        """更新相机跟随"""
        if (self.camera_system.current_mode == 'follow_unit' and 
            self.camera_system.follow_unit_id is not None):
            
            unit_id = self.camera_system.follow_unit_id
            if unit_id < len(self.unit_manager.units):
                unit = self.unit_manager.units[unit_id]
                self.camera_system.set_follow_unit_camera(
                    unit['position'],
                    unit.get('velocity', [1, 0, 0])
                )
    
    def interactive_control(self):
        """交互式控制"""
        print("交互式控制模式")
        print("快捷键:")
        print("  O - 俯视视角")
        print("  F - 第一人称视角") 
        print("  C - 跟随相机")
        print("  R - 自由飞行")
        print("  Q - 退出")
        
        # 设置键盘回调
        self.plotter.add_key_event("o", lambda: self.camera_system.set_overview_camera(self.terrain.bounds))
        self.plotter.add_key_event("f", self.set_first_person_view)
        self.plotter.add_key_event("c", self.set_follow_view)
        self.plotter.add_key_event("r", self.set_free_view)
        self.plotter.add_key_event("q", lambda: setattr(self, 'is_running', False))
    
    def set_first_person_view(self):
        """设置第一人称视角"""
        if len(self.unit_manager.units) > 0:
            unit_pos = self.unit_manager.units[0]['position']
            self.camera_system.set_first_person_camera(unit_pos)
            self.camera_system.current_mode = 'first_person'
    
    def set_follow_view(self):
        """设置跟随视角"""
        if len(self.unit_manager.units) > 0:
            self.camera_system.follow_unit_id = 0
            self.camera_system.current_mode = 'follow_unit'
    
    def set_free_view(self):
        """设置自由视角"""
        self.camera_system.current_mode = 'free_flight'
    
    def show_simulation(self):
        """显示仿真"""
        self.interactive_control()
        self.plotter.show()

7.2 完整可运行Demo

python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PyVista三维战场仿真完整Demo
功能:真实地形生成、动态海洋、海军单位模拟、多视角控制
作者:基于用户反馈深度优化
日期:2026年1月18日
"""

import pyvista as pv
import numpy as np
import time

# 这里包含前面定义的所有类:
# RealisticTerrainGenerator, TerrainTextureSystem, 
# NavalUnitFactory, MilitaryUnitManager,
# DynamicOceanSystem, OceanMaterialSystem, 
# BattlefieldCameraSystem, BattlefieldSimulationEngine

def main():
    """主函数"""
    print("=" * 60)
    print("PyVista三维海战场仿真系统")
    print("=" * 60)
    
    try:
        # 创建仿真引擎
        simulator = BattlefieldSimulationEngine()
        
        # 初始化仿真系统
        simulator.initialize_simulation()
        
        # 运行仿真(可选)
        print("开始运行仿真...")
        print("提示:使用鼠标进行交互查看")
        print("快捷键: O-俯视, F-第一人称, C-跟随, R-自由飞行, Q-退出")
        
        # 在单独的线程中运行仿真更新
        import threading
        simulation_thread = threading.Thread(
            target=simulator.run_simulation, 
            args=(300,)  # 运行300秒
        )
        simulation_thread.daemon = True
        simulation_thread.start()
        
        # 显示仿真界面
        simulator.show_simulation()
        
        print("仿真系统关闭")
        
    except Exception as e:
        print(f"错误: {str(e)}")
        import traceback
        traceback.print_exc()

if __name__ == "__main__":
    main()

8. 总结与扩展建议

本博客详细介绍了使用PyVista进行三维战场仿真的完整技术栈。通过实现真实感地形生成、动态海洋效果、军事单位建模和高级相机控制,我们构建了一个功能丰富的海战仿真系统。

8.1 技术亮点总结

  1. 真实感渲染:多频率噪声地形、动态海洋波动、高级材质系统

  2. 军事仿真:精细化海军单位建模、路径规划、实时运动控制

  3. 交互体验:多视角相机系统、键盘交互、实时动画

  4. 系统架构:模块化设计、可扩展的仿真引擎

8.2 性能优化建议

对于大规模战场仿真,可以考虑以下优化策略:

  • 使用层次细节(LOD)技术

  • 实现数据分块加载

  • 采用GPU加速计算

  • 优化网格数据结构和算法

8.3 扩展方向

  1. 人工智能集成:添加单位AI决策系统

  2. 物理引擎:集成刚体物理和碰撞检测

  3. 网络功能:实现多机协同仿真

  4. 数据驱动:接入真实地理和军事数据

复制代码
相关推荐
Aurora-Borealis.2 小时前
Day 38 GPU训练和call方法
python
深蓝电商API2 小时前
Scrapy爬虫部署到Scrapyd服务端详解
爬虫·python·scrapy
无垠的广袤2 小时前
【工业树莓派 CM0 NANO 单板计算机】YOLO26 部署方案
linux·python·opencv·yolo·树莓派·目标识别
董世昌412 小时前
HTTP协议中,GET和POST有什么区别?分别适用什么场景?
java·开发语言·前端
独自破碎E2 小时前
Java中HashMap的默认负载因子为什么设置为0.75?
java·开发语言·网络
STLearner2 小时前
AAAI 2026 | 时间序列(Time Series) 论文总结[下] (分类,异常检测,基础模型,表示学习,生成)
大数据·论文阅读·人工智能·python·深度学习·机器学习·数据挖掘
幽络源小助理2 小时前
SpringBoot+Vue大学城水电管理系统源码 | 后勤设备管理 | 幽络源
java·开发语言
闻林禹2 小时前
c++并发编程
开发语言·c++
科研鬼才(bushi2 小时前
项目文件夹规范
python