scimesh

Scimesh is a 3D renderer built for scientific mesh visualization, delivering publication-quality imagery entirely on the CPU.

Scientific compute environments are often constrained by the absence of graphical interfaces, specialized hardware, or complex driver stacks. Scimesh eliminates these bottlenecks by providing a zero-dependency, headless rendering pipeline—no OpenGL, no X11, and no GPU drivers required. Whether you are running complex visualization scripts on HPC clusters, inside isolated containers, or even on a modern macOS laptop where missing support for X11 makes traditional tools like rgl a challenge, Scimesh works reliably wherever your C++17 or R code runs.

Visualization Examples

Stanford Dragon rendered with scimesh

The Stanford Dragon (871k triangles), rendered with scimesh's software rasterizer using smooth shading, three-point Blinn-Phong lighting, and 4x anti-aliasing. Render time 5.2 seconds on the author's mini PC (AMD Ryzen 7 8745H CPU). Source code: R | C++

FreeSurfer reconstruction of human brain rendered with scimesh

A FreeSurfer reconstruction of a human brain surface based on an MRI scan (300k triangles), rendered with scimesh's software rasterizer using smooth shading, no anti-aliasing. Render time 1.8 seconds on the author's mini PC. Source code: R | C++

What scimesh is

Features

C++ layer

R Layer

The R layer gives access to all C++ layer features, and adds on top:

If you need colorbars in C++, have a look at scibar.

Global render defaults (R)

Anti-aliasing can be switched on for a whole session instead of per render call. render_options() resolves aa_samples from the global option scimesh.aa_samples (default 1, i.e. no AA) unless you pass it explicitly:

options(scimesh.aa_samples = 2)      # 2x2 supersampling, 4 for 4x4
img <- render_scene(scene(mesh))     # anti-aliased, no extra arguments needed
options(scimesh.aa_samples = NULL)   # back to no AA

This is most noticeable on screen-space lines and points (e.g. connectome edges, see line_layer() and render_segments()), which get smooth edges instead of a hard staircase pattern. The cost grows with aa_samples^2, both in render time and in memory (the internal framebuffer is width * aa_samples by height * aa_samples).

Text labels (R)

text_layer() annotates a figure. Labels are billboards: they always face the camera and keep their size in pixels, and the font ships with the package, so no system font is needed. Positions are either world space (the label sticks to the 3D location it annotates, and is hidden when geometry is in front of it) or screen space (space = "screen", pixels from the top left corner):

surf <- generate_sphere(c(0, 0, 0), radius = 1)
cam  <- camera_auto(list(surf), direction = c(0, 0, 1))

sc <- scene(list(surf), camera = cam,
            options = render_options(background_color = c(1, 1, 1, 1)),
            texts = list(
                # a label that belongs to the scene, anchored above the sphere
                text_layer(matrix(c(0, 1.3, 0), ncol = 3), "superior",
                           size = 20, adj = c(0.5, 0)),
                # a direction annotation that must stay readable: no depth test
                text_layer(matrix(c(1.4, 0, 0), ncol = 3), "anterior",
                           size = 18, adj = c(0, 0.5),
                           colors = c(0.8, 0.1, 0.1, 1), depth_test = FALSE),
                # a panel tag, positioned in output pixels
                text_layer(c(12, 10), "A", space = "screen", adj = c(0, 1),
                           size = 28, halo_color = c(1, 1, 1, 0.9))))
img <- render_scene(sc)

Labels can also be measured (text_extent()), projected from 3D to image pixels (world_to_screen()), rotated (rotation = 90 reads bottom to top, for a vertical axis label), and used without any mesh (render_text()). Use font_file = "path/to/font.ttf" or the SCIMESH_FONT environment variable to replace the bundled Inter font.

What scimesh is not

Installation

R package

# Install from GitHub
# remotes::install_github("dfsp-spirit/scimesh")
install.packages("scimesh", repos = c('https://dfsp-spirit.r-universe.dev', 'https://cloud.r-project.org'))

