Skip to main content

Render PyVista plotter scenes through Blender (bpy) for photoreal output.

Project description

pyvista-blender

[!WARNING] Very early development. APIs, defaults, and module layout will change without notice until the first stable release. Bug reports, missing-feature requests, and PRs are all very welcome — please open an issue if something doesn't work or behaves surprisingly.

Render PyVista plotter scenes through Blender (bpy) — photoreal output, full animation export, no file round-trip.

Build the scene once in PyVista. Pick VTK's preview or Blender's Cycles / Eevee Next for the final render. Export entire deforming, colour-evolving, lit animations to a single .blend that plays natively in Blender with no Python script inside.

Showcase

These structural mechanics examples start as PyVista scenes and use Blender for the final render. The transparent animated WebP previews link to the transparent VP9 WebM files.

I-beam bending stress animation Gyroid compression stress animation
I-beam bending
Fedoo stress animation with support and load geometry.
Gyroid compression
Metallic gyroid material revealed through a stress-alpha overlay.

Status

Initial public release (0.1.0). The offline render path, the desktop and browser interactive viewports, the Jupyter inline backend, and the full animation export to .blend are implemented and tested. The full ruff (select = ["ALL"]) + ty + format gate is clean. See the features list in the docs for the full surface and the architecture page for the translation pipeline.

Install

pip install pyvista-blender
# or
uv add pyvista-blender

For the Jupyter inline backend and the Trame-served browser viewport (pl.blender.show(backend="web")), install pyvista[jupyter] alongside; the bridge reuses pyvista's Trame stack rather than shipping its own extras.

pip install pyvista-blender 'pyvista[jupyter]'

Requires Python 3.11 (Blender 4.5 LTS via bpy>=4.5,<5) or 3.13 (Blender 5.x via bpy>=5.0,<6). Python 3.10, 3.12, and 3.14 have no matching bpy wheel on PyPI; requires-python blocks them.

Quick start

import pyvista as pv

pl = pv.Plotter(off_screen=True, window_size=(1920, 1080))
pl.add_mesh(pv.read("data.vtu"), scalars="von_mises", cmap="viridis", pbr=True)
pl.add_light(pv.Light(position=(5, -5, 5), light_type="scene light"))
pl.camera_position = "iso"

# Offline render via Cycles + OptiX denoise. No `import pyvista_blender`
# needed — the namespace registers itself on install through PyVista
# 0.48's plotter-component entry point.
pl.blender.render("frame.png", samples=128)

# Interactive hybrid viewport: VTK 60 fps during drag, Cycles render
# on mouse release. One window, mouse-driven, no auto-exec prompts.
pl.blender.show()

API surface

Entry point What it does
pl.blender.render(path, ...) Render a single frame to PNG via Cycles or Eevee Next.
pl.blender.animate(path, updater, frames, fps=...) Render an animation as gif / mp4 / webm / mov / mkv via imageio + imageio-ffmpeg.
pl.blender.show() Hybrid VTK / Cycles interactive viewport — VTK during drag, settled Cycles on release.
pl.blender.add_glyph(source, geom, *, orient, scale, factor) Geometry-Nodes-instanced glyphs; memory cost scales N + V instead of N · V.
pl.blender.export_blend(path) Save the live PyVista scene as a .blend for finishing in Blender.
pl.blender.export_animation_blend(path, updater, frames, fps, **bake) Bake a full animation into a .blend that plays natively on file open.
pl.blender.orbit_camera(n_frames=...) Build an updater for animate / export_animation_blend.

Three-tier config resolution everywhere: per-call kwarg → component attribute (pl.blender.engine = ...) → module default (pyvista_blender.config.*).

Animation export to .blend

export_animation_blend bakes each animation channel through its own opt-in kwarg. Every backend plays back natively when the file is opened in Blender — no Python in the .blend, no auto-execution prompt, no need to "Run Scripts" on load.

