| Type: | Package |
| Title: | Headless Publication-Quality 3D Mesh Rendering Engine |
| Version: | 0.4.0 |
| Description: | A fast, GPU-free 3D software renderer written in modern C++17 with native R bindings. Renders triangle meshes to publication-quality images entirely on the CPU, requiring no display server or graphics hardware. Features multi-light Blinn-Phong shading, screen-space ambient occlusion, anti-aliasing, depth fog, transparency, wireframe rendering, texture mapping, screen-space lines and text labels, and procedural geometry generation. Supports standard mesh file formats with PNG and PPM output. Works on high-performance computing clusters, headless servers, containers, and continuous integration pipelines, making it suitable for scientific visualization across neuro-imaging, molecular structures, and general 3D graphics. |
| License: | MIT + file LICENSE |
| URL: | https://github.com/dfsp-spirit/scimesh, https://dfsp-spirit.github.io/scimesh/ |
| BugReports: | https://github.com/dfsp-spirit/scimesh/issues |
| Imports: | Rcpp (≥ 1.0.0) |
| LinkingTo: | Rcpp |
| Suggests: | testthat (≥ 3.0.0), png, freesurferformats, viridisLite, knitr, rmarkdown |
| VignetteBuilder: | knitr |
| SystemRequirements: | C++17 |
| Config/testthat/edition: | 3 |
| Encoding: | UTF-8 |
| NeedsCompilation: | yes |
| Config/roxygen2/version: | 8.0.0 |
| RoxygenNote: | 7.3.3 |
| Packaged: | 2026-09-22 19:50:37 UTC; ts |
| Author: | Tim Schäfer [aut, cre], Martin Hořeňovský [ctb] (Author of Catch2 (cpp_tests/catch_amalgamated.{h,cpp})), Christophe Riccio [ctb] (Author of GLM - OpenGL Mathematics (src/third_party/glm/)), Dimitri Diakopoulos [ctb] (Author of tinyply (src/third_party/tinyply.{h,cpp})), Tim Schäfer [ctb] (Author of libfs (src/third_party/libfs.h)), Sebastian Reiter [ctb] (Author of stl_reader (src/third_party/stl_reader.h)), Sean Barrett [ctb] (Author of stb libraries (src/third_party/stb_image*.h, src/third_party/stb_truetype.h)), Rasmus Andersson [ctb] (Author of the Inter font (inst/extdata/Inter-Regular.ttf, SIL OFL 1.1)) |
| Maintainer: | Tim Schäfer <ts+code@rcmd.org> |
| Repository: | CRAN |
| Date/Publication: | 2026-09-22 20:40:02 UTC |
Apply a colormap to numerical data
Description
Maps numeric per-vertex (or per-element) data to RGBA colours using a colormap. Handles multi-dataset data (e.g., two brain hemispheres), NaN values, and optional outlier clipping via winsorizing.
Usage
apply_colormap(
data,
colormap = viridis_colormap(256L),
limits = NULL,
nan_color = c(0.5, 0.5, 0.5, 1),
winsor_percentiles = NULL
)
Arguments
data |
A numeric vector, or a list of numeric vectors for multi-dataset mapping (e.g., list(lh_data, rh_data)). |
colormap |
A colormap specification: a function f(n) returning n hex colour strings (e.g., viridis_colormap), a character vector of hex colours, or an Nx3/Nx4 matrix of RGBA values in [0,1]. Default is viridis_colormap(256L). |
limits |
How the data value range is determined. NULL (default) auto-detects from finite values after winsorizing. c(min, max) sets an explicit fixed range. "global" pools all datasets for a shared range. "each" uses independent per-dataset ranges. |
nan_color |
RGBA colour for NaN/NA values as a length-3 (RGB) or length-4 (RGBA) numeric vector in [0,1]. Default mid-grey. |
winsor_percentiles |
Optional c(lower, upper) percentiles for outlier clipping, e.g. c(0.02, 0.98). NULL disables winsorizing. |
Value
If data is a single vector: an Nx4 numeric matrix of RGBA colours. If data is a list: a list of Nx4 matrices.
Attributes on the result provide metadata. Single-dataset: data_min, data_max, raw_min, raw_max, winsor_lo, winsor_hi, nan_count. Multi-dataset: pooled_data_min, pooled_data_max (use for a colourbar), data_ranges, winsor_cutoffs, nan_counts.
Examples
data <- c(1.2, 3.4, NA, 2.1, 5.0, 2.8)
colors <- apply_colormap(data)
noisy <- c(rnorm(95, mean = 50, sd = 10), 200, -50)
colors <- apply_colormap(noisy, winsor_percentiles = c(0.02, 0.98))
lh <- c(2.3, 2.1, NA, 3.4)
rh <- c(2.5, 2.0, NA, 3.1)
colors <- apply_colormap(list(lh, rh),
colormap = viridis_colormap(256L),
limits = "global",
winsor_percentiles = c(0.02, 0.98),
nan_color = c(1, 1, 1, 1))
Convert rgl or scimesh mesh to canonical scimesh format
Description
Internal helper that transparently accepts either an rgl-style mesh
(list with vb/it) or a scimesh mesh descriptor
(list with vertices/triangles) and returns the
canonical scimesh format.
Usage
as_scimesh_mesh(x)
Arguments
x |
A mesh-like object (rgl tmesh3d or scimesh mesh descriptor). |
Value
A scimesh mesh descriptor list with vertices and
triangles.
Sample a Bezier curve from a control polygon
Description
Evaluates a Bezier curve of any degree with de Casteljau's algorithm. Unlike
spline_path, the control points are **not** points on the curve:
only the first and the last one are, and the rest pull the curve like a
magnet. This is the function to use when the input really is a control
polygon (a font outline, a vector graphics path, a designed shape); use
spline_path when your points are positions the curve should
pass through.
Usage
bezier_path(control_points, samples = 64L)
Arguments
control_points |
Nx3 numeric matrix of control points (at least 2). |
samples |
Number of points to emit along the curve (default 64, at least 2). Both endpoints are included in the result. |
Value
An Nx3 numeric matrix of path points, or an empty (0-row) matrix if there are fewer than two control points.
See Also
Examples
# A quadratic Bezier arc, drawn as a tube:
arc <- bezier_path(matrix(c(0, 0, 0, 1, 1, 0, 2, 0, 0), ncol = 3, byrow = TRUE))
nrow(arc)
Create a camera specification
Description
Defines a camera for rendering by specifying the eye position, look-at center, up vector, projection type, and field of view.
Usage
camera(
eye,
center,
up = c(0, 1, 0),
projection = c("perspective", "orthographic"),
fov = 45
)
Arguments
eye |
Numeric vector of length 3: camera position. |
center |
Numeric vector of length 3: point the camera looks at. |
up |
Numeric vector of length 3: camera up direction. |
projection |
Projection type: |
fov |
Field of view in degrees (perspective only). |
Value
A camera list suitable for render_mesh() or
render_scene().
Examples
cam <- camera(eye = c(0, 0, 5), center = c(0, 0, 0))
cam$eye
Auto-frame a camera to fit a mesh or vertex set
Description
Computes a camera position that frames the entire mesh in view.
The camera is placed on the side given by direction and looks
back at the mesh, at a distance that ensures the mesh fits within the
field of view.
Usage
camera_auto(
mesh,
direction = c(0, 0, -1),
up = c(0, 1, 0),
fov = 45,
margin = 1.1,
rgl_compat = FALSE,
projection = c("perspective", "orthographic")
)
Arguments
mesh |
Either an Nx3 numeric matrix of vertex positions, or a
mesh descriptor list with a |
direction |
Direction from the mesh towards the camera, as a
length-3 vector: it selects the side you view the mesh from (the
camera is placed at |
up |
The up vector as a length-3 vector. Default |
fov |
Field of view in degrees. Default 45° (30° when
|
margin |
Extra margin factor (1.0 = tight fit, 1.1 = 10% margin). |
rgl_compat |
Logical. If |
projection |
Projection type: |
Details
When rgl_compat = TRUE, the camera mimics rgl's default
auto-framing behaviour: a 30° FOV, 15° elevation, and the distance
is computed from the bounding sphere of the mesh (the
half-diagonal of the axis-aligned bounding box), reproducing the
formula distance = sphere_radius / sin(FOV/2) used by rgl.
Value
A camera list, with S3 class "scimesh_camera".
Note
This function frames a mesh (or a set of vertices). It does not know
about scene contents such as line layers or text labels; use
camera_fit_scene to fit a camera to a whole scene, including
the line layers that contribute to the scene bounds.
Examples
verts <- matrix(c(-1,-1,-1, 1,-1,-1, 1,1,-1, -1,1,-1,
-1,-1, 1, 1,-1, 1, 1,1, 1, -1,1, 1), ncol = 3, byrow = TRUE)
tris <- matrix(c(0L,3L,2L, 0L,2L,1L, 4L,5L,6L, 4L,6L,7L,
0L,1L,5L, 0L,5L,4L, 2L,3L,7L, 2L,7L,6L,
0L,4L,7L, 0L,7L,3L, 1L,2L,6L, 1L,6L,5L), ncol = 3, byrow = TRUE)
mesh <- list(vertices = verts, triangles = tris)
cam <- camera_auto(mesh, direction = c(1, 1, 1))
cam_rgl <- camera_auto(mesh, rgl_compat = TRUE)
Fit a camera to a whole scene
Description
Computes a camera that frames the contents of a scene (see
scene), i.e. its meshes together with the line layers that
contribute to the scene bounds (see line_layer, parameter
affects_bounds). Use this instead of camera_auto when
the camera has to consider something else than a mesh: a scene that contains
only line layers (e.g. a tractogram or a connectome without a brain surface)
is framed by those lines, and decorational layers
(affects_bounds = FALSE) are ignored.
Usage
camera_fit_scene(
scene,
direction = c(0, 0, -1),
up = c(0, 1, 0),
fov = 45,
margin = 1.1,
projection = c("perspective", "orthographic")
)
Arguments
scene |
A scene descriptor list, see |
direction |
Length-3 view direction, from the camera towards the scene
(default |
up |
Length-3 up vector (default |
fov |
Vertical field of view in degrees (default 45). |
margin |
Scale factor applied to the fitted distance; values above 1 leave a margin around the content (default 1.1). |
projection |
Projection type, |
Details
The camera is placed on the line from the center of the bounding box along
direction, at a distance that makes the content fit into the field of
view, exactly like camera_auto does it for a mesh.
Value
A camera list (see camera()) with class
"scimesh_camera".
See Also
camera_auto for meshes, scene,
scene_set_line_affects_bounds
Examples
# A scene without any mesh is framed by its lines.
line <- line_layer(matrix(c(0, 0, 0), ncol = 3), matrix(c(2, 0, 0), ncol = 3))
sc <- scene(list(), lines = line)
cam <- camera_fit_scene(sc, direction = c(0, 0, -1))
Orbit a camera around an axis
Description
Rotates a camera's eye position and up vector around its center by a given angle about a rotation axis. Useful for generating turntable-style frame sequences.
Usage
camera_orbit(camera, axis = c(0, 0, 1), angle_degrees)
Arguments
camera |
A camera list from |
axis |
Rotation axis as a length-3 vector. Default |
angle_degrees |
Rotation angle in degrees. |
Value
A camera list with S3 class "scimesh_camera".
Examples
mesh <- generate_torus(c(0, 0, 0))
cam <- camera_auto(mesh, direction = c(1, 1, 1))
cam2 <- camera_orbit(cam, axis = c(0, 0, 1), angle_degrees = 90)
Validate a Catmull-Rom parameterization exponent
Description
Validate a Catmull-Rom parameterization exponent
Usage
check_alpha(alpha)
Arguments
alpha |
Requested exponent. |
Value
The value as a double.
Validate a logical flag
Description
Validate a logical flag
Usage
check_flag(value, arg_name)
Arguments
value |
Requested value. |
arg_name |
Name of the argument, used in error messages. |
Value
A single logical.
Validate and normalize a set of 3D points
Description
Internal helper shared by the generator and render functions. Accepts an Nx3 numeric matrix or a single length-3 numeric vector (which is treated as a single point) and returns an Nx3 numeric matrix of storage mode double, as expected by the C++ layer. An empty (0-row) matrix is allowed and means "no points"; the generators then return an empty mesh.
Usage
check_points_matrix(x, arg_name = "x")
Arguments
x |
A numeric matrix with 3 columns, or a length-3 numeric vector. |
arg_name |
Name of the argument, used in error messages. |
Value
An Nx3 numeric matrix.
Validate a sample count
Description
Validate a sample count
Usage
check_sample_count(samples_per_segment)
Arguments
samples_per_segment |
Requested number of samples. |
Value
The value as an integer.
Create a clip plane specification
Description
Defines a clipping plane for render_options(). Geometry on the
negative side of the plane is removed, i.e. a point p is kept when
dot(normal, p) + offset >= 0.
Usage
clip_plane(normal, offset = 0, space = c("world", "eye"))
Arguments
normal |
Numeric vector of length 3: the plane normal. It points
toward the side of the plane that is kept. It does not have to be
unit-length; it is normalized internally and |
offset |
Numeric scalar: the signed distance of the plane from the
origin along |
space |
Character, either
|
Details
By default the plane is defined in world space, so the cut is a
fixed feature of the scene: it does not move when the camera is moved
around, which is what you want for cross-sections and multi-view figures.
Set space = "eye" for a camera-relative plane that travels with the
camera (the classic OpenGL glClipPlane behaviour), e.g. for
cutaway views.
Value
A list with components normal, offset and
space, suitable for the clip_planes argument of
render_options().
See Also
Examples
# World space (default): keep the half of the scene with x <= 0.
# The cut stays at x = 0, no matter where the camera is placed.
clip_plane(normal = c(-1, 0, 0), offset = 0)
# Keep only the part with z >= -0.5 (remove everything below z = -0.5):
clip_plane(normal = c(0, 0, 1), offset = 0.5)
# Eye space: remove everything closer than 2 units to the camera
# (a camera-attached cutaway).
clip_plane(normal = c(0, 0, -1), offset = -2, space = "eye")
# A world-space cut through a cuboid; the cut stays at x = 0 for any camera
cuboid <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
cut_opts <- render_options(clip_planes = list(
clip_plane(normal = c(-1, 0, 0), offset = 0)))
mesh_pixels <- function(img) sum(image_to_array(img)[, , 1] < 1)
cam <- camera(eye = c(3, 3, 3), center = c(0, 0, 0))
full <- render_mesh(cuboid$vertices, cuboid$triangles, camera = cam)
cut <- render_mesh(cuboid$vertices, cuboid$triangles, camera = cam,
options = cut_opts)
mesh_pixels(cut) < mesh_pixels(full) # TRUE: half of the cuboid is gone
Generate a horizontal colorbar image
Description
Creates a horizontal colorbar as a 4-channel RGBA array. The color
strip and optional tick labels are rendered to PNG using base R
graphics (headless-safe). Returns a 3D array suitable for
image_to_array() or direct composition.
Usage
colorbar_horizontal(
colormap,
n_colors = 256L,
width = 600L,
height = 80L,
ticks = NULL,
tick_labels = NULL,
data_range = c(0, 1),
label_cex = 1,
title = NULL,
background = c(1, 1, 1, 1)
)
Arguments
colormap |
A vector of colors or a function returning colors
(e.g. |
n_colors |
Number of discrete color segments in the gradient. |
width |
Output width in pixels. |
height |
Output height in pixels. |
ticks |
Numeric vector of tick positions in data units
(matching |
tick_labels |
Character vector of tick labels. If |
data_range |
The data range that |
label_cex |
Label size multiplier. |
title |
Optional title string drawn above the color strip (horizontal) or to the right (vertical). |
background |
Background RGBA color (0-1 scale). |
Value
A 3D array of dimensions (height, width, 4) with values in
[0, 1].
Examples
cbar <- colorbar_horizontal(viridis_colormap, data_range = c(-2, 3),
title = "Value")
dim(cbar) # height x width x 4
Generate a vertical colorbar image
Description
Creates a vertical colorbar as a 4-channel RGBA array.
Usage
colorbar_vertical(
colormap,
n_colors = 256L,
width = 80L,
height = 600L,
ticks = NULL,
tick_labels = NULL,
data_range = c(0, 1),
label_cex = 1,
title = NULL,
background = c(1, 1, 1, 1)
)
Arguments
colormap |
A vector of colors or a function returning colors. |
n_colors |
Number of discrete color segments in the gradient. |
width |
Output width in pixels. |
height |
Output height in pixels. |
ticks |
Numeric vector of tick positions in data units.
If |
tick_labels |
Character vector of tick labels. |
data_range |
The data range that |
label_cex |
Label size multiplier. |
title |
Optional title string drawn to the right of the color strip. |
background |
Background RGBA color (0-1 scale). |
Value
A 3D array of dimensions (height, width, 4) with values in
[0, 1].
Examples
cbar <- colorbar_vertical(viridis_colormap, data_range = c(0, 100),
title = "Count")
dim(cbar)
Compose multiple images into a single figure
Description
Arranges rendered images (from render_mesh() or
render_scene()) into a grid layout and optionally appends
a colorbar. All composition is done with pure R array operations.
Usage
compose_layout(
images,
nrow = NULL,
ncol = NULL,
colorbar = NULL,
colorbar_height = 80L,
colorbar_width = 80L,
background = c(0, 0, 0, 0),
colorbar_side = c("right", "left"),
crop = FALSE
)
Arguments
images |
A list of images, each a list with |
nrow |
Number of rows in the grid layout. |
ncol |
Number of columns in the grid layout. If both
|
colorbar |
Optional colorbar array (from
|
colorbar_height |
Height of the colorbar row in pixels. Only used when appending a horizontal colorbar. |
colorbar_width |
Width of the colorbar column in pixels. Only used when appending a vertical colorbar. |
background |
Background RGBA color for padding (0-1 scale). |
colorbar_side |
For vertical colorbars, whether to place
the bar on the |
crop |
Logical. If |
Value
A list with width, height, pixels
suitable for write_png() or image_to_array().
Examples
mesh1 <- generate_cuboid(c(-1.5, 0, 0), c(0.5, 0.5, 0.5), c(1, 0, 0, 1))
mesh2 <- generate_cuboid(c( 1.5, 0, 0), c(0.5, 0.5, 0.5), c(0, 0, 1, 1))
img1 <- render_mesh(mesh1$vertices, mesh1$triangles)
img2 <- render_mesh(mesh2$vertices, mesh2$triangles)
result <- compose_layout(list(img1, img2), nrow = 1L)
tmp_file <- tempfile(fileext = ".png")
write_png(result, tmp_file)
Compute per-vertex normals for a mesh
Description
Computes smooth vertex normals by averaging face normals. Returns
the same mesh with a normals component (Nx3 numeric matrix).
Useful for imported meshes that lack pre-computed normals.
Usage
compute_vertex_normals(mesh)
Arguments
mesh |
A mesh descriptor list with |
Value
The mesh with a normals component added.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
mesh <- compute_vertex_normals(mesh)
nrow(mesh$normals)
Path of the font used for text labels
Description
Text labels are drawn with a TrueType font that ships with the package
(inst/extdata/Inter-Regular.ttf, SIL Open Font License 1.1), so labels
look the same everywhere and no system font is required. This function
returns the path of the font that will be used by default.
Usage
default_font()
Details
It can be overridden without touching any code by setting the
SCIMESH_FONT environment variable to the path of another .ttf
file, or per call by passing font_file to
text_layer(), text_extent() and friends.
Value
A character scalar: the path to an existing font file.
See Also
Examples
default_font()
Custom diverging colormap for neuroimaging
Description
Returns a blue-white-red diverging colormap suitable for displaying signed morphometry data (e.g. cortical thickness Z-scores).
Usage
diverging_colormap(n)
Arguments
n |
Number of colors. |
Value
A character vector of hex color strings.
Examples
cols <- diverging_colormap(256)
plot(1:256, pch = 15, col = cols, cex = 2, axes = FALSE, xlab = "", ylab = "")
Flip the texture coordinates of a mesh vertically
Description
scimesh stores texture coordinates in image space, with v = 0
at the top edge of the texture image — the same rule as every other
coordinate in scimesh (c(0, 0) addresses the top-left pixel of the
texture image, c(1, 1) the bottom-right one). OBJ and PLY files,
OpenGL, rgl and tools like Blender and MeshLab use the opposite convention
(v = 0 at the bottom), so UVs taken from those sources have to be
converted once; this function does that, instead of you having to rewrite the
second column by hand.
Usage
flip_uvs(mesh)
Arguments
mesh |
A mesh descriptor (scimesh or rgl format, see
|
Details
Geometry, colors and normals are untouched. A mesh without texture coordinates is returned unchanged, so calling this is safe either way.
Value
The mesh with flipped UVs.
See Also
render_mesh (the uv and texture
arguments)
Examples
quad <- list(vertices = matrix(c(-1, -1, 0, 1, -1, 0, 1, 1, 0,
-1, -1, 0, 1, 1, 0, -1, 1, 0),
ncol = 3, byrow = TRUE),
triangles = matrix(c(1, 2, 3, 1, 3, 4), ncol = 3, byrow = TRUE),
# UVs with v = 0 at the bottom (OBJ/OpenGL convention)
uv = matrix(c(0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0),
ncol = 2, byrow = TRUE))
flipped <- flip_uvs(quad)
flipped$uv[, 2] # v is now measured from the top of the texture
Information about the font used for text labels
Description
Reports which font file is used (and where it lives), its family name and
its vertical metrics. Useful to check that the bundled font was found and to
see what a custom .ttf file contains.
Usage
font_info(font_file = NULL, size = 18)
Arguments
font_file |
Path to a |
size |
Text height in output pixels (default 18). |
Value
A list with components family, path, size,
ascent, descent and line_gap.
See Also
Examples
font_info()
Generate an arrow mesh
Description
Creates a 3D arrow from from to to, with a cylindrical
shaft and a conical head.
Usage
generate_arrow(
from,
to,
shaft_radius = 0.1,
head_radius = 0.3,
head_length = 0.6,
segments = 32,
color = c(1, 1, 1, 1)
)
Arguments
from |
Length-3 start point. |
to |
Length-3 end point (tip of the arrowhead). |
shaft_radius |
Radius of the shaft cylinder. |
head_radius |
Radius at the base of the conical head. |
head_length |
Length of the arrowhead. |
segments |
Subdivision count (default 32). |
color |
Length-4 RGBA colour. |
Value
A mesh descriptor list.
Examples
mesh <- generate_arrow(c(0, 0, 0), c(0, 2, 0))
nrow(mesh$vertices)
Generate XYZ axis arrows as cylinder meshes
Description
Creates three coloured arrow meshes (red X, green Y, blue Z) from a centre point.
Usage
generate_axes(center = c(0, 0, 0), size = 1, shaft_radius = 0.02)
Arguments
center |
Length-3 vector: origin of the axes. |
size |
Length of each axis. |
shaft_radius |
Cylinder radius for axis shafts. |
Value
A mesh descriptor list suitable for render_mesh()
or inclusion in a scene list.
Examples
axes_mesh <- generate_axes(size = 2)
nrow(axes_mesh$vertices)
Generate a wireframe bounding box mesh
Description
Creates 12 edge segments around an axis-aligned bounding box.
Usage
generate_bbox(bbox, color = c(0, 0, 0, 1), radius = 0.01)
Arguments
bbox |
A bounding box list from |
color |
RGBA colour for the edges (length 4, 0-1 scale). |
radius |
Cylinder radius for the edges. |
Value
A mesh descriptor list suitable for render_mesh()
or inclusion in a scene list.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 2, 3))
bbox_mesh <- generate_bbox(mesh)
nrow(bbox_mesh$vertices)
Generate a cone mesh
Description
Creates a cone from base to tip with the given base
radius, subdivided into segments around the axis.
The base cap is included.
Usage
generate_cone(base, tip, radius = 0.5, segments = 32, color = c(1, 1, 1, 1))
Arguments
base |
Length-3 vector: centre of the circular base. |
tip |
Length-3 vector: tip of the cone. |
radius |
Base radius. |
segments |
Subdivision count (default 32). |
color |
Length-4 RGBA colour. |
Value
A mesh descriptor list.
Examples
mesh <- generate_cone(c(0, -1, 0), c(0, 1, 0), radius = 0.8)
nrow(mesh$vertices)
Generate a cuboid mesh
Description
Creates an axis-aligned cuboid (box) centred at center
with the given half-extents along each axis.
Usage
generate_cuboid(center, half_extents, color = c(0.7, 0.7, 0.7, 1))
Arguments
center |
Length-3 vector: centre of the cuboid. |
half_extents |
Length-3 vector: half-width, half-height, half-depth. |
color |
Length-4 RGBA colour (0-1 scale). |
Value
A mesh descriptor list.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 2, 0.5))
nrow(mesh$vertices)
nrow(mesh$triangles)
Generate a cylinder mesh
Description
Creates a cylinder from start to end with the given
radius, subdivided into segments around the axis.
Both end caps are included unless caps = FALSE is passed.
Usage
generate_cylinder(
start,
end,
radius = 0.5,
segments = 32,
color = c(1, 1, 1, 1),
caps = TRUE
)
Arguments
start |
Length-3 vector: cylinder start point. |
end |
Length-3 vector: cylinder end point. |
radius |
Cylinder radius. |
segments |
Subdivision count (default 32). |
color |
Length-4 RGBA colour. |
caps |
Whether to close both ends with caps (default TRUE). Pass FALSE for an open tube, which roughly halves the number of vertices and triangles. Useful for edges whose ends are hidden by other geometry. |
Value
A mesh descriptor list.
Examples
mesh <- generate_cylinder(c(0, -1, 0), c(0, 1, 0), radius = 0.5)
nrow(mesh$vertices)
open <- generate_cylinder(c(0, -1, 0), c(0, 1, 0), radius = 0.5, caps = FALSE)
nrow(open$vertices)
Generate multiple cylinders as a single mesh
Description
Batched variant of generate_cylinder(): all cylinders are generated
into one mesh. This is the function to use for thousands of straight edges,
e.g. the edges of a network graph or a connectome. Pass caps = FALSE
to leave the ends open, which is usually what you want when the ends are
hidden inside spherical nodes (and roughly halves the geometry).
Usage
generate_multi_cylinders(
from,
to,
radii = 0.1,
colors = c(1, 1, 1, 1),
segments = 12L,
caps = TRUE
)
Arguments
from |
Nx3 numeric matrix of start points (or a length-3 vector). |
to |
Nx3 numeric matrix of end points (same number of rows as
|
radii |
Numeric vector of radii (length 1, recycled; or one per cylinder). |
colors |
RGBA colour(s): a single vector applied to all cylinders, or an
Nx4 numeric matrix (values in |
segments |
Subdivision count around the circumference (default 12). |
caps |
Whether to close both ends of every cylinder (default TRUE). |
Value
A mesh descriptor list with vertices, triangles and
colors.
See Also
generate_cylinder, generate_tubes
Examples
from <- matrix(c(0, 0, 0, 1, 0, 0), ncol = 3, byrow = TRUE)
to <- matrix(c(0, 3, 0, 1, 3, 0), ncol = 3, byrow = TRUE)
mesh <- generate_multi_cylinders(from, to, radii = 0.1,
colors = c(0.7, 0.7, 0.7, 1), caps = FALSE)
nrow(mesh$vertices) > 0
Generate multiple spheres as a single mesh
Description
Batched variant of generate_sphere(): all spheres are generated into
one mesh with a single vertex/triangle array, which is much faster than
generating and merging them one by one. This is the function to use for
thousands of nodes, e.g. the nodes of a network graph or a point cloud. The
returned mesh can be added to a scene and rendered with render_scene()
or render_mesh().
Usage
generate_multi_spheres(
centers,
radii = 1,
colors = c(1, 1, 1, 1),
segments = 16L
)
Arguments
centers |
Nx3 numeric matrix of sphere centres (or a length-3 vector for a single sphere). |
radii |
Numeric vector of radii (length 1, recycled; or one per sphere). |
colors |
RGBA colour(s): a single vector applied to all spheres, or an
Nx4 numeric matrix (values in |
segments |
Subdivision count per sphere (default 16). |
Value
A mesh descriptor list with vertices, triangles and
colors.
See Also
generate_sphere, generate_multi_cylinders
Examples
centers <- matrix(c(0, 0, 0, 2, 0, 0), ncol = 3, byrow = TRUE)
mesh <- generate_multi_spheres(centers, radii = c(0.5, 0.3),
colors = c(1, 0, 0, 1), segments = 12)
nrow(mesh$vertices) > 0
Generate a planar quad mesh
Description
Creates a flat rectangular plane centred at center and
oriented perpendicular to normal.
Usage
generate_plane(
center = c(0, 0, 0),
normal = c(0, 1, 0),
half_size_x = 1,
half_size_y = 1,
color = c(0.7, 0.7, 0.7, 1)
)
Arguments
center |
Length-3 vector: centre of the plane. |
normal |
Length-3 vector: surface normal. |
half_size_x |
Half-extent along the first tangent axis. |
half_size_y |
Half-extent along the second tangent axis. |
color |
Length-4 RGBA colour. |
Value
A mesh descriptor list.
Examples
mesh <- generate_plane(c(0, 0, 0), normal = c(0, 1, 0),
half_size_x = 2, half_size_y = 1)
nrow(mesh$vertices)
Generate a square pyramid mesh
Description
Creates a pyramid with a square base centred at base_center
in the XZ plane, with the apex above it along Y.
Usage
generate_pyramid(
base_center,
apex,
half_width = 1,
color = c(0.7, 0.7, 0.7, 1)
)
Arguments
base_center |
Length-3 vector: centre of the square base. |
apex |
Length-3 vector: position of the tip. |
half_width |
Half-width of the square base. |
color |
Length-4 RGBA colour. |
Value
A mesh descriptor list.
Examples
mesh <- generate_pyramid(c(0, 0, 0), c(0, 2, 0), half_width = 1)
mesh$vertices
Generate a sphere mesh
Description
Creates a UV sphere centred at center with the given
radius. The sphere is subdivided into segments
rings and segments per ring.
Usage
generate_sphere(center, radius = 1, segments = 32, color = c(1, 1, 1, 1))
Arguments
center |
Length-3 vector: sphere centre. |
radius |
Sphere radius. |
segments |
Subdivision count (default 32). |
color |
Length-4 RGBA colour. |
Value
A mesh descriptor list.
Examples
mesh <- generate_sphere(c(0, 0, 0), radius = 1.5, segments = 32)
nrow(mesh$vertices)
Generate a tetrahedron mesh
Description
Creates a tetrahedron (triangular pyramid) from four arbitrary 3D points.
Usage
generate_tetrahedron(p0, p1, p2, p3, color = c(0.7, 0.7, 0.7, 1))
Arguments
p0 |
Length-3 vector: first vertex. |
p1 |
Length-3 vector: second vertex. |
p2 |
Length-3 vector: third vertex. |
p3 |
Length-3 vector: fourth vertex. |
color |
Length-4 RGBA colour. |
Value
A mesh descriptor list.
Examples
mesh <- generate_tetrahedron(
c(0, 0, 0), c(1, 0, 0),
c(0.5, 1, 0), c(0.5, 0.5, 1))
nrow(mesh$vertices)
Generate a torus mesh
Description
Creates a torus (donut shape) centred at center, lying in
the XZ plane.
Usage
generate_torus(
center = c(0, 0, 0),
major_radius = 1,
minor_radius = 0.3,
major_segments = 32,
minor_segments = 16,
color = c(0.7, 0.7, 0.7, 1)
)
Arguments
center |
Length-3 vector: centre of the torus. |
major_radius |
Radius of the ring (tube path). |
minor_radius |
Radius of the tube cross-section. |
major_segments |
Number of segments around the ring. |
minor_segments |
Number of segments around the tube. |
color |
Length-4 RGBA colour. |
Value
A mesh descriptor list.
Examples
mesh <- generate_torus(major_radius = 2, minor_radius = 0.5)
nrow(mesh$vertices)
Generate a tube (generalized cylinder) along a path
Description
Sweeps a circular cross-section along the points of path, which allows
for curved shapes such as arcs, Bezier samples of network edges or
streamlines. A path of exactly two points produces the same mesh as
generate_cylinder().
Usage
generate_tube(
path,
radius = 0.1,
segments = 12L,
color = c(1, 1, 1, 1),
cap_start = TRUE,
cap_end = TRUE
)
Arguments
path |
Nx3 numeric matrix of path points (or a length-3 vector). |
radius |
Tube radius (default 0.1). |
segments |
Subdivision count around the circumference (default 12). |
color |
Length-4 RGBA colour. |
cap_start |
Whether to close the beginning of the tube (default TRUE). |
cap_end |
Whether to close the end of the tube (default TRUE). |
Details
The cross-section frames are computed by parallel transport (rotation-minimizing frames), so the tube does not twist around its own axis. Consecutive duplicate points are removed; a path with fewer than two distinct points yields an empty mesh.
Value
A mesh descriptor list.
See Also
generate_tubes, generate_cylinder
Examples
path <- matrix(c(0, 0, 0, 1, 1, 0, 2, 0, 0), ncol = 3, byrow = TRUE)
arc <- generate_tube(path, radius = 0.1, segments = 12,
cap_start = FALSE, cap_end = FALSE)
nrow(arc$vertices) > 0
Generate multiple tubes as a single mesh
Description
Batched variant of generate_tube(): all tubes are generated into one
mesh. Paths may differ in length. This is the function to use for curved
edges, e.g. connectome edges drawn as arcs.
Usage
generate_tubes(
paths,
radii = 0.1,
colors = c(1, 1, 1, 1),
segments = 12L,
caps = FALSE
)
Arguments
paths |
List of Nx3 numeric matrices (one per tube). Each path needs at least two distinct points to produce geometry. |
radii |
Numeric vector of radii (length 1, recycled; or one per tube). |
colors |
RGBA colour(s): a single vector applied to all tubes, or an Nx4
numeric matrix (values in |
segments |
Subdivision count around the circumference (default 12). |
caps |
Whether to close both ends of every tube (default FALSE, since batched tubes are typically connected at their ends). |
Value
A mesh descriptor list.
See Also
generate_tube, generate_multi_cylinders
Examples
paths <- list(matrix(c(0, 0, 0, 1, 1, 0), ncol = 3, byrow = TRUE),
matrix(c(0, 0, 2, 1, 1, 2, 2, 0, 2), ncol = 3, byrow = TRUE))
mesh <- generate_tubes(paths, radii = 0.05, segments = 8)
nrow(mesh$vertices) > 0
Apply contrast adjustment to an image
Description
Applies a contrast stretch (S-curve) to the RGB channels of a
rendered image. Formula: (value - 0.5) * contrast + 0.5,
clamped to [0, 1]. The default 1.0 means no change.
Values > 1.0 produce darker darks and lighter highlights.
Usage
image_apply_contrast(image, contrast = 1)
Arguments
image |
An image list returned by |
contrast |
Contrast multiplier. Default 1.0 (no change). Typical values: 1.1–1.2 for subtle S-curve, 1.5 for strong. |
Value
A new image list with contrast-adjusted pixel data.
Examples
cube <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
img <- render_mesh(cube$vertices, cube$triangles)
img <- image_apply_contrast(img, contrast = 1.1)
Crop an image to a rectangular region
Description
Crop an image to a rectangular region
Usage
image_crop(image, x, y, w, h)
Arguments
image |
An image list returned by |
x |
Left edge of the crop region (0-based pixel coordinate). |
y |
Top edge of the crop region (0-based pixel coordinate). |
w |
Crop width in pixels. |
h |
Crop height in pixels. |
Value
A new image list with the cropped dimensions.
Examples
cube <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
img <- render_mesh(cube$vertices, cube$triangles)
img <- image_crop(img, 100, 50, 400, 300)
Crop an image to its content bounding box
Description
Removes background-coloured margin from the specified edges of the image. The first non-background pixel found on each edge defines the crop boundary.
Usage
image_crop_to_content(image, direction, background)
Arguments
image |
An image list. |
direction |
One of |
background |
Numeric vector of length 4 with RGBA values in
|
Value
A new image list with cropped dimensions.
Examples
cube <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
img <- render_mesh(cube$vertices, cube$triangles,
options = render_options(background_color = c(0, 0, 0, 0)))
img <- image_crop_to_content(img, "all", c(0, 0, 0, 0))
Grow an image by adding padding
Description
Expands the canvas by adding pixel rows/columns filled with a background colour.
Usage
image_grow(image, top, bottom, left, right, background)
Arguments
image |
An image list. |
top |
Number of pixel rows to add above. |
bottom |
Number of pixel rows to add below. |
left |
Number of pixel columns to add to the left. |
right |
Number of pixel columns to add to the right. |
background |
Numeric vector of length 4 with RGBA values in
|
Value
A new image list with the expanded dimensions.
Examples
cube <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
img <- render_mesh(cube$vertices, cube$triangles)
img <- image_grow(img, 10, 10, 20, 20, c(1, 1, 1, 1))
Merge two images side by side or stacked
Description
Merges another image into this one at the specified edge. For left/right merging, the heights must match. For top/bottom, the widths must match.
Usage
image_merge(image, other, direction)
Arguments
image |
An image list. |
other |
Another image list. |
direction |
One of |
Value
A new image list with the merged dimensions.
Examples
cube <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
sphere <- generate_sphere(c(0, 0, 0), radius = 0.5)
left <- render_mesh(sphere$vertices, sphere$triangles)
right <- render_mesh(cube$vertices, cube$triangles)
merged <- image_merge(left, right, "right")
Rotate an image by 90 degrees
Description
Rotate an image by 90 degrees
Usage
image_rotate_90(image, clockwise = TRUE)
Arguments
image |
An image list. |
clockwise |
Logical, if |
Value
A new image list with width and height swapped.
Scale an image (nearest-neighbour)
Description
Resizes the image to the given dimensions using nearest-neighbour interpolation.
Usage
image_scale(image, new_width, new_height)
Arguments
image |
An image list. |
new_width |
Target width in pixels. |
new_height |
Target height in pixels. |
Value
A new image list with the new dimensions.
Convert a rendered image to an RGBA array
Description
Converts the output of render_mesh() or render_scene()
into a 3-dimensional R array of dimensions (height x width x 4) with
RGBA channels.
Usage
image_to_array(image)
Arguments
image |
An image list returned by |
Value
A 3D array of dimensions (height, width, 4) with values in
[0, 1].
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
img <- render_mesh(mesh$vertices, mesh$triangles)
arr <- image_to_array(img)
dim(arr) # height x width x 4
Create a line layer (screen-space lines, no geometry)
Description
Bundles a set of independent line segments with a width measured in pixels
into a layer that can be added to a scene (see the lines argument of
scene()), or drawn directly with render_segments.
In contrast to tube meshes (generate_tubes), no geometry is
created: the renderer draws the segments itself, so thousands of lines cost
almost nothing, and a width of 1 stays 1 pixel wide no matter how far away
the geometry is. This is what hardware line rendering (and
rgl::segments3d()) does.
Usage
line_layer(
from,
to,
colors = NULL,
width = 1,
depth_test = TRUE,
lit = FALSE,
affects_bounds = TRUE
)
Arguments
from |
Nx3 numeric matrix of segment start points (or a length-3 vector for a single segment). |
to |
Nx3 numeric matrix of segment end points (same number of rows as
|
colors |
RGBA colour(s): a single vector applied to all segments, or an
Nx4 numeric matrix (values in |
width |
Line width in pixels (default 1). |
depth_test |
Whether to test the lines against the depth buffer
(default |
lit |
Whether to apply lighting to the lines (default |
affects_bounds |
Whether this layer contributes to the bounding box of
the scene, and thus to the camera fitted to it (default |
Details
Line layers are drawn together with the meshes of the scene, after them and against the same depth buffer, so opaque meshes can hide lines and opaque lines can hide meshes. Segments whose colors have an alpha value below 1 are drawn in the blended pass, back to front, exactly like translucent triangles.
Lines usually *are* the content of a figure (graph or connectome edges,
streamlines, trajectories), so by default a layer contributes to the bounding
box of its scene, exactly like a mesh does: it defines the extent that the
camera has to cover. Set affects_bounds = FALSE for a layer that is
decoration rather than content (a leader line to a label, an axis cross, a
scale bar drawn as segments), so that it can never push the camera away from
the data. A scene that contains no mesh at all is framed by its line layers
even when they all opted out, since there would otherwise be no geometry to
derive a camera from.
Value
A line layer object (a list with class scimesh_lines) for use
in scene() or render_segments.
See Also
render_segments, generate_tubes
Examples
from <- matrix(c(-1, 0, 0, 0, -1, 0), ncol = 3, byrow = TRUE)
to <- matrix(c(1, 0, 0, 0, 1, 0), ncol = 3, byrow = TRUE)
layer <- line_layer(from, to, colors = c(0.2, 0.2, 0.2, 0.8), width = 2)
sc <- scene(list(generate_sphere(c(0, 0, 0), 0.5)), lines = layer)
Compute the axis-aligned bounding box of a mesh
Description
Compute the axis-aligned bounding box of a mesh
Usage
mesh_bbox(mesh)
Arguments
mesh |
A mesh descriptor list with |
Value
A list with min and max (each length-3 numeric).
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 2, 3))
bb <- mesh_bbox(mesh)
bb$min
bb$max
Convert an rgl tmesh3d to scimesh mesh format
Description
Extracts vertices and triangle indices from an rgl
tmesh3d object into the format expected by
render_mesh(). Does not require the rgl
package – any list with components vb (4xN
homogeneous coordinates) and it (3xM index matrix)
works.
Usage
mesh_from_rgl(tmesh)
Arguments
tmesh |
A list with components |
Value
A mesh descriptor list with vertices (Nx3)
and triangles (Mx3, 1-based indices).
Examples
fake <- list(vb = rbind(0:3, 0:3, 0:3, rep(1, 4)),
it = matrix(1:6, nrow = 3))
m <- mesh_from_rgl(fake)
m$vertices
m$triangles
Convert a scimesh mesh to rgl tmesh3d format
Description
Builds an rgl-compatible triangular mesh from a scimesh mesh
descriptor so that the result can be used with
rgl::shade3d() or other rgl functions.
Usage
mesh_to_rgl(mesh, color = NULL, face_color = NULL)
Arguments
mesh |
A scimesh mesh descriptor list with |
color |
Optional per-vertex colour, either a single length-4 RGBA vector (applied to all vertices) or an Nx4 matrix. |
face_color |
Optional per-face colour (Mx4 matrix). |
Value
A list with components vb (4xN homogeneous
coordinates), it (3xM 1-based index matrix), and
optionally normals and mat (material), suitable
for use with rgl's tmesh3d() and shade3d().
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
rgl_mesh <- mesh_to_rgl(mesh)
str(rgl_mesh)
Normalize the lines argument of scene()
Description
Accepts NULL, a single line layer, or a list of line layers and
returns a (possibly empty) list of line layers. Layers may also be wrapped
into a scene node (list(lines = <layer>, transform = ...)).
Usage
normalize_line_layers(lines)
Arguments
lines |
|
Value
A list of line layers (or line layer nodes).
Normalize the texts argument of scene()
Description
Accepts NULL, a single text layer, or a list of text layers and
returns a (possibly empty) list of text layers. Layers may also be wrapped
into a scene node (list(text = <layer>, transform = ...)), which
allows moving a group of world-space labels with one transform.
Usage
normalize_text_layers(texts)
Arguments
texts |
|
Value
A list of text layers (or text layer nodes).
Curvature along a path
Description
Estimates the curvature at every point from the neighbouring points, using
the standard formula \kappa = |x' \times x''| / |x'|^3, which does not
care how the points are spaced. On a circle of radius r the values
come out as 1/r, and on a straight line as 0.
Usage
path_curvature(path, closed = FALSE)
Arguments
path |
Nx3 numeric matrix of path points (or a length-3 vector). |
closed |
Whether the path loops back to its first point (default
|
Details
This is a diagnostic tool rather than a rendering input: sweeping a tube of
radius r along a curve whose curvature reaches \kappa folds the
tube inside out, so a path can be swept safely up to a radius of
1 / \max(\kappa), which is worth checking for tight turns in measured
data (max(path_curvature(path))).
Value
A numeric vector with one curvature value per input point. The endpoints of an open path report the value of their only neighbour; fewer than 3 points yield a zero-length vector, since curvature is undefined there.
See Also
Examples
# Largest tube radius that does not fold this path onto itself:
path <- spline_path(matrix(c(0, 0, 0, 1, 1, 0, 2, 0, 0, 3, 1, 0),
ncol = 3, byrow = TRUE))
1 / max(path_curvature(path))
Length of a path
Description
Sums the distances between consecutive points, plus the closing distance from
the last point back to the first for a closed path. Useful to pick a
sensible step for resample_path, or to derive a sampling
density from the size of the data.
Usage
path_length(path, closed = FALSE)
Arguments
path |
Nx3 numeric matrix of path points (or a length-3 vector). |
closed |
Whether the path loops back to its first point (default
|
Value
A single number: the arc length of the path (0 for fewer than two points).
See Also
Examples
path_length(matrix(c(0, 0, 0, 1, 0, 0, 1, 1, 0), ncol = 3, byrow = TRUE))
Read a Wavefront OBJ file
Description
Reads the geometry (vertices and triangles) of a Wavefront OBJ file and
returns a scimesh mesh descriptor list with vertices and
triangles. Normals and texture coordinates in the file are ignored:
call compute_vertex_normals() if you need normals, and assign
uv yourself (see render_mesh) if you want to render the
mesh with a texture.
Usage
read_obj(path)
Arguments
path |
Path to the OBJ file. |
Value
A mesh descriptor list with vertices and triangles.
Examples
## Not run:
mesh <- read_obj("model.obj")
nrow(mesh$vertices)
## End(Not run)
Read a Stanford PLY file
Description
Reads a PLY file (ASCII or binary) with optional per-vertex colors
and returns a scimesh mesh descriptor list with vertices,
triangles, and optionally colors. Texture coordinates in the
file are ignored.
Usage
read_ply(path)
Arguments
path |
Path to the PLY file. |
Value
A mesh descriptor list.
Examples
## Not run:
mesh <- read_ply("model.ply")
nrow(mesh$vertices)
## End(Not run)
Read an STL file
Description
Reads an ASCII or binary STL file and returns a scimesh mesh
descriptor list with vertices, triangles, and
normals.
Usage
read_stl(path)
Arguments
path |
Path to the STL file. |
Value
A mesh descriptor list.
Examples
## Not run:
mesh <- read_stl("model.stl")
nrow(mesh$vertices)
## End(Not run)
Recycle per-primitive colors to an Nx4 matrix
Description
Accepts a single RGB/RGBA vector (applied to all primitives), a single-row matrix (recycled), or an Nx4 (or Nx3, alpha is set to 1) matrix. An empty input means "no colors given", which the C++ generators interpret as white.
Usage
recycle_colors(colors, n, arg_name = "colors")
Arguments
colors |
Numeric vector or matrix of RGB/RGBA colors, or NULL. |
n |
Number of primitives. |
arg_name |
Name of the argument, used in error messages. |
Value
An Nx4 numeric matrix, or a 0x4 matrix.
Recycle a per-primitive radius vector to the requested length
Description
A single value is applied to all primitives, a vector of the exact length is used as-is, and an empty (or NULL) input means "no radii given", which the C++ generators interpret as radius 1.0.
Usage
recycle_radii(radii, n, arg_name = "radii")
Arguments
radii |
Numeric vector of radii, or NULL. |
n |
Number of primitives. |
arg_name |
Name of the argument, used in error messages. |
Value
Numeric vector of length 'n', or a zero-length vector.
Render line segments as thin cylinders
Description
Generates a merged cylinder mesh from start/end point pairs, radii, and colors, then renders it.
Usage
render_lines(
from,
to,
radii = 0.1,
colors,
camera,
options = render_options(),
segments = 12L
)
Arguments
from |
Nx3 numeric matrix of segment start points. |
to |
Nx3 numeric matrix of segment end points. |
radii |
Numeric vector of cylinder radii (length N, or 1 recycled to N). |
colors |
Nx4 numeric matrix of RGBA colours, or a single colour recycled to N. |
camera |
A camera list. |
options |
Render options. |
segments |
Number of sides around the cylinder (default 12). |
Value
An image list.
Examples
from <- matrix(c(0, 0, 0, 1, 1, 1), ncol = 3, byrow = TRUE)
to <- matrix(c(3, 0, 0, 0, 3, 0), ncol = 3, byrow = TRUE)
img <- render_lines(from, to, radii = 0.05,
colors = c(0, 0, 1, 1),
camera = camera_auto(rbind(from, to)))
tmp_file <- tempfile(fileext = ".png")
write_png(img, tmp_file)
Render a 3D mesh to an image
Description
Renders a single mesh using the scimesh software renderer.
The mesh can be specified either as separate
vertices/triangles matrices, as a scimesh mesh
descriptor list, or as an rgl tmesh3d-style list (with
vb/it components). rgl meshes are transparently
converted via mesh_from_rgl().
Usage
render_mesh(
vertices,
triangles = NULL,
colors = NULL,
face_colors = NULL,
normals = NULL,
uv = NULL,
texture = NULL,
camera = NULL,
options = render_options()
)
Arguments
vertices |
Either an Nx3 numeric matrix of vertex positions,
or a scimesh mesh descriptor list (with |
triangles |
Mx3 integer matrix of triangle indices (1-based).
Ignored when |
colors |
Optional Nx4 numeric matrix of RGBA vertex colors (0-1).
The fourth column is the alpha value; alpha < 1 renders the mesh
translucently (see the Transparency section below).
Use |
face_colors |
Optional Mx4 numeric matrix of per-face RGBA colors,
one row per triangle. When present, all three vertices of a triangle
use the same colour. Takes precedence over vertex |
normals |
Optional Nx3 numeric matrix of vertex normals. |
uv |
Optional Nx2 numeric matrix of texture coordinates (0-1). scimesh
uses image-space UVs: |
texture |
Optional texture image as a 3D array (H x W x 3 or 4)
with values in |
camera |
A camera list from |
options |
A render options list from |
Value
A list with components width, height, and
pixels (raw vector of RGBA values).
Transparency
The fourth column of colors (and of face_colors) is the
alpha value: values < 1 make the mesh translucent, and the renderer
blends it with whatever is behind it automatically - there is no flag to
set. Per-vertex alpha is interpolated across each triangle, so a smooth
fade is possible, and alpha = 0 makes geometry invisible (holes).
Translucent triangles are drawn back-to-front after the opaque geometry,
so they are correctly hidden by opaque meshes in front of them. Use
set_mesh_alpha() to set one alpha value for a whole mesh.
Examples
# Render a simple colored triangle
verts <- matrix(c(0, 0, 0, 1, 0, 0, 0.5, 1, 0), ncol = 3, byrow = TRUE)
tris <- matrix(1L, nrow = 1, ncol = 3)
cols <- matrix(c(1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1), ncol = 4, byrow = TRUE)
img <- render_mesh(verts, tris, colors = cols)
tmp_file <- tempfile(fileext = ".png")
write_png(img, tmp_file)
# Render from a mesh descriptor list (scimesh format)
mesh_desc <- list(vertices = verts, triangles = tris, colors = cols)
img <- render_mesh(mesh_desc)
Create render options
Description
Create render options
Usage
render_options(
width = 800L,
height = 600L,
shading = c("smooth", "flat"),
backface_culling = TRUE,
background_color = c(1, 1, 1, 1),
default_color = c(0.7, 0.7, 0.7, 1),
invert_normals = FALSE,
wireframe = FALSE,
wireframe_color = c(0, 0, 0, 1),
projection = c("perspective", "orthographic"),
specular_color = c(0, 0, 0, 0),
shininess = 0,
lights = NULL,
ambient = 0.3,
contrast = 1,
fog_enabled = FALSE,
fog_start = 0,
fog_end = 1,
fog_color = c(0, 0, 0, 0),
fog_space = c("world", "ndc"),
threads = 0L,
clip_planes = NULL,
ssao_enabled = FALSE,
ssao_radius = 16,
ssao_intensity = 0.8,
aa_samples = NULL,
near_plane = 0.1,
far_plane = 10000
)
Arguments
width |
Output image width in pixels. |
height |
Output image height in pixels. |
shading |
Shading mode: |
backface_culling |
Whether to cull back-facing triangles. |
background_color |
Background RGBA color as numeric vector of length 4 (values 0-1). |
default_color |
Default vertex color when no colors are provided. |
invert_normals |
Whether to invert surface normals. |
wireframe |
Whether to render in wireframe mode. |
wireframe_color |
RGBA color for wireframe edges (0-1
scale). Default |
projection |
Projection type: |
specular_color |
Specular highlight color (0-1 scale). When
|
shininess |
Specular exponent controlling highlight sharpness.
Higher values produce a tighter spot. Typical values: 32 (soft
plastic), 64 (shiny), 128 (glass). Default |
lights |
A list of light descriptors, each a list with
|
ambient |
Ambient light contribution (0-1). Default 0.3. |
contrast |
Contrast adjustment applied after shading, before
uint8_t conversion. Default 1.0 (no change). Values > 1.0 produce
darker darks and lighter highlights (S-curve). Formula:
|
fog_enabled |
Enable depth cueing (fog). Default |
fog_start |
Distance where fog begins, i.e. where objects start
fading toward |
fog_end |
Distance where fog is fully opaque. Must be larger
than |
fog_color |
RGBA fog colour (0-1 scale). Defaults to
|
fog_space |
Character, either
|
threads |
Number of render threads. 0 = auto-detect (use all cores), 1 = single-threaded (deterministic). Default 0. Requires OpenMP at compile time. |
clip_planes |
A list of clip planes (see |
ssao_enabled |
Enable screen-space ambient occlusion.
Default |
ssao_radius |
Screen-space sample radius in pixels. Default 16. |
ssao_intensity |
Occlusion strength (0-1). Default 0.8. |
aa_samples |
Anti-aliasing supersampling factor. Renders
internally at |
near_plane |
Distance of the near clipping plane (default 0.1).
Geometry closer to the camera is clipped away. Also defines the
depth range together with |
far_plane |
Distance of the far clipping plane (default 10000).
Must be larger than |
Value
A render options list for use with render_mesh() or
render_scene().
Examples
# Default options
opts <- render_options()
# High-resolution with anti-aliasing and specular highlights
opts <- render_options(width = 1200, height = 900,
aa_samples = 2L,
specular_color = c(0.4, 0.4, 0.4, 1),
shininess = 64)
# Wireframe with transparent background
opts <- render_options(wireframe = TRUE,
wireframe_color = c(0, 0, 0, 1),
background_color = c(0, 0, 0, 0))
# World-space clip plane: keep the half of the scene with x <= 0.
# The cut stays at x = 0, whatever the camera does.
opts <- render_options(clip_planes = list(
clip_plane(normal = c(-1, 0, 0), offset = 0)))
# Eye-space clip plane: additionally remove everything closer than 2 units
# to the camera (camera-attached cutaway).
opts <- render_options(clip_planes = list(
clip_plane(normal = c(-1, 0, 0), offset = 0),
clip_plane(normal = c(0, 0, -1), offset = -2, space = "eye")))
# Fog in world units (default): fade from 20 to 60 units away from the
# camera
opts <- render_options(fog_enabled = TRUE, fog_start = 20, fog_end = 60,
fog_color = c(0.9, 0.95, 1, 1))
# Legacy normalized-device-depth fog, for backwards compatibility
opts <- render_options(fog_enabled = TRUE, fog_space = "ndc",
fog_start = 0.5, fog_end = 1)
# Enable 2x2 anti-aliasing for this session: affects all subsequent
# render calls that do not pass \code{aa_samples} explicitly.
old <- options(scimesh.aa_samples = 2L)
opts <- render_options()
opts$aa_samples
options(old)
Render screen-space point primitives
Description
Renders points as fixed-size filled circles in screen space with
depth testing. Unlike render_spheres(), point size is
measured in pixels and does not change with camera distance.
Usage
render_points(
positions,
colors,
radius = 3,
camera = camera_auto(positions),
options = render_options()
)
Arguments
positions |
Nx3 numeric matrix of point positions. |
colors |
Nx4 numeric matrix of RGBA colours (0-1 scale). |
radius |
Point radius in pixels. |
camera |
A camera list. |
options |
Render options. |
Value
An image list.
Examples
pts <- matrix(c(0, 1, 2, 0, 1, 2, 0, 0, 0),
ncol = 3)
colors = matrix(c(0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1), ncol = 4)
img <- render_points(pts, colors = colors, radius = 5)
tmp_file <- tempfile(fileext = ".png")
write_png(img, tmp_file)
Render multiple meshes to an image
Description
Renders a list of meshes as a single scene using the scimesh
software renderer. Each element can be a scimesh mesh descriptor
or an rgl-style mesh (with vb/it); rgl meshes are
transparently converted.
Usage
render_scene(meshes, camera = NULL, options = NULL)
Arguments
meshes |
Either a |
camera |
A camera list from |
options |
A render options list from |
Value
A list with components width, height, and
pixels (raw vector of RGBA values).
Examples
# Render two cubes side by side
cube1 <- generate_cuboid(c(-1.5, 0, 0), c(0.8, 0.8, 0.8), c(1, 0, 0, 1))
cube2 <- generate_cuboid(c( 1.5, 0, 0), c(0.8, 0.8, 0.8), c(0, 0, 1, 1))
cam <- camera_auto(list(cube1, cube2), direction = c(1, 1, 1))
img <- render_scene(list(cube1, cube2), cam,
render_options(width = 800, height = 600, background_color = c(1, 1, 1, 1)))
tmp_file <- tempfile(fileext = ".png")
write_png(img, tmp_file)
# Render multiple meshes together
scimesh_cube <- generate_cuboid(c(-1, 0, 0), c(0.5, 0.5, 0.5))
sphere <- generate_sphere(c(1, 0, 0), radius = 0.5, color = c(0, 1, 0, 1))
cam <- camera_auto(list(scimesh_cube, sphere), direction = c(1, 1, 1))
img <- render_scene(list(scimesh_cube, sphere), cam,
render_options(width = 400, height = 300, background_color = c(1, 1, 1, 1)))
Render line segments directly to an image
Description
Convenience wrapper around line_layer for the case where no
meshes are involved: the segments are drawn (with a screen-space width) into
an image and nothing else. To combine lines with meshes, add the layer to a
scene instead and render that scene.
Usage
render_segments(
from,
to,
colors = NULL,
width = 1,
camera = NULL,
options = render_options(),
lit = FALSE
)
Arguments
from |
Nx3 numeric matrix of segment start points (or a length-3 vector). |
to |
Nx3 numeric matrix of segment end points (same number of rows as
|
colors |
RGBA colour(s): a single vector applied to all segments, or an
Nx4 numeric matrix. |
width |
Line width in pixels (default 1). |
camera |
A camera list, e.g. from |
options |
Render options, see |
lit |
Whether to apply lighting (default |
Value
An image list, see render_scene.
See Also
Examples
from <- matrix(c(-1, 0, 0, 0, -1, 0), ncol = 3, byrow = TRUE)
to <- matrix(c(1, 0, 0, 0, 1, 0), ncol = 3, byrow = TRUE)
img <- render_segments(from, to, colors = c(1, 0, 0, 1), width = 3)
tmp_file <- tempfile(fileext = ".png")
write_png(img, tmp_file)
Render multiple spheres from point data
Description
Generates a merged sphere mesh from a set of center points, radii, and colors, then renders it with the given camera and options.
Usage
render_spheres(
centers,
radii,
colors,
camera,
options = render_options(),
segments = 16L
)
Arguments
centers |
Nx3 numeric matrix of sphere centre coordinates. |
radii |
Numeric vector of sphere radii (length N, or 1 recycled to N). |
colors |
Nx4 numeric matrix of RGBA colours (0-1 scale), or a single colour recycled to N. |
camera |
A camera list from |
options |
Render options from |
segments |
Number of latitude/longitude segments per sphere (default 16). |
Value
An image list with width, height,
pixels.
Examples
centers <- matrix(c(0, 2, 4, 0, 0, 0, 0, 0, 0), ncol = 3)
img <- render_spheres(centers, radii = 0.5,
colors = c(1, 0, 0, 1),
camera = camera_auto(centers))
tmp_file <- tempfile(fileext = ".png")
write_png(img, tmp_file)
Render text labels to an image
Description
Convenience wrapper around text_layer for the case where no
meshes are involved: the labels are drawn onto the background described by
the render options. Screen-space labels (space = "screen") do not use
a camera at all, so this is the quick way to turn a label into an image or to
decorate an empty canvas; world-space labels need a camera.
Usage
render_text(positions, text, camera = NULL, options = NULL, ...)
Arguments
positions |
Anchor positions, see |
text |
Character vector of labels, see |
camera |
A camera list from |
options |
Render options from |
... |
Further arguments passed to |
Value
A list with components width, height, and
pixels (raw vector of RGBA values).
See Also
Examples
img <- render_text(c(20, 20), "figure A", space = "screen",
adj = c(0, 1), size = 24,
options = render_options(width = 300, height = 80))
tmp <- tempfile(fileext = ".png")
write_png(img, tmp)
Render raw triangles without index buffer
Description
Renders triangle geometry where positions and colours are given as flat arrays with 3 vertices per triangle (no index buffer). Useful for voxel renderings, misc3d isosurfaces, and other dynamically generated geometry.
Usage
render_triangles(positions, colors, camera, options = render_options())
Arguments
positions |
Nx3 numeric matrix of vertex positions, where N is a multiple of 3 (3 per triangle). |
colors |
Nx4 numeric matrix of RGBA colours (0-1 scale). |
camera |
A camera list from |
options |
Render options from |
Value
An image list with width, height,
pixels.
Examples
# Render a single red triangle from raw vertices
positions <- matrix(c(0, 0, 0, 1, 0, 0, 0.5, 1, 0), ncol = 3, byrow = TRUE)
colors <- matrix(c(1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1), ncol = 4, byrow = TRUE)
cam <- camera_auto(positions)
img <- render_triangles(positions, colors, cam)
Resample a path at a fixed arc length step
Description
Walks along a path and emits a point every step units of arc length.
The result has (nearly) uniform point spacing regardless of how the input was
parameterized, which is what makes a swept tube look even:
generate_tube places exactly one cross-section per path point,
so uneven spacing means a tube that is finely subdivided in one place and
faceted in another. Typical use is to even out the output of
spline_path, whose samples are evenly spaced in the curve
parameter rather than along the curve.
Usage
resample_path(path, step, closed = FALSE)
Arguments
path |
Nx3 numeric matrix of path points (or a length-3 vector). |
step |
Arc length between samples. Must be a single positive number; other values return the path unchanged. |
closed |
Whether the path loops back to its first point (default
|
Details
The spacing that is uniform is the *arc length* along the path; the straight-line distances between consecutive samples are slightly shorter wherever the path curves. An open path always keeps its final point (with a possibly shorter last step); a closed path ends on a copy of its first point and is covered in a whole number of steps, so its effective step can differ from the requested one by a fraction of a percent.
Value
An Nx3 numeric matrix of resampled path points. A path without length (or with fewer than two points) is returned as it is.
See Also
Examples
waypoints <- matrix(c(0, 0, 0, 1, 1, 0, 2, 0, 0), ncol = 3, byrow = TRUE)
smooth <- spline_path(waypoints, samples_per_segment = 32)
even <- resample_path(smooth, step = 0.1)
nrow(even)
Rotate a mesh around an axis
Description
Vertex normals (if the mesh has any) are rotated with the mesh.
Usage
rotate_mesh(mesh, angle_rad, axis = c(0, 0, 1))
Arguments
mesh |
A mesh descriptor list. |
angle_rad |
Rotation angle in radians. |
axis |
Length-3 numeric vector defining the rotation axis. |
Value
A new mesh descriptor list with rotated vertices.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
rotated <- rotate_mesh(mesh, pi / 4, axis = c(0, 1, 0))
rotated$vertices[1, ]
Scale a mesh uniformly or per-axis
Description
Per-vertex normals (if the mesh has any) are scaled as well, using the inverse transpose of the scaling matrix: a non-uniform scale would otherwise leave normals pointing in a direction that no longer matches the surface, which shows up as wrong shading.
Usage
scale_mesh(mesh, scale)
Arguments
mesh |
A mesh descriptor list. |
scale |
A single numeric scale factor (uniform) or a length-3 numeric vector for per-axis scaling (x, y, z). |
Value
A new mesh descriptor list with scaled vertices.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
big <- scale_mesh(mesh, 3)
flat <- scale_mesh(mesh, c(2, 0.5, 1))
Create a scene descriptor
Description
Bundles a list of meshes together with their placement transforms, a
camera, and render options into a single scene object that can be passed
to render_scene() or write_gltf().
Usage
scene(
meshes,
camera = NULL,
options = NULL,
transforms = NULL,
names = NULL,
lines = NULL,
texts = NULL
)
Arguments
meshes |
A list of mesh descriptors (scimesh or rgl format, see
|
camera |
A camera list from |
options |
A render options list from |
transforms |
Optional list of 4x4 numeric matrices, one per mesh,
overriding any embedded |
names |
Optional character vector, one per mesh, overriding any
embedded |
lines |
|
texts |
|
Details
Each mesh is wrapped into a scene node list(mesh = ..., transform = ...,
name = ...). The optional transform is a 4x4 numeric matrix
(column-major, GLM style — the same convention accepted by
transform_mesh()) that places the mesh in world space at
render/export time without modifying the mesh itself. The optional
name is used by exporters such as glTF for node names.
Value
A scene descriptor list with S3 class "scimesh_scene",
with components meshes (list of scene nodes), lines (list
of line layers, possibly empty), texts (list of text layers,
possibly empty), camera, and options.
See Also
Examples
cube1 <- generate_cuboid(c(0, 0, 0), c(0.5, 0.5, 0.5), c(1, 0, 0, 1))
cube2 <- generate_cuboid(c(0, 0, 0), c(0.5, 0.5, 0.5), c(0, 0, 1, 1))
# place the second cube 2 units along +X
tr <- diag(1, 4); tr[1, 4] <- 2
sc <- scene(list(cube1, list(mesh = cube2, transform = tr, name = "blue")),
camera = camera_auto(list(cube1, cube2), direction = c(1, 1, 1)))
img <- render_scene(sc)
# add a line layer drawn on top of the meshes:
sc2 <- scene(list(cube1),
lines = line_layer(matrix(c(0, 0, 1), ncol = 3),
matrix(c(1, 1, 1), ncol = 3), width = 3))
# add a label anchored above the cube:
sc3 <- scene(list(cube1),
texts = text_layer(matrix(c(0, 1, 0), ncol = 3), "cube",
size = 18, adj = c(0.5, 0)))
Change whether line layers of a scene contribute to its bounds
Description
Sets the affects_bounds flag of one or more line layers of a scene, see
line_layer. A layer with the flag set contributes to the
bounding box of the scene, and thus to the extent that a camera fitted to the
scene (camera_auto) has to cover; a layer without it is ignored
when the bounds are computed, which is what you want for decorational lines.
Usage
scene_set_line_affects_bounds(
scene,
index = NULL,
name = NULL,
affects_bounds = TRUE
)
Arguments
scene |
A scene descriptor list, see |
index |
Integer vector, the positions (1-based) of the layers to update,
or |
name |
Character vector, the names of the layers to update, or
|
affects_bounds |
Whether the selected layers contribute to the scene
bounds (default |
Details
The layers can be selected by position (index) or by name
(name, for layers that were added as scene nodes with a
name). Exactly one of the two has to be given. A scene that contains
no mesh at all is framed by its line layers even when they all opted out,
since there would otherwise be no geometry to derive a camera from.
Value
The scene with the updated layers, invisibly. Since a scene is a
plain list, the update has to be assigned to take effect, e.g.
sc <- scene_set_line_affects_bounds(sc, name = "leader",
affects_bounds = FALSE).
See Also
Examples
from <- matrix(c(-1, 0, 0, 5, 0, 0), ncol = 3, byrow = TRUE)
to <- matrix(c(1, 0, 0, 6, 0, 0), ncol = 3, byrow = TRUE)
# The second segment is a decorational leader line pointing away from the data.
sc <- scene(list(generate_cuboid(c(0, 0, 0), c(0.5, 0.5, 0.5))),
lines = list(list(lines = line_layer(from, to), name = "edges")))
sc <- scene_set_line_affects_bounds(sc, index = 1, affects_bounds = TRUE)
Set the transparency of a whole mesh
Description
Returns a copy of the mesh in which every vertex (and every face, if per-face colors are used) has the given alpha value. The renderer blends meshes whose colors are not fully opaque automatically, so this is all that is needed to draw a mesh translucently - for example a brain surface at 10 percent opacity for spatial reference.
Usage
set_mesh_alpha(mesh, alpha)
Arguments
mesh |
A mesh descriptor list (see |
alpha |
Alpha value in |
Details
A mesh without colors gets uniform colors first (its default_color
if it has one, light gray otherwise), so the mesh keeps its appearance and
only becomes see-through. Use alpha = 0 for completely invisible
geometry and alpha = 1 to make a mesh opaque again.
Value
A mesh descriptor list with the alpha applied.
See Also
Examples
sphere <- generate_sphere(c(0, 0, 0), 1)
ghost <- set_mesh_alpha(sphere, 0.2)
# Per-vertex alpha (here: every other vertex transparent) can be set
# directly on the color matrix:
cols <- sphere$colors
cols[, 4] <- rep(c(0, 1), length.out = nrow(cols))
sphere$colors <- cols
Smooth curve through ordered 3D points
Description
Turns a coarse list of waypoints into a dense, smooth path, which is what the
path-taking geometry functions expect: generate_tube sweeps a
cross-section along a path, and line_layer draws one straight
segment per consecutive pair of points. Handing a handful of control points
to those gives a visibly faceted tube and a polygonal line; this is how you
get the smooth version.
Usage
spline_path(
points,
method = c("catmull-rom", "bspline"),
samples_per_segment = 8L,
closed = FALSE,
alpha = 0.5
)
Arguments
points |
Nx3 numeric matrix of points the curve has to pass through (or
a length-3 vector for a single point). An open curve needs at least 2
points, a closed one at least 3 ( |
method |
Either |
samples_per_segment |
Number of points to generate per segment between two input points (default 8, clamped to at least 1). This is the knob that controls how smooth the result looks when rendered. |
closed |
Whether the curve loops back to its first point (default
|
alpha |
Parameterization exponent of the Catmull-Rom curve (default
|
Details
Two curves are available, and they differ in a way that matters:
-
"catmull-rom"(the default) **interpolates**: the curve passes through every input point, and each point's tangent is derived from its two neighbours. This is what you want when the input points are positions that the curve has to hit (measured or digitized data). -
"bspline"**approximates**: the points act as a control cage that the curve stays inside, which irons out noise instead of reproducing it, and the curve isC^2continuous everywhere. It generally does not pass through the input points.
For the Catmull-Rom curve, alpha selects the parameterization and is
the knob that matters most on real data:
-
0.5(default) — *centripetal*. Knot intervals grow with the square root of the chord length, which prevents the cusps, loops and self-intersections that the uniform curve produces when the spacing of the input points is uneven (long segment followed by a short one, the norm for measured data). -
1— chord length: still free of cusps, but can overshoot more. -
0— uniform: the textbook curve, exact on evenly spaced points and misbehaving on everything else.
Value
An Nx3 numeric matrix of path points, ready for
generate_tube, generate_tubes,
line_layer or camera_auto. An empty (0-row)
matrix if there are not enough distinct points for the chosen curve.
See Also
bezier_path, resample_path,
path_curvature, generate_tube
Examples
waypoints <- matrix(c(0, 0, 0, 1, 1, 0, 2, 0, 0, 3, 1, 0),
ncol = 3, byrow = TRUE)
path <- spline_path(waypoints, samples_per_segment = 8)
nrow(path) # 3 segments * 8 samples + the final point
# A smooth tube through the waypoints, instead of a faceted one:
mesh <- generate_tube(waypoints, radius = 0.1)
smooth <- generate_tube(path, radius = 0.1)
# An approximating (noise-reducing) closed loop:
loop <- spline_path(waypoints, method = "bspline", closed = TRUE)
Stack images horizontally
Description
Stacks a list of rendered images side by side. A convenience
wrapper around compose_layout().
Usage
stack_horizontal(
...,
colorbar = NULL,
colorbar_height = 80L,
colorbar_width = 80L,
background = c(0, 0, 0, 0),
colorbar_side = c("right", "left"),
crop = FALSE
)
Arguments
... |
Images from |
colorbar |
Optional colorbar. |
colorbar_height |
Height of the colorbar in pixels. |
colorbar_width |
Width of the colorbar in pixels. |
background |
Background RGBA color for padding. |
colorbar_side |
Side for the colorbar: |
crop |
If |
Value
A composed image list.
Examples
mesh1 <- generate_cuboid(c(-2, 0, 0), c(0.5, 1, 1), c(1, 0, 0, 1))
mesh2 <- generate_cuboid(c( 2, 0, 0), c(0.5, 1, 1), c(0, 0, 1, 1))
img1 <- render_mesh(mesh1$vertices, mesh1$triangles)
img2 <- render_mesh(mesh2$vertices, mesh2$triangles)
result <- stack_horizontal(img1, img2)
tmp_file <- tempfile(fileext = ".png")
write_png(result, tmp_file)
Stack images vertically
Description
Stacks a list of rendered images vertically (one below another).
A convenience wrapper around compose_layout().
Usage
stack_vertical(
...,
colorbar = NULL,
colorbar_height = 80L,
colorbar_width = 80L,
background = c(0, 0, 0, 0),
colorbar_side = c("right", "left"),
crop = FALSE
)
Arguments
... |
Images from |
colorbar |
Optional colorbar from |
colorbar_height |
Height of the colorbar in pixels. |
colorbar_width |
Width of the colorbar in pixels. |
background |
Background RGBA color for padding. |
colorbar_side |
Side for the colorbar: |
crop |
If |
Value
A composed image list.
Examples
mesh1 <- generate_cuboid(c(0, 2, 0), c(1, 0.5, 1), c(1, 0, 0, 1))
mesh2 <- generate_cuboid(c(0, -2, 0), c(1, 0.5, 1), c(0, 1, 0, 1))
img1 <- render_mesh(mesh1$vertices, mesh1$triangles)
img2 <- render_mesh(mesh2$vertices, mesh2$triangles)
result <- stack_vertical(img1, img2)
tmp_file <- tempfile(fileext = ".png")
write_png(result, tmp_file)
Measure text
Description
Computes the size of the text box that text_layer uses, which
is needed to place labels relative to each other (for example to right-align
a caption, or to keep two labels from overlapping). Multi-line labels are
measured as a whole, using the same line spacing as the renderer.
Usage
text_extent(text, size = 18, font_file = NULL, line_spacing = 1.2)
Arguments
text |
Character vector of labels (UTF-8; |
size |
Text height in output pixels (default 18). |
font_file |
Path to a |
line_spacing |
Distance between lines, as a multiple of the glyph box height (default 1.2). |
Value
A data frame with one row per input string and the columns
text, width (widest line), height (whole block),
ascent, descent and lines.
See Also
Examples
text_extent("anterior", size = 20)
text_extent(c("left hemisphere", "right hemisphere"), size = 16)
Create a text label layer (2D annotations for a scene)
Description
Bundles strings with anchor positions into a layer that can be added to a
scene (see the texts argument of scene()), or drawn
directly with render_text.
Usage
text_layer(
positions,
text,
colors = NULL,
size = 18,
font_file = NULL,
space = c("world", "screen"),
adj = c(0.5, 0.5),
offset = c(0, 0),
line_spacing = 1.2,
depth_test = TRUE,
halo_color = NULL,
halo_width = 1.5,
rotation = 0
)
Arguments
positions |
Anchor positions: an Nx3 numeric matrix for world space, or
an Nx2/Nx3 numeric matrix for |
text |
Character vector of labels (UTF-8), recycled to
|
colors |
RGBA colour(s): a single vector applied to all labels, or an
Nx4 numeric matrix (values in |
size |
Text height in output pixels (default 18). Independent of the
anti-aliasing setting: a label keeps its physical size when
|
font_file |
Path to a |
space |
|
adj |
Numeric vector of length 2 giving where the position sits on the
text box, in |
offset |
Numeric vector of length 2: extra offset in output pixels (positive x = right, positive y = down), applied after anchoring. Handy to push an atom label next to the atom instead of onto it. |
line_spacing |
Distance between two lines of a multi-line label, as a multiple of the font's glyph box height (default 1.2). |
depth_test |
Whether a label is hidden by geometry in front of its
anchor (default |
halo_color |
RGBA colour of the halo (outline) drawn behind the glyphs,
which keeps labels readable on dark or busy geometry. |
halo_width |
Halo thickness in pixels (default 1.5). |
rotation |
Rotation of the label in degrees, counter-clockwise, about the anchor position (default 0). Use 90 to write along a vertical axis (the usual orientation of a y-axis label), 180 for an upside-down label, or any other angle to follow an annotation line. The anchor stays fixed while the text turns around it. |
Details
Labels are billboards: they always face the camera and keep the size
given in size (in output pixels), so they stay readable from any
viewpoint — unlike text that is turned into 3D geometry, which skews as the
camera moves. This is the screen-friendly counterpart of
rgl::text3d(), and the intended way to label brain regions, atoms,
panels or figure axes.
Positions are given either in world space (the default) or in
screen space: with space = "screen" the coordinates are
pixels of the output image, measured from the top left corner, which is what
you want for titles, panel tags and captions. World-space labels are
projected with the camera of the scene, so they stick to the annotated
location, and they are hidden by geometry in front of them unless
depth_test = FALSE.
Value
A text layer object (a list with class scimesh_text) for use
in scene() or render_text.
See Also
render_text, text_extent,
scene, line_layer
Examples
sph <- generate_sphere(c(0, 0, 0), radius = 1)
# world-space label above the sphere
labels <- text_layer(matrix(c(0, 1.4, 0), ncol = 3), "top", size = 20)
labels
# screen-space panel tag, positioned by its top left corner
tag <- text_layer(c(10, 12), "A", space = "screen", adj = c(0, 1), size = 28,
halo_color = c(1, 1, 1, 0.9))
tag
# multiple labels with per-label colors and positions
multi <- text_layer(matrix(c(-1, 0, 0, 1, 0, 0), ncol = 3, byrow = TRUE),
c("left", "right"), colors = matrix(c(1, 0, 0, 1,
0, 0, 1, 1),
ncol = 4, byrow = TRUE))
multi
Apply a 4x4 transformation matrix to a mesh
Description
Transforms all vertex positions in a mesh by a 4x4 homogeneous
matrix (applied as M * (x, y, z, 1)^T). Vertex colors are
kept as they are; vertex normals (if the mesh has any) are
transformed by the inverse transpose of M, so that shading
stays correct for shearing and non-uniform scaling. Use
compute_vertex_normals() if the mesh has no normals yet.
Usage
transform_mesh(mesh, matrix)
Arguments
mesh |
A mesh descriptor list with |
matrix |
A 4x4 numeric matrix. |
Value
A new mesh descriptor list with transformed vertices.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
mat <- diag(4)
mat[1:3, 4] <- c(2, 3, 4)
translated <- transform_mesh(mesh, mat)
translated$vertices[1, ]
Translate a mesh
Description
Vertex colors and normals are untouched: a translation does not change the orientation of a surface.
Usage
translate_mesh(mesh, translation)
Arguments
mesh |
A mesh descriptor list. |
translation |
Length-3 numeric vector (x, y, z). |
Value
A new mesh descriptor list with translated vertices.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
moved <- translate_mesh(mesh, c(5, 0, 0))
colMeans(moved$vertices)
Viridis colormap
Description
Returns the viridis color palette. A convenience wrapper around
grDevices::hcl.colors that mimics the viridis color scheme
without requiring extra packages.
Usage
viridis_colormap(n, alpha = 1, direction = 1)
Arguments
n |
Number of colors. |
alpha |
Alpha channel value (0-1). |
direction |
Forward (1) or reversed (-1) direction. |
Value
A character vector of hex color strings.
Examples
cols <- viridis_colormap(10)
plot(1:10, pch = 19, col = cols, cex = 3)
Project world coordinates to image pixels
Description
Runs the same view and projection as the renderer, so the result lands
exactly on the rendered image. Useful to place screen-space annotations
(text_layer(space = "screen")) next to a 3D location, or to
draw callout lines with line_layer in image coordinates.
Usage
world_to_screen(points, camera, width, height, options = NULL)
Arguments
points |
An Nx3 numeric matrix of world coordinates (or a length-3 vector for a single point). |
camera |
A camera list from |
width, height |
Size of the rendered image in pixels. |
options |
Render options, used for the projection type and the clipping
planes. |
Value
A data frame with one row per input point and the columns x,
y (pixels, origin top left), depth (NDC depth, smaller is
closer) and in_front (whether the point is in front of the camera;
for FALSE the pixel coordinates are not meaningful).
See Also
Examples
sph <- generate_sphere(c(0, 0, 0), radius = 1)
cam <- camera_auto(list(sph), direction = c(0, 0, 1))
opts <- render_options(width = 400, height = 300)
world_to_screen(matrix(c(0, 1, 0), ncol = 3), cam, 400, 300, opts)
Write a scene or mesh list to a glTF file
Description
Exports a scene (or a list of meshes) to the glTF 2.0 format, either as a
JSON document with an external binary buffer (.gltf + .bin)
or as a single self-contained binary file (.glb). The resulting
file can be viewed in any glTF-capable viewer (e.g. a browser using
three.js) and includes per-mesh placement transforms, vertex colors, and
optionally a camera.
Usage
write_gltf(meshes, path, camera = NULL, format = c("gltf", "glb"))
Arguments
meshes |
Either a |
path |
Output file path. For |
camera |
Optional camera list from |
format |
Output format: |
Details
Renderer-specific settings (shading mode, fog, SSAO, ...) are not part of the glTF standard and are not exported. Per-face colors are exported by splitting vertices (each triangle gets its own vertices), which increases geometry roughly 3x.
Value
Invisibly NULL.
Examples
cube <- generate_cuboid(c(0, 0, 0), c(0.5, 0.5, 0.5), c(1, 0, 0, 1))
tr <- diag(1, 4); tr[1, 4] <- 2
sc <- scene(list(cube, list(mesh = cube, transform = tr, name = "second")))
out <- tempfile(fileext = ".glb")
write_gltf(sc, out, format = "glb")
Write a rendered image to a PNG file
Description
Writes the output of render_mesh() or render_scene()
to a PNG file using the built-in C++ PNG writer (stb_image_write).
No additional R packages are required.
Usage
write_png(image, filename)
Arguments
image |
An image list returned by |
filename |
Output PNG file path. |
Value
No return value; called for side effects.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
img <- render_mesh(mesh$vertices, mesh$triangles)
tmp_file <- tempfile(fileext = ".png")
write_png(img, tmp_file)
Write a mesh to an STL file
Description
Writes a scimesh mesh descriptor to an ASCII or binary STL file.
Usage
write_stl(mesh, path, format = c("binary", "ascii"))
Arguments
mesh |
A mesh descriptor list. |
path |
Path to the output STL file. |
format |
|
Value
invisible NULL, called for side effects of writing the file.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
tmp_file <- tempfile(fileext = ".stl")
write_stl(mesh, tmp_file, format = "binary")
Write a rendered image to a TGA file
Description
Writes the output of render_mesh() or render_scene()
to a TGA file using scimesh's own C++ TGA writer (no external
dependencies). TGA output is uncompressed true-color.
Usage
write_tga(image, filename, use24bit = FALSE)
Arguments
image |
An image list returned by |
filename |
Output TGA file path. |
use24bit |
If |
Value
No return value; called for side effects.
Examples
mesh <- generate_cuboid(c(0, 0, 0), c(1, 1, 1))
img <- render_mesh(mesh$vertices, mesh$triangles)
tmp_file <- tempfile(fileext = ".tga")
write_tga(img, tmp_file)