# For FreeSurfer neuroimaging data
remotes::install_github("dfsp-spirit/freesurferformats")

C++

Via CMake FetchContent (recommended)

include(FetchContent)
FetchContent_Declare(
    scimesh
    GIT_REPOSITORY https://github.com/dfsp-spirit/scimesh.git
    GIT_TAG        main          # or a release tag, e.g. v0.2.8
)
FetchContent_MakeAvailable(scimesh)

add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE scimesh)

That's it — no manual source listing, include paths, or preprocessor defines needed.

Manually (header + source)

The C++ core lives in src/core/. To use scimesh in a C++ project without CMake, add the source files and include paths to your build system. See CPP_GETTING_STARTED.md for details.

Quick Start

R

library(scimesh)

sphere <- generate_sphere(c(0, 0, 0), radius = 1.2,
                          segments = 32, color = c(0.9, 0.3, 0.2, 1.0))
cam <- camera_auto(sphere, direction = c(1.2, 0.8, 1))

# Flat-shaded sphere
img_shaded <- render_mesh(sphere$vertices, sphere$triangles,
    colors = sphere$colors, camera = cam,
    options = render_options(
        background_color = c(1, 1, 1, 1),
        lights = list(
            list(position = c(0.5, 1.0, 0.8), intensity = 1.5),
            list(position = c(-0.5, 0.2, 0.6), intensity = 0.5))))

# Wireframe sphere
img_wire <- render_mesh(sphere$vertices, sphere$triangles,
    colors = sphere$colors, camera = cam,
    options = render_options(wireframe = TRUE,
        wireframe_color = c(0, 0, 0, 1),
        background_color = c(1, 1, 1, 1),
        backface_culling = FALSE))

# Side-by-side
img <- stack_horizontal(img_shaded, img_wire)
write_png(img, "sphere.png")

C++

Documentation

Direct Links to Example Program Source Code

Example Language Description
examples/R/spot_cow/ R Textured OBJ mesh (Spot cow) with multi-light setup
examples/R/transparency/ R Semi-transparent pial overlay on white matter
examples/R/primitives/ R All geometric primitives demo
examples/R/dragon/ R Stanford Dragon with SSAO, specular, and 4x AA
examples/R/whole_brain_sulc/ R Whole-brain sulcal depth rendering
examples/R/video_frames_orbit/ R Turntable video from orbit frames
examples/cpp/spot_cow/ C++ Textured OBJ rendering with bilinear sampling
examples/cpp/bunny/ C++ High-quality Stanford Bunny with SSAO, specular, and 4x AA
examples/cpp/dragon/ C++ Stanford Dragon with SSAO, specular, and 4x AA
examples/cpp/all_primitives/ C++ All geometric primitives demo
examples/cpp/transparency/ C++ Multi-mesh alpha blending with FreeSurfer data
examples/cpp/protein_data_bank_pdb_file/ C++ Protein ball-and-stick visualization from PDB files
examples/cpp/whole_brain_sulc/ C++ Whole-brain sulcal depth rendering
examples/cpp/whole_brain_sulc_fsaverage/ C++ Same on fsaverage template
examples/cpp/whole_brain_annot/ C++ Cortical parcellation visualization
examples/cpp/brain_video/ C++ Turntable brain animation via camera_orbit()
examples/cpp/full_CLI_renderer/ C++ Self-contained CLI renderer with TOML config + CLI overrides

Acknowledgements

Thanks heaps to the authors of these great software packages that scimesh is built upon:

And of course, thanks to the authors of the dependencies of these packages, and their dependencies...

Detailed information on the licenses for all these packages (all MIT-compatible) can be found in the file THIRD_PARTY_LICENSES.md.

Note: This section is to give credit only. Users do not need to worry about installing these dependencies, they come vendored with scimesh already.

Developer Information

Please refer to README_DEVELOPMENT.md.

License and Author

License: MIT

Author: Tim Schäfer