Vibe Coding实践案例:油藏模型三维可视化系统
基于 C++/OpenSceneGraph 桌面端 + WebAssembly/Three.js Web 端的双架构油藏数值模拟三维可视化平台,支持亿级以上网格模型的高效加载、渲染与交互分析。
目录
- 项目简介
- 系统架构
- 功能清单
- 技术栈
- 项目结构
- 快速开始
- 数据格式
- 编译指南
- 运行说明
- 性能基准
- 关键技术
- 近期修复记录
- 常见问题
项目简介
本项目是一个面向油藏数值模拟领域的三维可视化系统,旨在解决亿级网格(1.04亿+单元格)油藏模型的高效可视化问题。系统采用双架构设计:
| 桌面端 | C++17 + OpenSceneGraph + Dear ImGui | 超大规模数据(亿级网格),本地高性能渲染 |
| Web端 | WebAssembly + Three.js + JavaScript | 中等规模数据(百万级网格),浏览器零安装访问 |
核心能力
- 支持 HiSim 格式油藏数值模拟数据(静态/动态属性、井轨迹)
- 外表面提取与渲染、切片视图、等值面分析
- 时间步动画播放(150步动态属性)
- 多颜色映射方案(Rainbow/Jet/Viridis 等)
- LOD 多级细节管理、数据分块加载、L1/L2 两级缓存
- 数据导出(PLY/glTF/GLB 格式)
系统架构
整体架构
┌──────────────────────────────────────────────────────────────────┐
│ 表示层 (Presentation) │
│ ┌─────────────────────┐ ┌──────────────────────────────────┐ │
│ │ 桌面端 (OSG+ImGui) │ │ Web端 (Three.js+WASM) │ │
│ │ – 菜单栏/属性面板 │ │ – 侧边栏控制面板 │ │
│ │ – 时间轴/性能监控 │ │ – 文件上传/切片控制 │ │
│ │ – OpenGL 渲染器 │ │ – WebGL 渲染器 │ │
│ └──────────┬──────────┘ └──────────────┬───────────────────┘ │
└─────────────┼──────────────────────────────┼─────────────────────┘
│ │
┌─────────────▼──────────────────────────────▼─────────────────────┐
│ 数据处理层 (Data Layer) │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ BinReader (二进制读取) → Gross2Net 映射 → 属性数据 │ │
│ │ XCOORD/YCOORD/DEPTH 坐标系统 → 顶点构建 → 网格几何体 │ │
│ └────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
数据流水线
HiSim 二进制文件 (_geom.bin / _stu.bin)
↓
BinReader (读取 + 解压 + Gross2Net 映射)
↓
属性数据 (net 顺序 → gross 顺序)
↓
坐标系统 (XCOORD / YCOORD / DEPTH + 不活跃单元线性插值)
↓
可视化引擎 (外表面 / 切片 / 等值面 / 属性着色)
功能清单
桌面端(C++/OSG)
| 数据管理 | 树形数据目录、按需加载、内存统计、搜索过滤、L1/L2缓存 | ✅ |
| 三维渲染 | 网格体渲染、属性着色、多颜色映射、透明度调节、外表面提取 | ✅ |
| 切片视图 | X/Y/Z方向切片、索引控制、透明度调节、剖切效果 | ✅ |
| 等值面 | Marching Cubes提取、等值面值调节、脏标记延迟计算、并行加速 | ✅ |
| 井轨迹 | 井轨迹线渲染、井口标注、线宽调节、井列表 | ✅ |
| 时间动画 | 150步动态属性播放、播放/暂停/停止、速度调节、时间线 | ✅ |
| 交互操作 | 视角旋转/平移/缩放、预设视角、右键菜单、网格拾取/筛选 | ✅ |
| 性能优化 | LOD多级细节、数据分块、帧率监控、采样因子可调 | ✅ |
| 数据导出 | PLY/glTF/GLB 格式导出 | ✅ |
Web端(WASM/Three.js)
| 数据加载 | 浏览器直接上传 _geom.bin + _stu.bin 文件 | ✅ |
| WASM解析 | Emscripten 编译的 C++ 模块,浏览器内解析油藏数据 | ✅ |
| 外表面渲染 | 网格外表面几何体构建与渲染 | ✅ |
| 切片视图 | X/Y/Z方向切片、属性着色、平滑过渡 | ✅ |
| 属性可视化 | PORV/PORO 等静态属性着色显示 | ✅ |
| 渲染优化 | 抗锯齿(MSAA)、ACES色调映射、多光源光照系统 | ✅ |
| 交互UI | 可折叠侧边栏、文件上传、网格信息展示、属性选择 | ✅ |
| 相机控制 | OrbitControls 旋转/缩放/平移 | ✅ |
技术栈
桌面端
| 编程语言 | C++ | C++17 |
| 渲染引擎 | OpenSceneGraph | 3.6.5+ |
| UI框架 | Dear ImGui | 1.89+ |
| 并行计算 | OpenMP | 5.0+ |
| 数学库 | Eigen | 3.4+ |
| 构建工具 | Visual Studio / CMake | 2019/2022, 3.16+ |
Web端
| 编程语言 | C++ → WebAssembly | C++17, Emscripten |
| 3D渲染 | Three.js | r169+ |
| 前端 | HTML5 + JavaScript (ES6+) | – |
| 构建工具 | Emscripten SDK | latest |
| HTTP服务 | Python http.server / Node.js | – |
项目结构
3DVisualizationOfReservoirsHisim/
├── include/ # C++ 头文件
│ ├── BinReader.h # 二进制数据读取
│ ├── HiSimParser.h # HiSim 格式解析
│ ├── SliceView.h # 切片视图
│ ├── Isosurface.h # 等值面提取
│ ├── PropertyVisualizer.h # 属性可视化
│ ├── AnimationManager.h # 时间动画管理
│ ├── WellTrajectory.h # 井轨迹渲染
│ ├── LODManager.h # LOD 管理
│ ├── DataCache.h # L1/L2 数据缓存
│ ├── SurfaceExtractor.h # 表面提取
│ ├── PlyExporter.h # PLY 导出
│ ├── GltfExporter.h # glTF 导出
│ └── … # 其他模块
├── src/ # C++ 源文件
│ ├── main.cpp # 主程序入口 (~4500行)
│ ├── BinReader.cpp # 数据读取实现
│ ├── SliceView.cpp # 切片视图实现
│ ├── Isosurface.cpp # 等值面实现
│ ├── HiSimParser.cpp # HiSim 解析实现
│ ├── SurfaceExtractor.cpp # 表面提取实现
│ └── … # 其他实现
├── wasm/ # WebAssembly 模块
│ ├── src/
│ │ ├── main.cpp # WASM 主入口(坐标加载/映射)
│ │ └── pre.js # WASM 预加载脚本
│ ├── dist/
│ │ ├── reservoir.js # 编译后的 JS 胶水代码
│ │ └── reservoir.wasm # 编译后的 WASM 二进制
│ ├── test/
│ │ ├── test.html # Web 可视化测试页面
│ │ ├── data/ # 测试数据
│ │ └── src/ # Web 端辅助模块
│ ├── test.html # Web 可视化页面(根目录)
│ └── build_wasm.bat # WASM 编译脚本
├── web_preview/ # 轻量级 Web 预览(glTF 加载)
│ ├── index.html # 预览页面
│ ├── viewer.js # Three.js 查看器
│ ├── three/ # Three.js 库文件
│ └── …
├── tests/ # 测试文件
├── docs/ # 设计文档与技术文档
├── doc/ # 截图与演示素材
├── build_nmake/ # CMake 构建输出
├── SUMMARY.md # WASM 修复总结
└── README.md # 本文件
快速开始
方式一:Web端运行(推荐快速体验)
前置条件:安装 Python 3.x 或 Node.js
# 1. 编译 WASM 模块(如需更新)
cd wasm
.\\build_wasm.bat
# 2. 启动 HTTP 服务器
cd ..
python –m http.server 8080
# 3. 浏览器访问
# http://localhost:8080/wasm/
使用流程:


