Ink3D Render

June 17, 2026 · View on GitHub

Multi-pass 3D model rendering pipeline based on Blender. Supports horizontal (H) and vertical (V) camera orbits, outputting color, depth, normal, albedo, and position maps as images and videos.

Features

  • Horizontal orbit (H): Camera circles the equator at a fixed elevation
  • Vertical orbit (V): Camera travels along a meridian (full 360° vertical loop)
  • Multi-pass output: RGB, depth, normal, albedo, position, mask
  • Video export: Auto-generates MP4 videos for each channel
  • GPU rendering: CYCLES with CUDA/OptiX GPU acceleration
  • Batch rendering: Process entire directories of GLB files

Environment Setup

# 1. Create conda environment with Python 3.10
conda create -n bpy40 python=3.10
conda activate bpy40

# 2. Download and install bpy==4.0.0 (not available on PyPI)
#    Download from Hugging Face:
wget https://huggingface.co/datasets/Yuehavingfun/ink3d-example-data/resolve/main/bpy-4.0.0-py310-linux-x86_64.tar.gz
tar -xzf bpy-4.0.0-py310-linux-x86_64.tar.gz -C $CONDA_PREFIX/lib/python3.10/site-packages/

# 3. Install dependencies
pip install numpy imageio[ffmpeg] Pillow scipy tqdm requests zstandard

# 4. Install this package
cd Render
pip install -e .

Note: bpy==4.0.0 is no longer available on PyPI. We provide a pre-packaged version on Hugging Face. Requires Python 3.10 and Linux x86_64.

Quick Start

Example Data

Download example meshes from Hugging Face:

pip install huggingface_hub
python3 -c "
from huggingface_hub import snapshot_download
snapshot_download('Yuehavingfun/ink3d-example-data', repo_type='dataset',
                  allow_patterns='034/*', local_dir='./example_data')
"
# Downloads mesh.glb + pre-rendered condition videos for case 034 (cup model)

Single Model Rendering

conda activate bpy40

# Horizontal orbit, 120 cameras, GPU rendering
python3 render.py \
    --input_file ./example_data/034/mesh.glb \
    --output_dir ./output \
    --orbit horizontal \
    --num_cameras 120

# Vertical orbit
python3 render.py \
    --input_file ./example_data/034/mesh.glb \
    --output_dir ./output \
    --orbit vertical \
    --num_cameras 120

# CPU rendering (for machines without compatible GPU)
python3 render.py \
    --input_file /path/to/model.glb \
    --output_dir ./output \
    --engine CYCLES_CPU

Batch Rendering

# Render all GLBs in a directory
python render_batch.py \
    --input_dir /path/to/glb_folder \
    --output_dir ./output \
    --orbit horizontal

# Batch render with vertical orbit + flip_x
python render_batch.py \
    --input_dir /path/to/glb_folder \
    --output_dir ./output \
    --orbit vertical \
    --flip_x

# Multi-threaded batch rendering
python render_batch.py \
    --input_dir /path/to/glb_folder \
    --output_dir ./output \
    --threads 4 \
    --skip 10  # skip first 10 files

Output Structure

output/
└── <model_name>/
    └── h120/  (or v120)
        ├── images/
        │   ├── render_0001.png     # RGBA color
        │   ├── depth_0001.exr      # Depth (EXR)
        │   ├── depth_0001.png      # Depth (normalized PNG)
        │   ├── normal_0001.png     # Normal map
        │   ├── albedo_0001.png     # Albedo (base color)
        │   ├── position_0001.exr   # Position (EXR)
        │   ├── position_0001.png   # Position (normalized PNG)
        │   ├── metallic_0001.png   # Metallic (single channel, --mr only)
        │   └── roughness_0001.png  # Roughness (single channel, --mr only)
        ├── rgb.mp4                 # Color video (white background)
        ├── mask.mp4                # Alpha mask video
        ├── depth.mp4               # Depth video
        ├── normal.mp4              # Normal video
        ├── albedo.mp4              # Albedo video
        ├── position.mp4            # Position video
        ├── mr.mp4                  # Metallic/Roughness video (--mr only, see below)
        └── meta.json               # Camera parameters & render info