Kwarg Mechanism File layout
bake_camera=True (default) Keyframes on scene.camera.location + rotation_quaternion per frame inside .blend
bake_deformation="shape_keys" One Shape Key per frame, value-keyframed with linear interpolation inside .blend
bake_deformation="mdd" (= True) Lightwave MDD sidecar + MESH_CACHE modifier .blend + __<mesh>.mdd
bake_scalars=True Packed PNG (rows = frames, columns = vertices / cells) + Geometry Nodes graph; works for point-data and cell-data scalars inside .blend
bake_lights=True Per-light keyframes on location, rotation, energy, color inside .blend

Example: full multi-channel animation in one self-contained file.

import numpy as np
import pyvista as pv

pl = pv.Plotter(off_screen=True, window_size=(1280, 720))
plane = pv.Plane(i_resolution=60, j_resolution=60)
plane.cell_data["heat"] = np.zeros(plane.n_cells, dtype=np.float32)
pl.add_mesh(plane, scalars="heat", cmap="inferno", clim=[-1.0, 1.0])

light = pv.Light(position=(5, 0, 4), light_type="scene light", intensity=1.0)
pl.add_light(light)

n_frames = 60
orbit = pl.blender.orbit_camera(n_frames=n_frames)
centers_xy = plane.cell_centers().points[:, :2]


def update(frame: int) -> None:
    orbit(frame)
    angle = -frame * (2.0 * np.pi / n_frames)
    light.position = (5.0 * np.cos(angle), 5.0 * np.sin(angle), 5.0)
    light.intensity = 0.4 + 0.6 * (0.5 + 0.5 * np.sin(frame * 0.3))
    r = np.linalg.norm(centers_xy, axis=1)
    plane.cell_data["heat"] = np.sin(2.0 * r - frame * 0.2).astype(np.float32)


pl.blender.export_animation_blend(
    "scene.blend",
    update,
    frames=range(n_frames),
    fps=30,
    bake_camera=True,
    bake_lights=True,
    bake_scalars=True,
)
pl.close()

Open scene.blend in Blender 4.5+ / 5.x and press Space: camera orbits, the explicit light orbits in the opposite direction while pulsing, the heat field travels as a radial wave with flat per- cell shading. One file, ~500 KB, nothing to ship alongside.

Development

uv sync --group dev --no-install-package bpy  # fast local sync (no 200 MB bpy wheel)
uvx prek install                              # install pre-commit hooks
uv run pytest                                 # ~10 s with bpy installed
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run ty check

Real bpy is only needed for the @pytest.mark.bpy tests. CI runs the full suite against the live wheel.

License

GPL-3.0-or-later. Forced by bpy's license; every source file carries an SPDX header. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyvista_blender-0.1.0.tar.gz (136.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyvista_blender-0.1.0-py3-none-any.whl (156.3 kB view details)

Uploaded Python 3

File details

Details for the file pyvista_blender-0.1.0.tar.gz.

File metadata

  • Download URL: pyvista_blender-0.1.0.tar.gz
  • Upload date:
  • Size: 136.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pyvista_blender-0.1.0.tar.gz
Algorithm Hash digest
SHA256 00cb7e52aee3485ff9670bd1ebe4a3724489644d6675852ccba39cafcaad7ca0
MD5 4f13785ef821fc1ff8eb9cb324e8207d
BLAKE2b-256 cbc2acf1f432f2936ce142ab4784b9d3f555c8221130e3e56649804e3b1fe0f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyvista_blender-0.1.0.tar.gz:

Publisher: release.yml on kmarchais/pyvista-blender

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyvista_blender-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pyvista_blender-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 156.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pyvista_blender-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6d0bf07dfdda51af183c6d3166bc86dfbc0e8a2a5bd5b66ee72e1d247924b727
MD5 5c404f9561f84bc43ea32afab3bb0664
BLAKE2b-256 94f5d08defd5bfdcc4933da36edc0c8beb143e8cd583450bc503fb899d4caec4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyvista_blender-0.1.0-py3-none-any.whl:

Publisher: release.yml on kmarchais/pyvista-blender

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page