方式二:桌面端运行(处理超大规模数据)
前置条件:Visual Studio 2019/2022 + OpenSceneGraph 3.6.5+
# 1. 编译项目
cd build_nmake
msbuild OilReservoirVisualization.sln /p:Configuration=Release /p:Platform=x64 /m
# 2. 运行
.\\bin\\Release\\OilReservoirVisualization.exe
使用流程:

数据格式
HiSim 二进制格式
| *_geom.bin | 静态网格参数 | 网格维度、坐标、属性(PORO/PERMX等) |
| *_stu.bin | 动态网格参数 | 时间步数据(POIL/SOIL/SWAT等) |
| *_wstu.out | 井筒数据 | 井轨迹、井口坐标 |
关键数据结构
| GRIDINFO | 网格维度信息(ni, nj, nk) |
| Gross2Net | Gross→Net 索引映射(活跃/不活跃单元) |
| XCOORD/YCOORD/DEPTH | 顶点坐标数组 |
| GRID_VTX | 网格顶点数据 |
| PORV/PORO/PERMX/PERMZ | 静态属性 |
| POIL/SOIL/SWAT/SCFIP | 动态属性 |
编译指南
WASM 模块编译
前置条件:安装 Emscripten SDK
cd wasm
.\\build_wasm.bat
编译产物输出到 wasm/dist/ 目录:
- reservoir.js – JS 胶水代码
- reservoir.wasm – WASM 二进制模块
桌面端编译
环境要求:
| 操作系统 | Windows 10/11 |
| 编译器 | Visual Studio 2019/2022 |
| OpenGL | 3.3+ |
| 内存 | 建议 16GB 以上 |
| 显卡 | NVIDIA/AMD 独立显卡 |
依赖安装:
编译步骤:
:: 方法1:Visual Studio IDE
:: 打开 build_nmake\\OilReservoirVisualization.sln → Release x64 → 编译
:: 方法2:命令行
cd build_nmake
msbuild OilReservoirVisualization.sln /p:Configuration=Release /p:Platform=x64 /m
运行说明
快捷键(桌面端)
| H | 重置视角 |
| ESC | 退出程序 |
| Ctrl + 点击 | 多选节点 |
| Shift + 点击 | 范围选择 |

