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.

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++

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++
camera_fit_mesh, camera_fit_scene)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.
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_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.
# 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")
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.
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.
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")
vignettes/scimesh.Rmd — comprehensive guide to the
R package with examples for all major features.examples/R/ — runnable scripts
demonstrating textured rendering, transparency, and neuroimaging
visualization.?<function>, where you replace <function> with a function name. Like this: ?read_ply.example(<function>) to see a live demo that uses the function <function>. Like this: example(read_ply).cpp_getting_started.html
— gentle introduction to the C++ renderer.
\subpage cpp_getting_startedexamples/cpp/ — standalone
programs covering textured OBJ, transparency, protein visualization,
and whole-brain rendering.| 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 |
Thanks heaps to the authors of these great software packages that scimesh is built upon:
cpp_tests/catch_amalgamated.{h,cpp}: catchorg/Catch2 — C++ test framework by Martin Hořeňovskýsrc/third_party/glm/: g-truc/glm — header-only C++ math library.src/third_party/tinyply.{h,cpp}: ddiakopoulos/tinyply — PLY file reader by Dimitri Diakopoulossrc/third_party/libfs.h: dfsp-spirit/libfs — FreeSurfer file format reader + OBJ mesh loader by Tim Schäfersrc/third_party/stl_reader.h: sreiter/stl_reader — STL file reader, maintained by Sebastian Reitersrc/third_party/stb_image.h, src/third_party/stb_image_write.h: nothings/stb — image loading/saving, maintained by Sean BarrettAnd 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.
Please refer to README_DEVELOPMENT.md.
License: MIT
Author: Tim Schäfer