# XCVolumeRenderer 深入方向规划 本文档详细列出本科毕业设计可深入的所有方向,供选择和规划。 --- ## 一、渲染效果提升 ### 1.1 多散射 (Multiple Scattering) #### 背景 当前实现的是单散射(Single Scattering),光线只从光源到体素再到相机弹射一次。真实云层中,光线会在体积内多次弹射,产生柔和的边缘和通透的内部效果。 #### 当前问题 - 云内部过暗,缺乏体积感 - 边缘过于锐利,不自然 - 逆光效果不明显 #### 解决方案 **方法A:迭代多散射** ``` for (散射次数) { for (每个采样点) { 计算该点的入射光(来自光源 + 其他体素的散射光) 累积散射光 } } ``` - 优点:物理正确 - 缺点:性能开销大,O(n²) 或更高 **方法B:近似多散射** ``` // 使用扩散近似(Diffusion Approximation) // 参考: Jensen et al. "A Practical Model for Subsurface Light Transport" float multiScatter = exp(-sigmaT * d) * diffusionTerm; ``` - 优点:性能好 - 缺点:近似,不够精确 **方法C:预计算多散射** ``` // 离线预计算散射LUT // 运行时查表 Texture3D scatteringLUT; float multiScatter = scatteringLUT.Sample(sampler, uvw); ``` - 优点:运行时快 - 缺点:需要额外存储 #### 实现步骤 1. 实现简单的双散射(Double Scattering) 2. 观察效果变化 3. 优化性能(重要性采样) 4. 扩展到多阶散射 #### 参考资料 - Jensen, H. W., et al. "A Practical Model for Subsurface Light Transport" (SIGGRAPH 2001) - Hachisuka, T., et al. "Progressive Photon Mapping" (SIGGRAPH 2008) - Kutz, P., et al. "Spectral and Decomposition Tracking for Rendering Heterogeneous Volumes" (SIGGRAPH 2017) #### 工作量估计 - 双散射基础实现:1周 - 完整多散射:2-3周 - 性能优化:1周 --- ### 1.2 相函数 (Phase Function) #### 背景 相函数描述光线在介质中散射的方向分布。当前使用的是均匀相函数 `return 1.0`,即各向同性散射。真实云层的相函数是各向异性的,具有强烈的前向散射特性。 #### 当前问题 - 光照效果过于均匀 - 缺乏真实云层的光晕效果 - 逆光时的"银边"效果不明显 #### 相函数类型 **1. Henyey-Greenstein (HG) 相函数** ```hlsl float hg_phase(float cosTheta, float g) { float g2 = g * g; return (1 - g2) / pow(1 + g2 - 2 * g * cosTheta, 1.5) / (4 * PI); } ``` - `g = 0`: 各向同性 - `g > 0`: 前向散射(云层特性) - `g < 0`: 后向散射 - 参数 `g` 范围:(-1, 1) **2. 双 Henyey-Greenstein 相函数** ```hlsl float double_hg_phase(float cosTheta, float g1, float g2, float w) { return w * hg_phase(cosTheta, g1) + (1 - w) * hg_phase(cosTheta, g2); } ``` - 结合两个HG相函数 - 更好地模拟真实云层 - `g1 ≈ 0.8`(强前向),`g2 ≈ -0.2`(弱后向) **3. Mie 相函数** ```hlsl // 查表实现,更精确但复杂 // 通常用HG近似 ``` - 物理最正确 - 计算复杂 - 通常用双HG近似 **4. Rayleigh 相函数** ```hlsl float rayleigh_phase(float cosTheta) { return (3 / (16 * PI)) * (1 + cosTheta * cosTheta); } ``` - 适用于大气散射 - 小粒子(空气分子) #### 实现步骤 1. 实现 HG 相函数 2. 添加参数 UI 控制 `g` 值 3. 观察不同 `g` 值的效果 4. 实现双 HG 相函数 5. 对比效果 #### 参数建议 | 场景 | g 值 | 说明 | |------|------|------| | 云层 | 0.7 ~ 0.9 | 强前向散射 | | 雾 | 0.1 ~ 0.3 | 弱前向散射 | | 烟雾 | -0.2 ~ 0.2 | 接近各向同性 | #### 参考资料 - Henyey, L. G., & Greenstein, J. L. "Diffuse radiation in the galaxy" (1941) - Nishita, T., et al. "Display of clouds taking into account multiple anisotropic scattering and sky light" (SIGGRAPH 1996) #### 工作量估计 - HG相函数实现:1-2天 - 双HG相函数:2-3天 - 参数UI:1天 --- ### 1.3 体积自发光 (Volumetric Emission) #### 背景 火焰、熔岩、霓虹气体等发光体积。除了散射外部光源,自身也发出光。 #### 实现方法 ```hlsl // 在着色器中添加自发光项 float3 emission = emissionColor * emissionIntensity * emissionMask; float3 S = sigmaS * phase_function() * shadow * float3(1, 1, 1) + emission; ``` #### 扩展 - 温度场驱动发光颜色(黑体辐射) - 发光影响周围体积(需多散射支持) #### 工作量估计 - 基础实现:1-2天 - 温度场驱动:3-4天 --- ## 二、性能优化 ### 2.1 Temporal Reprojection #### 背景 当前渲染存在噪点,尤其是阴影采样。Temporal Reprojection 利用历史帧信息进行降噪。 #### 原理 ``` 当前帧颜色 = α * 当前帧渲染 + (1-α) * 历史帧重投影颜色 ``` #### 核心步骤 **1. 速度缓冲 (Motion Vector)** ```hlsl // 计算当前像素在上一帧的位置 float2 motionVector = currentPos - previousPos; float2 prevUV = currentUV - motionVector; ``` **2. 历史帧采样** ```hlsl float3 historyColor = historyTexture.Sample(sampler, prevUV); ``` **3. 颜色约束 (Clamping)** ```hlsl // 防止鬼影 float3 minColor = min(neighbors); float3 maxColor = max(neighbors); historyColor = clamp(historyColor, minColor, maxColor); ``` **4. 混合** ```hlsl float3 finalColor = lerp(currentColor, historyColor, 0.9); ``` #### 需要的资源 - 历史帧颜色缓冲 - 深度缓冲(当前帧 + 历史帧) - Motion Vector 缓冲 #### 实现步骤 1. 创建历史帧缓冲 2. 实现 Motion Vector 计算 3. 实现重投影逻辑 4. 实现颜色约束 5. 调试和参数调优 #### 注意事项 - 相机快速移动时会产生鬼影 - 需要处理物体移动(动态场景) - 需要处理体积自身的旋转/移动 #### 参考资料 - Karis, B. "High Quality Temporal Supersampling" (SIGGRAPH 2014) - Schied, C., et al. "Temporal Sample Anti-Aliasing" (EGSR 2020) #### 工作量估计 - 基础实现:1周 - 调优和调试:1周 --- ### 2.2 Compute Shader 重构 #### 背景 当前使用 Pixel Shader 进行 Ray Marching,每个像素独立计算。Compute Shader 可以更灵活地控制线程,实现更好的优化。 #### 优势 **1. 线程组共享内存** ```hlsl groupshared float sharedDensity[8][8]; // 相邻像素可共享中间计算结果 ``` **2. 自适应工作分配** ```hlsl // 可以跳过空像素,让活跃线程处理更多 ``` **3. 更好的缓存利用** ```hlsl // 可以手动控制数据加载,优化缓存 ``` #### 实现架构 ``` Compute Shader Dispatch (32x32 线程组) ↓ 每个线程处理一个像素 ↓ Ray Marching ↓ 输出到 UAV 纹理 ``` #### 代码示例 ```hlsl [numthreads(8, 8, 1)] void MainCS(uint3 DTid : SV_DispatchThreadID) { float2 uv = (float2(DTid.xy) + 0.5) / Resolution; float3 color = RayMarch(uv); OutputTexture[DTid.xy] = float4(color, 1); } ``` #### 可实现的高级优化 - 波前追踪 (Wavefront Tracing) - 空间跳跃优化 - 自适应采样 #### 工作量估计 - 基础重构:1-2周 - 高级优化:2-3周 --- ### 2.3 自适应步长 #### 背景 当前使用固定步长,但在低密度区域可以加大步长,高密度区域减小步长。 #### 实现方法 **方法A:基于密度** ```hlsl float density = SampleDensity(pos); float stepSize = baseStep * (1 + (1 - density) * maxScale); ``` **方法B:基于梯度** ```hlsl float gradient = length(SampleGradient(pos)); float stepSize = baseStep / (1 + gradient * gradientScale); ``` **方法C:预计算重要性场** ```hlsl // 离线预计算每个区域的重要性 // 运行时根据重要性调整步长 ``` #### 注意事项 - 步长变化过大可能导致伪影 - 需要注意光线一致性 #### 工作量估计 - 基础实现:2-3天 - 调优:1周 --- ## 三、功能扩展 ### 3.1 多光源支持 #### 背景 当前只支持单一方向光。真实场景可能有多个光源(太阳 + 天光 + 点光源)。 #### 实现内容 **1. 多方向光** ```hlsl struct DirectionalLight { float3 direction; float3 color; float intensity; }; #define MAX_DIR_LIGHTS 4 DirectionalLight dirLights[MAX_DIR_LIGHTS]; ``` **2. 点光源** ```hlsl struct PointLight { float3 position; float3 color; float intensity; float radius; }; float3 SamplePointLight(PointLight light, float3 pos) { float3 dir = light.position - pos; float dist = length(dir); dir /= dist; // 衰减 float attenuation = 1.0 / (1.0 + dist * dist); // 阴影采样 float shadow = VolumetricShadow(pos, dir, dist); return light.color * light.intensity * attenuation * shadow; } ``` **3. 聚光灯** ```hlsl struct SpotLight { float3 position; float3 direction; float3 color; float intensity; float innerAngle; float outerAngle; float range; }; ``` #### 实现步骤 1. 设计光源数据结构 2. 实现多方向光循环 3. 实现点光源阴影采样 4. 实现聚光灯锥形衰减 5. 添加参数 UI #### 性能考虑 - 每个光源都需要额外的阴影采样 - 限制光源数量或使用延迟渲染思路 #### 工作量估计 - 多方向光:2-3天 - 点光源:3-4天 - 聚光灯:2-3天 - UI和参数:1-2天 --- ### 3.2 大气散射 #### 背景 将体积渲染与天空大气结合,实现更真实的室外场景。 #### 核心算法 **1. Rayleigh 散射** ```hlsl // 空气分子散射,产生蓝天 float3 RayleighScattering(float cosTheta, float height) { float3 betaR = float3(5.8e-6, 13.5e-6, 33.1e-6); // Rayleigh系数 float density = exp(-height / 8500); // 大气密度衰减 return betaR * density * (3 / (16 * PI)) * (1 + cosTheta * cosTheta); } ``` **2. Mie 散射** ```hlsl // 气溶胶散射,产生雾和光晕 float3 MieScattering(float cosTheta, float g) { float3 betaM = float3(21e-6, 21e-6, 21e-6); // Mie系数 return betaM * HGPhase(cosTheta, g); } ``` **3. 单次散射积分** ```hlsl float3 IntegrateAtmosphere(float3 rayOrigin, float3 rayDir, float3 sunDir) { float3 color = 0; float transmittance = 1; for (int i = 0; i < steps; i++) { float3 pos = rayOrigin + rayDir * t; float height = length(pos) - earthRadius; // Rayleigh float densityR = exp(-height / 8500); float3 scatterR = RayleighScattering(dot(rayDir, sunDir), height); // Mie float densityM = exp(-height / 1200); float3 scatterM = MieScattering(dot(rayDir, sunDir), 0.76); // 光学深度 float3 opticalDepth = (scatterR + scatterM) * stepSize; transmittance *= exp(-opticalDepth); color += transmittance * (scatterR + scatterM) * stepSize; t += stepSize; } return color; } ``` #### 效果 - 蓝天 - 日落/日出 - 远山大气透视 - 太阳光晕 #### 参考资料 - Nishita, T., et al. "Display of The Earth Taking into Account Atmospheric Scattering" (SIGGRAPH 1993) - Bruneton, E., & Neyret, F. "Precomputed Atmospheric Scattering" (EGSR 2008) - Hillaire, S. "A Scalable and Production Ready Sky and Atmosphere Rendering Technique" (SIGGRAPH 2020) #### 工作量估计 - 基础实现:1周 - 优化和调参:1周 --- ### 3.3 体积雾 #### 背景 将体积渲染作为后处理效果,与场景几何体融合。 #### 实现方法 **1. 深度重建世界坐标** ```hlsl float depth = depthTexture.Sample(sampler, uv); float4 worldPos = mul(invViewProj, float4(ndc, depth, 1)); worldPos /= worldPos.w; ``` **2. 沿视线积分** ```hlsl float3 cameraPos = ...; float3 rayDir = normalize(worldPos - cameraPos); float dist = length(worldPos - cameraPos); float3 color = IntegrateVolume(cameraPos, rayDir, dist); ``` **3. 与场景混合** ```hlsl float3 sceneColor = sceneTexture.Sample(sampler, uv); float3 finalColor = lerp(sceneColor, volumeColor, volumeAlpha); ``` #### 工作量估计 - 基础实现:3-4天 --- ## 四、交互与控制 ### 4.1 相机交互 #### 功能需求 - 鼠标左键拖动:旋转视角 - 鼠标右键拖动:平移 - 鼠标滚轮:缩放 - WASD:自由移动 #### 实现方法 **1. 弧球相机 (Arcball Camera)** ```cpp // 围绕目标点旋转 XMVECTOR target = XMVectorSet(0, 0, 0, 1); float distance = 500.0f; float yaw = 0, pitch = 0; void UpdateCamera() { XMVECTOR eye = XMVectorSet( sin(yaw) * cos(pitch) * distance, sin(pitch) * distance, cos(yaw) * cos(pitch) * distance, 1.0f ); viewMatrix = XMMatrixLookAtLH(eye, target, XMVectorSet(0, 1, 0, 0)); } ``` **2. 自由相机 (Free Camera)** ```cpp XMVECTOR position; float yaw = 0, pitch = 0; void Move(float dx, float dy, float dz) { XMVECTOR forward = XMVectorSet(sin(yaw), 0, cos(yaw), 0); XMVECTOR right = XMVectorSet(cos(yaw), 0, -sin(yaw), 0); XMVECTOR up = XMVectorSet(0, 1, 0, 0); position += forward * dz + right * dx + up * dy; } void Rotate(float dYaw, float dPitch) { yaw += dYaw; pitch += dPitch; pitch = clamp(pitch, -PI/2 + 0.01f, PI/2 - 0.01f); } ``` #### 输入处理 ```cpp // Windows 消息处理 case WM_LBUTTONDOWN: isDragging = true; lastMousePos = GET_MOUSE_POS(lParam); break; case WM_MOUSEMOVE: if (isDragging) { POINT currentPos = GET_MOUSE_POS(lParam); float dx = (currentPos.x - lastMousePos.x) * sensitivity; float dy = (currentPos.y - lastMousePos.y) * sensitivity; camera.Rotate(dx, dy); lastMousePos = currentPos; } break; ``` #### 工作量估计 - 弧球相机:2-3天 - 自由相机:2-3天 - 输入处理:1-2天 --- ### 4.2 实时参数 UI #### 功能需求 - 密度缩放 (Density Scale) - 步长 (Step Size) - 最大步数 (Max Steps) - 光照方向 (Light Direction) - 光照强度 (Light Intensity) - 相函数参数 (Phase Function G) - 阴影采样数 (Shadow Samples) #### UI 库选择 **选项A:Dear ImGui (推荐)** ```cpp #include "imgui.h" void RenderUI() { ImGui::Begin("Volume Parameters"); ImGui::SliderFloat("Density Scale", &densityScale, 0.0f, 1.0f); ImGui::SliderFloat("Step Size", &stepSize, 0.1f, 5.0f); ImGui::SliderInt("Max Steps", &maxSteps, 100, 5000); ImGui::SliderFloat3("Light Dir", lightDir, -1.0f, 1.0f); ImGui::SliderFloat("Phase G", &phaseG, -0.99f, 0.99f); ImGui::End(); } ``` **选项B:Win32 原生控件** - 不需要额外库 - 实现复杂 - 样式受限 #### 集成步骤 1. 添加 ImGui 到项目 2. 实现 D3D12 后端 3. 创建参数面板 4. 绑定参数到常量缓冲区 #### 工作量估计 - ImGui 集成:2-3天 - 参数面板:1-2天 --- ### 4.3 体积数据编辑 #### 功能需求 - 实时修改体积密度 - 添加/删除体素 - 画笔工具 #### 实现思路 **1. CPU 端编辑** ```cpp // 读取当前体积数据 std::vector volumeData = ReadVolumeData(); // 修改 int x = floor(pos.x / voxelSize); int y = floor(pos.y / voxelSize); int z = floor(pos.z / voxelSize); volumeData[index(x,y,z)] += strength; // 重新上传 GPU UpdateGPUBuffer(volumeData); ``` **2. 画笔工具** ```cpp void PaintVolume(float3 center, float radius, float strength) { for each voxel in range: float dist = length(voxelPos - center); if (dist < radius) { float falloff = 1 - dist / radius; voxel.density += strength * falloff; } } ``` #### 挑战 - NanoVDB 是只读结构,需要重建 - 或改用 3D Texture #### 工作量估计 - 基础编辑:1周 - 画笔工具:3-4天 --- ## 五、数据生成 ### 5.1 程序化云生成 #### 背景 使用 Noise 函数程序化生成云层,无需外部数据文件。 #### 核心算法 **1. Perlin Noise** ```hlsl float perlinNoise(float3 p) { // 梯度噪声实现 float3 i = floor(p); float3 f = frac(p); float3 u = f * f * (3 - 2 * f); // smoothstep return lerp( lerp(lerp(hash(i + float3(0,0,0)), hash(i + float3(1,0,0)), u.x), lerp(hash(i + float3(0,1,0)), hash(i + float3(1,1,0)), u.x), u.y), lerp(lerp(hash(i + float3(0,0,1)), hash(i + float3(1,0,1)), u.x), lerp(hash(i + float3(0,1,1)), hash(i + float3(1,1,1)), u.x), u.y), u.z ); } ``` **2. Fractal Brownian Motion (FBM)** ```hlsl float fbm(float3 p, int octaves) { float value = 0; float amplitude = 0.5; float frequency = 1; for (int i = 0; i < octaves; i++) { value += amplitude * perlinNoise(p * frequency); amplitude *= 0.5; frequency *= 2; } return value; } ``` **3. 云密度函数** ```hlsl float cloudDensity(float3 pos) { // 基础形状(球体或盒子) float shape = sphere(pos, center, radius); // 噪声扰动 float noise = fbm(pos * scale, 5); // 密度 float density = shape * noise; // 阈值和锐化 density = smoothstep(threshold, threshold + edgeSoftness, density); return density; } ``` **4. Worley Noise (细胞噪声)** ```hlsl // 用于云的细节和孔洞 float worleyNoise(float3 p) { float minDist = 1e10; int3 cell = floor(p); for (int x = -1; x <= 1; x++) for (int y = -1; y <= 1; y++) for (int z = -1; z <= 1; z++) { int3 neighbor = cell + int3(x, y, z); float3 point = neighbor + hash3(neighbor); float dist = distance(p, point); minDist = min(minDist, dist); } return minDist; } ``` #### 云层模型 **Cumulus (积云)** - 底部平坦,顶部蓬松 - 使用多个 FBM 叠加 - 高度衰减 **Stratus (层云)** - 薄层状 - 低频噪声 - 均匀分布 **Cirrus (卷云)** - 高空,纤维状 - 高频噪声 - 方向性 #### 动态演化 ```hlsl // 随时间演化 float density = cloudDensity(pos + wind * time); // 形态变化 float growth = sin(time * growthSpeed); density *= 1 + growth * 0.2; ``` #### 参考资料 - Ebert, D. S., et al. "Texturing & Modeling: A Procedural Approach" - Gili, A. "The Real-Time Volumetric Cloudscapes of Horizon Zero Dawn" (SIGGRAPH 2015) - Hillaire, S. "Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite" (SIGGRAPH 2016) #### 工作量估计 - Perlin/FBM 实现:2-3天 - Worley Noise:2天 - 云密度函数:3-4天 - 参数调优:1周 --- ### 5.2 离线流体模拟器 #### 背景 实现 CPU 端流体模拟,导出 OpenVDB/NanoVDB 格式。 #### 核心算法:Navier-Stokes 方程 ``` ∂u/∂t = -(u·∇)u - ∇p/ρ + ν∇²u + f ∇·u = 0 ``` 其中: - u:速度场 - p:压力场 - ρ:密度 - ν:粘度 - f:外力 #### 求解步骤 **1. 对流 (Advection)** ```cpp void advect(VelocityField& u, ScalarField& q, float dt) { for each cell (i, j, k): // 回溯粒子位置 Vec3 pos = Vec3(i, j, k) - u(i, j, k) * dt; // 插值采样 q_new(i, j, k) = interpolate(q, pos); } ``` **2. 扩散 (Diffusion)** ```cpp void diffuse(ScalarField& q, float viscosity, float dt) { // Jacobi 迭代 for (int iter = 0; iter < iterations; iter++) { for each cell (i, j, k): q_new(i, j, k) = (q(i-1,j,k) + q(i+1,j,k) + q(i,j-1,k) + q(i,j+1,k) + q(i,j,k-1) + q(i,j,k+1) + q_old(i,j,k) * alpha) / (6 + alpha); } } ``` **3. 压力求解 (Pressure Solve)** ```cpp void project(VelocityField& u) { // 计算散度 for each cell: divergence(i, j, k) = -0.5 * (u(i+1,j,k).x - u(i-1,j,k).x + u(i,j+1,k).y - u(i,j-1,k).y + u(i,j,k+1).z - u(i,j,k-1).z); // Jacobi 迭代求解压力 for (int iter = 0; iter < iterations; iter++) { for each cell: p_new(i, j, k) = (p(i-1,j,k) + p(i+1,j,k) + p(i,j-1,k) + p(i,j+1,k) + p(i,j,k-1) + p(i,j,k+1) - divergence(i,j,k)) / 6; } // 速度校正 for each cell: u(i, j, k).x -= 0.5 * (p(i+1,j,k) - p(i-1,j,k)); u(i, j, k).y -= 0.5 * (p(i,j+1,k) - p(i,j-1,k)); u(i, j, k).z -= 0.5 * (p(i,j,k+1) - p(i,j,k-1)); } ``` **4. 外力 (External Forces)** ```cpp void addForce(VelocityField& u, Vec3 forcePos, Vec3 forceDir, float strength) { for each cell near forcePos: u(i, j, k) += forceDir * strength * falloff(distance); } ``` #### 烟雾模拟扩展 **密度场** ```cpp // 对流密度 advect(u, density, dt); // 添加烟雾源 for each source cell: density(i, j, k) = sourceStrength; // 衰减 density *= (1 - decay * dt); ``` **温度场** ```cpp // 浮力 for each cell: float buoyancy = temperature(i,j,k) * buoyancyStrength; u(i,j,k).y += buoyancy * dt; ``` **涡度约束 (Vorticity Confinement)** ```cpp // 增加细节 Vec3 curl = computeCurl(u); Vec3 N = normalize(curl); Vec3 omega = curl; u += dt * vorticityStrength * N * omega; ``` #### OpenVDB 集成 ```cpp #include #include void exportToVDB(const ScalarField& density, const std::string& filename) { openvdb::initialize(); // 创建网格 openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(); openvdb::FloatGrid::Accessor accessor = grid->getAccessor(); // 填充数据 for each active voxel (i, j, k): openvdb::Coord coord(i, j, k); accessor.setValue(coord, density(i, j, k)); // 保存 openvdb::io::File file(filename); file.write({grid}); file.close(); } ``` #### NanoVDB 转换 ```cpp #include void convertToNanoVDB(const std::string& openvdbFile, const std::string& nanovdbFile) { // 读取 OpenVDB openvdb::io::File file(openvdbFile); openvdb::GridBase::Ptr baseGrid = file.readGrid("density"); // 转换 auto handle = nanovdb::openToNanoVDB(baseGrid); // 保存 nanovdb::io::writeToFile(nanovdbFile, handle); } ``` #### 工作流程 ``` 1. 初始化网格和场 2. 循环帧: a. 对流速度场 b. 添加外力 c. 扩散(粘度) d. 压力求解 e. 对流密度/温度 f. 导出当前帧 3. 批量转换为 NanoVDB ``` #### 参考资料 - Bridson, R. "Fluid Simulation for Computer Graphics" (书籍) - Stam, J. "Stable Fluids" (SIGGRAPH 1999) - Fedkiw, R., et al. "Visual Simulation of Smoke" (SIGGRAPH 2001) #### 工作量估计 - 基础流体求解器:2周 - 烟雾扩展:1周 - OpenVDB 集成:1周 - NanoVDB 导出:3-4天 - UI 和参数:1周 --- ### 5.3 多格式导入 #### 支持格式 | 格式 | 描述 | 库 | |------|------|-----| | OpenVDB (.vdb) | 行业标准 | openvdb 库 | | DDS 体积纹理 | DirectX 格式 | DirectX | | Raw 体素数据 | 自定义格式 | 手动解析 | #### 实现思路 ```cpp class VolumeLoader { public: virtual bool load(const std::string& path) = 0; virtual float sample(int x, int y, int z) const = 0; virtual Vec3 size() const = 0; }; class OpenVDBLoader : public VolumeLoader { ... }; class DDSLoader : public VolumeLoader { ... }; class RawLoader : public VolumeLoader { ... }; ``` #### 工作量估计 - OpenVDB 支持:3-4天 - DDS 支持:2-3天 - 统一接口:1-2天 --- ## 六、高级算法 ### 6.1 重要性采样 #### 背景 根据体积密度分布,在重要区域增加采样密度,在空区域减少采样。 #### 方法 **1. 基于密度的重要性采样** ```hlsl // 根据密度调整采样概率 float pdf = density / totalDensity; float step = baseStep / pdf; ``` **2. 分层采样** ```hlsl // 将光线分成段,每段内均匀采样 for each segment: float randomOffset = rand(); float samplePos = segmentStart + randomOffset * segmentLength; ``` **3. 多重要性采样** ```hlsl // 结合多种采样策略 float sampleByDensity = ...; float sampleByLight = ...; float weight = misWeight(densityWeight, lightWeight); ``` #### 工作量估计 - 基础实现:3-4天 - 优化:1周 --- ### 6.2 屏幕空间降噪 #### 背景 低采样率导致的噪点,通过屏幕空间滤波器降噪。 #### 算法 **1. 双边滤波 (Bilateral Filter)** ```hlsl float3 bilateralFilter(float2 uv, float3 centerColor, float centerDepth) { float3 sum = 0; float weightSum = 0; for each neighbor: float3 neighborColor = sample(neighborUV); float neighborDepth = sampleDepth(neighborUV); float spatialWeight = gaussian(distance); float rangeWeight = gaussian(length(neighborColor - centerColor)); float depthWeight = gaussian(abs(neighborDepth - centerDepth)); float weight = spatialWeight * rangeWeight * depthWeight; sum += neighborColor * weight; weightSum += weight; return sum / weightSum; } ``` **2. SVGF (Spatiotemporal Variance-Guided Filtering)** - Temporal 累积 - 空间滤波 - 方差估计 **3. BMFR (Blockwise Multi-Order Feature Regression)** - 块处理 - 特征回归 #### 参考资料 - Schied, C., et al. "Spatiotemporal Variance-Guided Filtering" (EGSR 2017) #### 工作量估计 - 双边滤波:2-3天 - SVGF:2-3周 --- ## 七、场景融合 ### 7.1 体积与场景遮挡 #### 问题 当前体积渲染不考虑场景几何体的遮挡。 #### 解决方案 **1. 深度测试** ```hlsl // 从深度缓冲重建世界坐标 float depth = depthTexture.Sample(sampler, uv); float3 sceneWorldPos = reconstructWorldPos(uv, depth); // 计算到场景的距离 float sceneDist = length(sceneWorldPos - cameraPos); // Ray Marching 时限制最大距离 float tmax = min(rayTmax, sceneDist); ``` **2. 阴影遮挡** ```hlsl // 场景几何体遮挡体积 float sceneShadow = 1.0; if (isOccludedByScene(pos)) { sceneShadow = 0.0; } ``` #### 工作量估计 - 深度测试:2-3天 - 完整遮挡:1周 --- ### 7.2 阴影接收 #### 问题 体积应该接收场景几何体的阴影。 #### 解决方案 ```hlsl float sceneShadow = SampleSceneShadowMap(pos); float3 S = sigmaS * phase_function() * shadow * sceneShadow; ``` #### 工作量估计 - 基础实现:2-3天 --- ## 八、应用场景 ### 8.1 动态天气系统 #### 功能 - 云层动态演化 - 日出日落光照变化 - 雨雾效果 #### 实现 ```hlsl // 云层演化 float timeOfDay = sin(time * dayCycleSpeed); float cloudDensity = baseDensity * (0.5 + 0.5 * timeOfDay); // 光照变化 float3 sunColor = lerp(sunriseColor, noonColor, timeOfDay); float3 ambientColor = lerp(nightAmbient, dayAmbient, timeOfDay); // 雾气 float fogDensity = fogBase + fogVariation * sin(time); ``` #### 工作量估计 - 1-2周 --- ### 8.2 火焰/爆炸效果 #### 需求 - 温度场驱动 - 黑体辐射颜色 - 自发光 #### 实现 ```hlsl // 温度到颜色 (黑体辐射) float3 temperatureToColor(float T) { // Planck 定律近似 float x = T / 10000.0; float3 color; color.r = 1.0; color.g = clamp(1.0 - exp(-5.0 * x), 0, 1); color.b = clamp(1.0 - exp(-10.0 * x), 0, 1); return color; } // 发光 float3 emission = temperatureToColor(temperature) * emissionIntensity; float3 S = sigmaS * phase_function() * shadow + emission; ``` #### 工作量估计 - 1周 --- ## 九、推荐方案总结 ### 方案A:渲染深化(学术向) ``` 多散射 + 相函数 + Temporal Reprojection ``` - 难度:⭐⭐⭐⭐ - 工作量:4-5周 - 论文价值:高 - 适合:想发论文/读研 ### 方案B:工程完整(展示向) ``` 相机交互 + 参数UI + 多光源 + 大气散射 ``` - 难度:⭐⭐⭐ - 工作量:3-4周 - 展示效果:好 - 适合:答辩演示 ### 方案C:离线工具链(创新向) ``` 离线流体模拟器 + OpenVDB集成 + NanoVDB导出 ``` - 难度:⭐⭐⭐⭐⭐ - 工作量:6-8周 - 创新性:强 - 适合:想深入图形学 ### 方案D:程序化生成(创意向) ``` 程序化云生成 + 参数控制 + 动态天气 ``` - 难度:⭐⭐⭐⭐ - 工作量:3-4周 - 展示性:强 - 适合:想展示效果 ### 方案E:平衡方案(推荐) ``` 多散射 + Temporal Reprojection + 相函数 + 程序化扰动动画 ``` - 难度:⭐⭐⭐⭐ - 工作量:4-5周 - 效果提升明显 - 有技术深度 - 工作量可控 --- ## 十、时间规划建议 ### 单方向深入(4-5周) | 阶段 | 内容 | 时间 | |------|------|------| | 第1周 | 多散射基础实现 | 7天 | | 第2周 | 多散射优化 + 相函数 | 7天 | | 第3周 | Temporal Reprojection | 7天 | | 第4周 | 程序化扰动 + 效果调优 | 7天 | | 第5周 | 文档 + 测试 | 7天 | ### 多方向扩展(6-8周) | 阶段 | 内容 | 时间 | |------|------|------| | 第1-2周 | 渲染效果提升 | 14天 | | 第3-4周 | 性能优化 | 14天 | | 第5-6周 | 交互与控制 | 14天 | | 第7周 | 效果调优 | 7天 | | 第8周 | 文档 + 测试 | 7天 | --- ## 十一、参考资料汇总 ### 论文 1. Jensen, H. W., et al. "A Practical Model for Subsurface Light Transport" (SIGGRAPH 2001) 2. Kutz, P., et al. "Spectral and Decomposition Tracking for Rendering Heterogeneous Volumes" (SIGGRAPH 2017) 3. Stam, J. "Stable Fluids" (SIGGRAPH 1999) 4. Fedkiw, R., et al. "Visual Simulation of Smoke" (SIGGRAPH 2001) 5. Karis, B. "High Quality Temporal Supersampling" (SIGGRAPH 2014) 6. Schied, C., et al. "Spatiotemporal Variance-Guided Filtering" (EGSR 2017) ### 书籍 1. Bridson, R. "Fluid Simulation for Computer Graphics" 2. Ebert, D. S., et al. "Texturing & Modeling: A Procedural Approach" 3. Pharr, M., et al. "Physically Based Rendering: From Theory to Implementation" ### 开源项目 1. OpenVDB: https://github.com/AcademySoftwareFoundation/openvdb 2. NanoVDB: https://github.com/AcademySoftwareFoundation/nanovdb 3. Mantaflow: https://mantaflow.uni-mainz.de/ 4. Dear ImGui: https://github.com/ocornut/imgui --- *文档版本: 1.0* *更新日期: 2026年3月*