Web端操作
| 鼠标左键拖拽 | 旋转模型 |
| 鼠标滚轮 | 缩放 |
| 鼠标右键拖拽 | 平移 |
| 侧边栏切换按钮 | 显示/隐藏控制面板 |
性能基准
桌面端(data3 数据集,1.04亿网格)
| 网格维度 | 588 × 328 × 560 | gross: 108,003,840 / net: 102,790,320 |
| 表面提取时间 | ~3秒 | 采样因子=3 |
| 等值面计算时间 | ~2秒 | 粗网格 196×109×187 |
| 帧率 | 30-60 FPS | RTX 3060 |
| 总数据量 | 118.4 GB | 174个节点 |
Web端(data0 数据集,112万网格)
| 网格维度 | 60 × 220 × 85 |
| 总单元格 | 1,122,000 |
| 顶点数 | 1,159,366 |
| 几何文件 | 203 MB |
| 动态文件 | 552 MB |
| 加载时间 | ~10秒 |
| 帧率 | 60 FPS |
关键技术
1. Gross2Net 映射与坐标插值
油藏模型中并非所有网格单元都是活跃的。系统通过 Gross2Net 映射表区分活跃/不活跃单元:
- 活跃单元:直接从 XCOORD/YCOORD/DEPTH 数组读取坐标
- 不活跃单元:基于活跃单元的真实坐标范围进行线性插值,确保回退坐标与真实数据范围一致
// 不活跃单元线性插值(wasm/src/main.cpp)
cellX[grossIdx] = activeXMin + (double)i / (ni – 1) * xRange;
cellY[grossIdx] = activeYMin + (double)j / (nj – 1) * yRange;
cellZ[grossIdx] = activeZMin + (double)k / (nk – 1) * zRange;
2. 脏标记延迟计算(等值面)
等值面采用脏标记机制避免重复计算,仅在参数变化时重新计算:
void setIsovalue(double v) {
if (m_isovalue != v) { m_isovalue = v; m_dirty = true; }
}
void refresh() {
if (!m_dirty) return;
computeIsosurface();
m_dirty = false;
}
3. L1/L2 两级缓存
| L1 | 内存 | LRU | 高频属性数据快速访问 |
| L2 | 磁盘 (.l2cache) | 自动回填 | 跨会话数据持久化 |
4. Web端渲染优化
- 抗锯齿:antialias: true + setPixelRatio(min(devicePixelRatio, 2))
- 色调映射:ACESFilmicToneMapping + toneMappingExposure = 1.2
- 光照系统:环境光 + 半球光 + 双方向光,增强立体感
- 侧边栏:CSS transform 过渡动画,支持显示/隐藏切换
近期修复记录
Web端(WASM/Three.js)
| 模型渲染为三角形 | GRID_VTX stride 计算错误 | 使用 XCOORD/YCOORD/DEPTH + Gross2Net 映射 |
| 浏览器卡死 | 点云渲染过多顶点 | 移除 createPointCloud 调用 |
| 坐标数组越界 | getCoord 索引越界 | 添加边界检查和安全索引 |
| 外表面条状几何体 | 不活跃单元回退坐标范围不匹配 | 活跃单元范围线性插值 |
| 切片渲染错误 | createSliceGeometry 重构引入 bug | 回退到内联实现版本 |
桌面端(C++/OSG)
| 切片属性值全为0 | remap 参数错误 + NaN填充 + 精度污染 | 修正 remap=false、改 0.0 填充、恢复精度 |
| 等值面稀疏面片 | 双重降采样 | 强制 Full 策略 |
| 等值面崩溃(UAF) | 裸指针被渲染线程持有 | 改为 ref_ptr + 互斥锁 |
| 表面提取零外表面 | FaceKey 匹配失败 | 改用邻域检查法 |
常见问题
编译问题
Q:WASM 编译失败? A:确保 Emscripten SDK 已正确安装并激活,运行 emsdk activate latest && emsdk_env.bat。
Q:桌面端 MSBuild Access Violation? A:VS2022 环境问题,请在 VS2022 Developer Command Prompt 中手动编译。
Q:链接错误 LNK2019? A:检查 OSG 的 lib 目录配置,确保使用 x64 版本。
运行时问题
Q:Web端加载数据后模型显示异常? A:确保同时上传 _geom.bin 和 _stu.bin 文件,检查浏览器控制台日志中的坐标范围信息。
Q:桌面端切片显示 [0, 0]? A:已修复,请使用最新代码编译。
Q:内存占用过高? A:系统采用按需加载,未加载的属性不占内存。可通过采样因子降低渲染负载。



