Student: Pragati Toppo
Course: CSC 572 - Computer Graphics
Date: December 2024
Original Paper: "Neural Monte Carlo Fluid Simulation"
Authors: Pranav Jain, Ziyin Qu, Peter Yichen Chen, Oded Stein
Published: SIGGRAPH 2024
DOI: 10.1145/3641519.3657438
- Project Overview
- System Requirements
- Installation & Building
- Running the Simulations
- File Structure
- Simulation Parameters
- Technical Implementation
- Performance Notes
- Troubleshooting
- Known Limitations
- Future Work
- References
This project reproduces and extends the Neural Monte Carlo Fluid Simulation paper from SIGGRAPH 2024. The original paper presents a mesh-free fluid simulation method combining neural networks with Monte Carlo techniques for pressure solving.
- Monte Carlo particle-based fluid dynamics (300,000 particles)
- Multi-scale turbulence using 3-level Perlin noise
- Boundary condition enforcement for obstacle interaction
- Density field voxelization via Gaussian kernel splatting
- Particle advection, diffusion, and lifecycle management
- VTK-based 3D visualization with density-gradient coloring
- Three working simulation modes:
- Mode 1: Rising smoke plume
- Mode 2: Colliding toroidal smoke rings
- Mode 3: Smoke interacting with spherical obstacle
- Interactive real-time rendering with camera controls
- Dual viewers (standard + obstacle visualization)
- Batch screenshot generation tool
- C++ implementation for performance optimization
- Mode 4: Mesh engulfing framework (OBJ file loading implemented, boundary enforcement needs further stabilization)
- Windows 10/11 (tested)
- Linux (should work, untested)
- macOS (should work, untested)
- CMake 3.12 or higher
- C++17 compatible compiler:
- Windows: MSVC 2019+ (Visual Studio)
- Linux: GCC 9+ or Clang 10+
- macOS: Xcode Command Line Tools
- VTK 9.x (tested with VTK 9.5.2)
- CommonCore, CommonDataModel
- FiltersCore, FiltersGeneral, FiltersSources
- IOImage, IOGeometry, IOXML
- InteractionStyle
- RenderingCore, RenderingOpenGL2
- CPU: Multi-core processor (4+ cores recommended)
- RAM: 8GB minimum, 16GB recommended
- GPU: Any OpenGL 3.2+ compatible graphics card
- Disk: 2GB free space for output files
Option A - Download pre-built binaries:
https://vtk.org/download/
Option B - Build from source:
# Download VTK source from https://vtk.org
# Extract and create build directory
cd vtk-source
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j4 # or cmake --build . --config Release# Extract the provided zip file to your desired location
cd /path/to/572-final-projWindows:
mkdir build && cd build
cmake .. -DVTK_DIR="C:/VTK-9.5.2/build"Linux/macOS:
mkdir build && cd build
cmake .. -DVTK_DIR="/usr/local/lib/cmake/vtk-9.5"Windows (Visual Studio):
cmake --build . --config ReleaseLinux/macOS:
make -j4Build outputs:
- Windows:
build/Release/ - Linux/macOS:
build/
From build/Release (Windows) or build/ (Linux/macOS):
Interactive mode:
./FinalSmokeProjectCommand-line mode:
./FinalSmokeProject [mode]| Mode | Description | Frames | Time |
|---|---|---|---|
| 1 | Rising smoke plume | 100 | 8-10 min |
| 2 | Colliding smoke rings | 80 | 6-8 min |
| 3 | Smoke around sphere obstacle | 120 | 10-12 min |
Examples:
./FinalSmokeProject 1
./FinalSmokeProject 2
./FinalSmokeProject 3Output Location:
../../data/smoke_0000.vti
../../data/smoke_0001.vti
...
../../data/rings_0000.vti
../../data/obstacle_0000.vti
Standard Viewer (for modes 1 and 2):
./SmokeViewer <vti_file> [iso_value]Obstacle Viewer (for mode 3 - shows sphere):
./ObstacleViewer <vti_file> [iso_value]Examples:
./SmokeViewer ../../data/smoke_0060.vti 0.02
./SmokeViewer ../../data/rings_0030.vti 0.01
./ObstacleViewer ../../data/obstacle_0080.vti 0.02| Range | Effect |
|---|---|
| 0.01-0.05 | Shows fine wispy details |
| 0.05-0.15 | Shows main smoke structure |
| 0.15-0.30 | Shows only dense core |
- Left mouse button: Rotate camera
- Middle mouse button: Pan camera
- Right mouse button / Scroll: Zoom
- 'r' key: Reset camera view
- Close window: Exit
Generate screenshots for entire sequences:
./BatchScreenshot <base_name> <start_frame> <end_frame> [iso_value]Examples:
./BatchScreenshot obstacle 0 119 0.02
./BatchScreenshot rings 0 79 0.01Outputs: ../../screenshots/[name]_0000.png, etc.
572-final-proj/
│
├── src/
│ ├── main.cpp # Main simulation driver
│ ├── SmokeFromObj.h # Simulation class header
│ ├── SmokeFromObj.cpp # Core simulation implementation
│ ├── SmokeViewer.cpp # Standard visualization
│ ├── ObstacleViewer.cpp # Obstacle-specific viewer
│ └── BatchScreenshot.cpp # Batch rendering tool
│
├── data/
│ ├── smoke_XXXX.vti # Rising smoke outputs
│ ├── rings_XXXX.vti # Colliding rings outputs
│ └── obstacle_XXXX.vti # Obstacle flow outputs
│
├── screenshots/ # Generated screenshots
│
├── build/ # CMake build directory
│ └── Release/ # Executables (Windows)
│ ├── FinalSmokeProject.exe
│ ├── SmokeViewer.exe
│ ├── ObstacleViewer.exe
│ └── BatchScreenshot.exe
│
├── CMakeLists.txt # Build configuration
├── README.md # This file
└── README.txt # Plain text version
Can be modified in src/SmokeFromObj.cpp:
MAX_PARTICLES = 300000 // Maximum active particles
PARTICLES_PER_FRAME = 2500 // Emission rate
GRID_SIZE = 150 // Volume resolution (150³)turbulence = 1.8 // Turbulence strength
buoyancy = 0.02 // Upward force
damping = 0.99 // Velocity damping
life_decay = dt / 12.0 // Particle lifetime (8-12s)Coarse scale: 0.03 // Large-scale flows
Fine scale: 0.12 // Medium eddies
Wispy scale: 0.25 // Small-scale detailSphere radius = 8.0 // Grid units
Center = (75, 75, 75) // Grid center
Push strength = 2.0 // Repulsion forceKernel radius = 2.0 // Gaussian kernel size
Kernel falloff = cubic // Smoothing function- Format: VTK XML ImageData (.vti)
- Dimensions: 150 × 150 × 150 voxels
- Spacing: 1.0 × 1.0 × 1.0 units
- Origin: (0, 0, 0)
- Data type: 32-bit floating point
- Scalar name: "ImageScalars"
- Value range: [0.0, 1.0] (density)
- Pattern:
[mode]_####.vti - Frames: 0000, 0001, 0002, ..., ####
- Zero-padded to 4 digits
- Open ParaView
- File → Open
- Select all
[mode]_*.vtifiles - Click "Apply"
- Use animation controls to play sequence
- Add filters: Contour, Threshold, etc.
Each particle has:
- Position (x, y, z) in grid coordinates
- Velocity (vx, vy, vz) in grid units/timestep
- Life remaining (seconds)
- Density contribution (0-2.0 range)
- Active flag (alive/dead)
- Emit new particles from source regions
- Apply forces:
- Perlin noise turbulence (3 scales)
- Buoyancy (upward)
- Obstacle repulsion (if mode 3)
- Advect particles:
position += velocity × dt - Apply velocity damping
- Decay density with lifetime
- Remove dead particles (life ≤ 0 or out of bounds)
- Voxelize active particles to grid
Three-octave Perlin noise:
noise = perlin(pos × 0.03) × 1.0 # Coarse
+ perlin(pos × 0.12) × 0.5 # Fine
+ perlin(pos × 0.25) × 0.3 # Wispy
Time-evolution:
noise(pos, time) = perlin(pos + time × speed)
For each particle:
if (distance_to_center < obstacle_radius) {
direction = normalize(particle_pos - obstacle_center);
particle_velocity += direction × push_strength;
}
if (distance_to_center < 40.0) {
turbulence_scale × 2.5; // Enhanced wake turbulence
}For each active particle:
- Find nearby grid cells (within kernel radius)
- Calculate Gaussian weight:
weight = (1 - dist/radius)³ - Accumulate:
grid[i,j,k] += particle.density × weight - Clamp final values to [0, 1]
- Load VTI:
vtkXMLImageDataReader - Extract isosurface:
vtkFlyingEdges3Dat iso_value - Compute normals:
vtkPolyDataNormals(smooth shading) - Map density → color:
vtkLookupTable - Render:
vtkPolyDataMapper+vtkActor - Display:
vtkRenderWindow+vtkRenderWindowInteractor
| Density Range | Color Transition |
|---|---|
| 0.00-0.25 | Deep blue → Bright blue |
| 0.25-0.50 | Bright blue → Purple |
| 0.50-0.75 | Purple → Pink/Magenta |
| 0.75-1.00 | Pink → Orange/Red |
- Frame generation: 2-5 seconds per frame
- Full simulation (100 frames): 3-12 minutes
- Viewer frame rate: 30-60 FPS for 150³ grid
- Memory usage:
- Simulation: ~500MB (300K particles)
- Viewer: ~200MB per loaded frame
- Reduce
MAX_PARTICLESfor faster generation - Reduce
GRID_SIZEfor less memory (try 100³) - Increase
PARTICLES_PER_FRAMEfor denser smoke - Build in Release mode (10x faster than Debug)
- Use SSD storage for faster VTI file I/O
- Current implementation: Single-threaded
- Potential improvements:
- OpenMP for particle updates
- GPU acceleration with CUDA/OpenCL
- Parallel voxelization
Solution: Specify VTK path explicitly:
cmake .. -DVTK_DIR="C:/VTK-9.5.2/build"Solution: Ensure all VTK components listed in CMakeLists.txt are built in your VTK installation
Solution: Use lower iso value (try 0.01-0.05)
Solution:
- Generate more frames (120+)
- Lower iso value
- Check
GRID_SIZEis 150
Solution:
- Verify VTI file exists and isn't empty
- Try different iso values (0.01-0.30)
- Check console for error messages
Solution:
- Ensure VTK DLLs are in PATH (Windows)
- Or copy VTK DLLs to same directory as .exe
- Check VTK version compatibility
Solution:
- Check
../../datadirectory exists - Verify write permissions
- Look for error messages in console
Solution:
- Use
SmokeViewer(notObstacleViewer) for rings ObstacleVieweralways shows sphere (for mode 3 only)
Solution:
- Colors depend on iso value threshold
- Lower iso = more blue (low density visible)
- Higher iso = more pink/red (only high density)
- Add new enum value to
SimulationTypeinSmokeFromObj.h - Add new emission pattern in
EmitParticles()or create new Emit function - Update
main.cppto handle new mode selection - Add corresponding output path
Edit UpdateParticles() in SmokeFromObj.cpp:
- Adjust
noise_scale,fine_scale,wisp_scale - Change noise weights (currently 1.0, 0.5, 0.3)
- Modify
time_offsetfor faster/slower evolution
Edit SmokeViewer.cpp:
- Modify color lookup table in
lut->SetTableValue(...) - Adjust opacity in
actor->GetProperty()->SetOpacity(...) - Change background in
renderer->SetBackground(...)
Implement vtkCommand subclass to handle keyboard/mouse events
Example: Toggle parameters, change iso value, reset simulation
-
Not a full NMC reproduction:
- Uses particle advection instead of neural velocity field
- Perlin noise instead of learned turbulence
- No true Monte Carlo pressure solve
- Qualitative results, not quantitatively accurate
-
Parameter sensitivity:
- Requires manual tuning for good visuals
- Different scenarios need different parameters
- No automatic parameter optimization
-
Performance:
- Single-threaded (no GPU acceleration)
- Could benefit from spatial hashing
- Voxelization is O(n×m) where n=particles, m=kernel size
-
Visualization:
- Isosurface extraction loses some volume detail
- No volume rendering option
- Fixed grid resolution (150³)
-
Work in progress features:
- Mesh engulfing mode (Mode 4) framework implemented but boundary enforcement needs stabilization
- OBJ file loading works but interaction requires refinement
- Complete mesh engulfing mode with stable boundary conditions
- Implement actual Walk-on-Spheres pressure solver
- Add neural network velocity field representation
- GPU acceleration with CUDA or OpenCL
- Adaptive resolution (octree-based)
- Volume rendering instead of isosurfaces
- Real-time parameter adjustment
- Two-way coupling with rigid bodies
- Vorticity confinement for sharper features
Jain, P., Qu, Z., Chen, P. Y., & Stein, O. (2024).
Neural Monte Carlo Fluid Simulation.
ACM SIGGRAPH 2024 Conference Papers.
DOI: 10.1145/3641519.3657438
Project Page
- Bridson, R. (2015). Fluid Simulation for Computer Graphics. A K Peters/CRC Press.
- Perlin, K. (1985). An image synthesizer. ACM SIGGRAPH Computer Graphics, 19(3), 287-296.
- Stam, J. (1999). Stable fluids. ACM SIGGRAPH 1999 Conference Proceedings, 121-128.
- The VTK User's Guide (11th Edition)
- https://vtk.org/documentation/
Student: Pragati Toppo
Email: ptoppo@calpoly.edu
Course: CSC 572 - Computer Graphics
Instructor: Fahim Khan
Institution: Cal Poly
Term: Fall 2025
Submission Date: December 8, 2025