OrbitVideoGen

June 15, 2026 · View on GitHub

Multi-view video generation with WAN 14B + LoRA. Given a 3D mesh's rendered condition videos (position, normal, albedo) and a reference image, generates textured appearance videos from orbital viewpoints.

Condition Videos (H/V orbit) + Reference Image → WAN 14B + LoRA → Generated Video (4-panel MP4)

Directory

OrbitVideoGen/
├── tests/
│   ├── test_single_h.py         # H-track inference
│   ├── test_single_v_hv.py      # V-track inference
│   └── bg_remover.py            # RMBG-2.0 background removal
├── scripts/
│   ├── train_*.sh               # Training launch scripts (4 modes × high/low)
│   └── generate_*.py            # CSV generation utilities
├── examples/                     # Training code
│   └── wanvideo/model_training/
├── diffsynth/                    # WAN pipeline, LoRA, VAE, trainers
└── README.md

Environment

conda create -n orbitgen python=3.10
conda activate orbitgen

# Install PyTorch (CUDA 12.x)
pip install torch torchvision torchaudio

# Install dependencies
pip install diffusers accelerate transformers imageio[ffmpeg] opencv-python-headless \
    scipy numpy Pillow pandas

# Download base models (WAN 14B, T5, VAE) — paths configured in training scripts
# Download LoRA weights from Hugging Face or train your own

Training Modes

Four data augmentation strategies for training the model with horizontal (H) and vertical (V) orbit data.

Mode 1: H-only

Standard training using only horizontal orbit videos.

PropertyValue
Resolution512×512
Frames121
CSVposition2albedo_all_321.csv
Training scripttrain_14b_ref_normal_revise_light_aug_61_revise2_121h0322_v2.py
# Training
bash scripts/train_h_only_high.sh    # High noise [900, 1000]
bash scripts/train_h_only_low.sh     # Low noise [0, 900]

# Inference
python tests/test_single_h.py \
    --ref_image ./example_data/034/ref.png \
    --video_dir ./example_data/034/h120 \
    --models_base /path/to/models \
    --model_ckpt_high /path/to/high.safetensors \
    --model_ckpt_low /path/to/low.safetensors \
    --output output_h.mp4

Mode 2: H/V Random Sampling

H and V entries randomly interleaved in training CSV. Each batch draws from either H or V data.

PropertyValue
Resolution512×512
Frames121
CSVposition2albedo_all_321_hv.csv
Training scriptSame as Mode 1
# Generate merged CSV (if needed)
python scripts/generate_hv_csv.py

# Training
bash scripts/train_hv_random_high.sh
bash scripts/train_hv_random_low.sh

# Inference (same as Mode 1 — separate H and V tests)
python tests/test_single_h.py ... --output output_h.mp4
python tests/test_single_v_hv.py ... --output output_v.mp4

Mode 3: H/V Spatial Concat

H and V frames concatenated spatially (side-by-side) into a single 1024×512 frame. Each frame contains both viewpoints simultaneously.

PropertyValue
Resolution1024×512 (H
Frames61 (stride-2 from 121-frame source)
CSVposition2albedo_all_321hv.csv
Training scripttrain_14b_ref_normal_revise_light_aug_61_revise2_imageref0322.py

$ \text{Frame} \text{layout}: [ \text{H} 512 \times 512 | \text{V} 512 \times 512 ] ← 1024 → $

# Training
bash scripts/train_hv_spatial_high.sh
bash scripts/train_hv_spatial_low.sh

# Inference (use same test scripts, model expects 1024x512 input)
python tests/test_single_h.py \
    --width 1024 --height 512 \
    --video_dir ./example_data/034/h120 \
    ...

Mode 4: H/V Temporal Interleave

H and V frames interleaved in time: 60 H frames (stride-2) + 60 V frames (stride-2) + H[0] loop closure = 121 frames.

PropertyValue
Resolution512×512
Frames60 H + 60 V + 1 = 121
CSVposition2albedo_all_321_hv_paired.csv
Training scripttrain_14b_hv_interleave.py
Timeline: [H0, H2, H4, ..., H118] [V0, V2, V4, ..., V118] [H0]
            ← 60 H frames →       ← 60 V frames →       loop
# Generate paired CSV
python scripts/generate_hv_paired_csv.py

# Training
bash scripts/train_hv_interleave_high.sh
bash scripts/train_hv_interleave_low.sh

# Inference (same as Mode 1)
python tests/test_single_h.py ... --output output_h.mp4
python tests/test_single_v_hv.py ... --output output_v.mp4
``$

## \text{Mode} \text{Comparison}

| \text{Mode} | \text{Resolution} | \text{Frames} | \text{H}+\text{V} \text{in} \text{one} \text{sample}? | \text{Training} \text{code} |
|------|-----------|--------|---------------------|---------------|
| 1: \text{H}-\text{only} | 512 \times 512 | 121 | \text{No} | $train_14b_*_v2.py$ |
| 2: \text{HV} \text{random} | 512 \times 512 | 121 | \text{No} (\text{alternating}) | \text{Same} \text{as} \text{Mode} 1 |
| 3: \text{Spatial} \text{concat} | 1024 \times 512 | 121 | \text{Yes} (\text{side}-\text{by}-\text{side}) | $train_14b_*_imageref0322.py$ |
| 4: \text{Temporal} \text{interleave} | 512 \times 512 | 121 | \text{Yes} (\text{back}-\text{to}-\text{back}) | $train_14b_hv_interleave.py` |

## CSV Data Format

### Mode 1, 2 (single-video)
```csv
video,control_video,reference_image,prompt
objaverse_60k_120h/videos_curve/000/xxx/albedo.mp4,objaverse_60k_120h/.../position.mp4,...

Mode 3, 4 (paired H+V)

h_video,h_control_video,v_video,v_control_video,reference_image,prompt
objaverse_60k_120h/.../albedo.mp4,.../position.mp4,objaverse_60k_120v/.../albedo.mp4,.../position_flip.mp4,...

Generate with:

python scripts/generate_hv_csv.py           # Mode 2: H+V merged (shuffled)
python scripts/generate_hv_paired_csv.py    # Mode 3/4: paired H+V per object

Test Scripts

ModeTest scriptResolutionNotes
1, 2, 4 (H)`tests/test_single_h.py$768 \times 768\text{H}-\text{track} \text{inference}
1, 2, 4 (\text{V})tests/test_single_v_hv.py768 \times 768\text{V}-\text{track} \text{inference}, \text{supports} $--h_video`
3 (spatial)`tests/test_single_hv_spatial.py$512 \times 1024\text{H}+\text{V} \text{side}-\text{by}-\text{side} \text{input}/\text{output}

\text{All} \text{scripts} \text{auto}-\text{detect} 4-\text{panel} \text{video} \text{format} \text{and} \text{support} $--models_base, --no_bg_remove`.

Background Removal

# RMBG-2.0 (recommended, matches training distribution)
# Download weights to /path/to/RMBG-2.0
python tests/test_single_h.py --ref_image img.png ...   # auto-runs bg_remover
python tests/test_single_h.py --ref_image img.png --no_bg_remove ...  # skip if ref already has black bg