# HTMLCFD
**Repository Path**: tong_yan_jun/htmlcfd
## Basic Information
- **Project Name**: HTMLCFD
- **Description**: CFD页面交互效果,可在手机网页上访问
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: https://htmlcfd.vercel.app/
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-03-12
- **Last Updated**: 2026-03-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Fluid Simulation
基于 Navier-Stokes 方程的实时交互式 WebGL 流体模拟。
## 预览

通过鼠标/触摸滑动创建流体效果,小范围扰动产生精细涡结构。点击右上角按钮切换视觉风格,按钮同时作为流体壁面边界。
## 快速开始
### 安装依赖
```bash
npm install
```
### 开发模式
```bash
npm run dev
```
访问 http://localhost:5173
### 生产构建
```bash
npm run build
```
构建产物输出到 `dist/` 目录。
### 预览构建结果
```bash
npm run preview
```
## 使用方法
| 操作 | 效果 |
|------|------|
| **鼠标拖动** | 在小范围内创建流体扰动,产生精细涡结构 |
| **触摸滑动** | 移动端流体交互 |
| **点击右上角按钮** | 切换视觉风格(Navier 彩色 / Smoke 单色) |
> **壁面边界**:切换按钮同时作为流体壁面,流体经过按钮区域会绕开,模拟真实边界效果。
## 技术架构
### 物理管线
每帧执行以下步骤:
```
Advection → Splat → Divergence → Pressure (Jacobi 40x) → Projection → Render
```
| 步骤 | 作用 |
|------|------|
| **Advection** | 半拉格朗日平流,密度和速度随流场移动 |
| **Splat** | 注入鼠标速度作为外力 |
| **Divergence** | 计算速度场散度 ∇·u |
| **Pressure** | Jacobi 迭代求解压力场 |
| **Projection** | 速度场投影,满足不可压缩条件 |
### 文件结构
```
src/
├── main.ts # 入口,动画循环
├── core/
│ ├── WebGLContext.ts # WebGL 2.0 上下文 + 扩展检查
│ ├── FBO.ts # 帧缓冲双缓冲系统
│ └── ShaderLoader.ts # GLSL 编译工具
├── sim/
│ ├── FluidSimulator.ts # 物理管线编排
│ └── shaders/ # GLSL 着色器
│ ├── advection.frag # 平流
│ ├── splat.frag # 力注入
│ ├── divergence.frag # 散度
│ ├── jacobi.frag # 压力求解
│ └── project.frag # 速度投影
├── render/
│ └── styles/ # 视觉风格
│ ├── navier.frag # Navier.ai 彩色风格
│ └── smoke.frag # 烟雾/墨水风格
├── input/
│ └── PointerHandler.ts # 鼠标/触摸输入
└── config/
└── Config.ts # 物理参数配置
```
## 调试指南
### 常见问题
#### 1. 页面黑屏,无流体效果
**检查控制台错误:**
```javascript
// 打开浏览器开发者工具 (F12)
// 查看是否有 WebGL 相关错误
```
**可能原因:**
- 浏览器不支持 WebGL 2.0
- 显卡驱动问题
#### 2. 流体"爆炸"或闪烁
**调整物理参数:**
```typescript
// src/config/Config.ts
{
physics: {
dt: 0.008, // 减小时间步长
viscosity: 0.0001,
diffusion: 0.0001,
pressureIterations: 40 // 增加迭代次数
}
}
```
#### 3. 性能问题
**当前实现**:模拟分辨率与显示分辨率 1:1 匹配,在 1080p 屏幕上约 200万像素点物理计算。
**优化方案**:修改 `FluidSimulator.ts` 中的分辨率缩放:
```typescript
// src/sim/FluidSimulator.ts resize() 方法
this.simWidth = Math.floor(width / 2); // 1/2 分辨率
this.simHeight = Math.floor(height / 2);
```
### 调试工具
#### 查看着色器编译错误
```typescript
// src/core/ShaderLoader.ts 中的 compileShader 会抛出详细错误
// 包含完整的 GLSL 错误日志
```
#### 检查 FBO 状态
```typescript
// 在 FBO.ts 中添加调试代码
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.log('FBO Status:', status === gl.FRAMEBUFFER_COMPLETE ? 'OK' : 'Error');
```
#### 可视化物理场
修改 `render()` 方法渲染不同字段:
```typescript
// 渲染速度场(红色 = X速度,绿色 = Y速度)
this.gl.useProgram(this.navierProgram.program);
this.gl.bindTexture(this.gl.TEXTURE_2D, this.velocity.readTexture);
// 渲染压力场
this.gl.bindTexture(this.gl.TEXTURE_2D, this.pressure.readTexture);
```
### 浏览器兼容性
| 浏览器 | 版本要求 |
|--------|----------|
| Chrome | 56+ |
| Firefox | 51+ |
| Safari | 15+ |
| Edge | 79+ |
检查 WebGL 2.0 支持:
```javascript
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
console.log(gl ? 'WebGL 2.0 supported' : 'WebGL 2.0 NOT supported');
```
## 配置参数
```typescript
// src/config/Config.ts
{
physics: {
dt: 0.016, // 时间步长(秒)
viscosity: 0.0001, // 粘性系数
diffusion: 0.0001, // 扩散系数
pressureIterations: 40 // 压力求解迭代次数
},
interaction: {
splatRadius: 0.015, // 扰动半径(归一化坐标,小值产生精细涡结构)
forceMultiplier: 300 // 力放大系数
},
visual: {
style: 'navier' // 视觉风格:'navier' | 'smoke'
}
}
```
## 参考资料
- [Jos Stam - Stable Fluids (1999)](https://www.researchgate.net/publication/2447775_Real-Time_Fluid_Dynamics_for_Games)
- [WebGL 2 Fundamentals](https://webgl2fundamentals.org/)
- [Navier.ai](https://navier.ai/) - 视觉风格参考
## License
MIT