MR Video Channel Layout

mr.mp4 combines metallic and roughness into a 3-channel RGB video:

ChannelValueDescription
R (0)255Unused (constant white)
G (1)roughnessRoughness map (0-255)
B (2)metallicMetallic map (0-255)

Dataset Preparation (Batch)

For large-scale dataset rendering, two batch scripts handle multi-threaded, resumable processing of GLB lists.

Albedo / Normal / Position pass

Renders multi-pass channels (rgb, albedo, normal, position, depth, mask) for H and V orbits.

python scripts/batch_render_albedo.py \
    --input_json selected_glb_paths.json \
    --base_glb_path /path/to/glbs \
    --output_dir_h ./output_h --output_dir_v ./output_v \
    --num_camera 120 --threads 4 --skip 0

Metallic / Roughness pass

Renders PBR material properties (mr.mp4) using render.py --mr.

python scripts/batch_render_mr.py \
    --input_json selected_glb_paths.json \
    --base_glb_path /path/to/glbs \
    --output_dir_h ./output_h --output_dir_v ./output_v \
    --num_camera 120 --threads 4
ArgumentDescription
--input_jsonJSON list of relative GLB paths
--base_glb_pathRoot directory for GLB files
--output_dir_h/vOutput directories for H/V orbits
--num_cameraCameras per orbit (120)
--threadsParallel workers (1)
--skipResume from index N

Reconstruction: Bake Videos Back to GLB

验证数据集质量——用渲染视频 + 相机参数反向重建带 PBR 纹理的 GLB。

conda activate trellis2
python scripts/bake_pbr.py \
    --sha256 "000-058/{uuid}" \
    --glb_path ./glbs_normalized/{uuid}.glb \
    --albedo_h_video ./albedo_h.mp4 \
    --albedo_v_video ./albedo_v.mp4 \
    --mr_h_video ./mr.mp4 \
    --mr_v_video ./mr_v.mp4 \
    --h_meta ./meta_h.json \
    --v_meta ./meta_v.json \
    --output_dir ./output
输入来源
--albedo_h_video, --albedo_v_videoH/V 渲染产出的 albedo 视频
--mr_h_video, --mr_v_videoH/V 的 metallic/roughness 视频
--glb_pathglbs_normalized/ 目录下的归一化网格
--h_meta, --v_metaH/V 相机参数 (meta.json)
输出说明
bake_1024_a.glbPBR GLB (baseColor + metallicRoughness)
texture.pngAlbedo 纹理图集
texture_metallic.pngMetallic 纹理
texture_roughness.pngRoughness 纹理

Command-Line Options

ArgumentDefaultDescription
--input_file(required)Path to input GLB/OBJ/FBX/PLY file
--output_diroutputsBase output directory
--model_nameGLB filenameCustom model name for output subdirectory
--orbithorizontalCamera orbit: horizontal or vertical
--num_cameras120Number of camera positions
--flip_xfalseFlip right axis (left-right mirror) for vertical orbit
--engineCYCLES_GPURender engine: CYCLES_GPU, CYCLES_CPU, BLENDER_EEVEE
--width1024Render width in pixels
--height1024Render height in pixels
--fps24Video frame rate
--camera_radius1.5Camera orbit radius
--azimuth_offset-90Azimuth offset in degrees
--scene_scale1.0Scene normalization scale
--env_mapassets/env_textures/...HDR environment map path

Note: --flip_x is available as an optional correction if the vertical orbit produces flipped images relative to the horizontal orbit. Most models trained on non-flipped V data do not require this flag.

Requirements

  • Python 3.10
  • bpy 4.0.0 (Blender Python API)
  • numpy, imageio[ffmpeg], Pillow, scipy, tqdm
  • CUDA-compatible GPU (for CYCLES_GPU)