Open-source project
tylermorganwall/rayrender avatar
tylermorganwall/rayrender

rayrender and physically based rendering from inside R

A pathtracer for R. Build and render complex scenes and 3D data visualizations directly from R

645 stars42 forksC++License varies

At a glance

What is it?
rayrender is an R package that wraps a C++ pathtracer, so a scene of primitives and meshes can be built and rendered with a pipeable R interface, with glossy and dielectric surfaces, procedural textures, multicore rendering and optional denoising. The interesting engineering is in the shading model and the texture pipeline, and the interesting constraint is the toolchain the C++ core implies.
Who is it for?
rayrender is a good fit for an R user who wants physically based renders without leaving the language, particularly for 3D data visualisation where a mesh is the subject rather than a model, because the pipeable interface means a scene is built by composing functions and the same call renders it.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A tidy R interface over a C++ pathtracer

rayrender is described in the README as an open source R package for raytracing scenes created in R, providing a tidy R interface to a fast pathtracer written in C++ to render scenes built out of an array of primitives and meshes.

The design decision that matters is the split. R is the modelling and orchestration layer, C++ is the renderer. The repository is C++ heavy, with a src/ directory, and the R side lives in R/ with a NAMESPACE, a DESCRIPTION file and pkgdown configuration in _pkgdown.yml.

The scene-building interface is pipeable, and the usage example shows how that reads:

``` r library(rayrender)

scene = generate_ground(material=diffuse(checkercolor="grey20")) |> add_object(sphere(y=0.2,mat ```

The pipe operator is the point. A scene is a value that you build by composing transformations on it, and the same object is then handed to the renderer. That is idiomatic R rather than a procedural API, and it means a scene can be assembled in a loop or stored and reused without a builder object to manage.

The package is published on CRAN, with a CRAN version badge and a status badge for the r-universe build, and the documentation site is at rayrender.net.

The audience is an R user who wants a still image of a physically based scene, and in particular someone who works with 3D data and wants to render a visualisation rather than a model.

Shading options, textures and the lighting model

The feature list is where the renderer's real capabilities show, and it is more specific than a general list of primitives.

The shading options are diffuse, metallic, dielectric, which is glass, glossy, microfacet, and light emitting. That set covers the physically based categories rather than a single diffuse plus specular model, and the distinction matters: a microfacet surface and a glossy one are different roughness models, and a light emitting surface is what makes an emissive object rather than a lamp in the scene.

Textures are described as procedural or user-specified, with image, roughness, bump and normal texture inputs. Procedural means the texture is computed rather than loaded, so there is no image file to manage, and separating roughness, bump and normal maps from a base colour map is the convention that keeps a physically based pipeline coherent.

HDR environment lighting is supported, which is the other half of making the surfaces read correctly. A shading model without a good environment map looks flat, and an HDRI is the cheapest way to get a plausible response without building the lighting rig by hand.

There is also a geometry layer beyond primitives: OBJ and PLY support, so an existing mesh can be dropped into a scene alongside the generated primitives. The usage example mentions an included R.obj file whose location is returned by the r_obj() function, and the example scene is described as the ground, a sphere and that file. So a typical render is a procedural environment with real geometry in it, which is exactly the shape of a data visualisation.

Multicore, PCG random numbers and a clean package build

Three implementation details are called out in the README and each says something about the project's priorities.

Multicore support comes via RcppThread, with progress bars, which is the difference between an interactive render and an overnight one. A path tracer needs many samples per pixel, and the sample count is where the time goes, so parallelising the sampling loop is the highest-value optimisation available.

Random number generation uses the PCG RNG. That choice is deliberate for a renderer: a path tracer needs many independent random samples, and a generator with good statistical properties and cheap state produces visibly less noise for the same sample count, which is exactly the practical measure that matters here.

Denoising support is provided through Intel Open Image Denoise, and it is optional. The README is clear that if OIDN is not found, rayrender will still work, just without denoising support. That framing is the right one, because denoising is a quality-versus-time knob: a noisy render at high sample count or a denoised render at low sample count, and the package lets you choose.

The repository is a well-behaved R package. There is a .Rbuildignore, a configure and a configure.win script, a cleanup and cleanup.win, a cran_build.R script for CRAN submission, an AGENT.md alongside CONTRIBUTING.md, and tests/ plus a NEWS file. The configure scripts are the interesting part: they are where the package probes for OIDN and enables denoising support if it is found, which is why the README says that after installing OIDN you should reinstall the package from source so that configure can detect it.

Installing the package and the OIDN detour

The package install itself is a single devtools call, and the README shows the GitHub route rather than a CRAN one:

``` r # To install the latest version from Github: # install.packages("devtools") devtools::install_github("tylermorganwall/rayrender")

code

Denoising is the part that takes work, and the reason is that OIDN has to be installed as a separate library and then pointed at.

On macOS you download the appropriate binary for your architecture, extract it, and set the path in your .Renviron:

bash # Extract the archive tar -xvzf oidn-2.3.1.x86_64.macos.tar.gz # or for Apple Silicon tar -xvzf oidn-2.3.1.arm64.macos.tar.gz

# Set OIDN_PATH in your .Renviron file to the extracted directory echo "OIDN_PATH=/path/to/extracted/oidn" >> ~/.Renviron ```

Linux is the same shape with the linux archive. OIDN_PATH should point to a directory that contains include/OpenImageDenoise and lib, or lib64, with the OIDN libraries.

The Windows path is the one the README calls slightly trickier, because it requires Rtools45 and a source build of OIDN. The prerequisites are make and ninja via RTools, plus ISPC, the Intel SPMD Program Compiler, and then compiling and installing OIDN itself and pointing rayrender at it via OIDN_PATH. The build uses a static-posix toolchain with the CPU-only device enabled and the GPU devices turned off, and the install prefix becomes C:/local/oidn-static.

After that, adding the path to the user .Renviron and reinstalling the package from source is what makes configure detect OIDN and enable denoising support on Windows. The dependency tree here, Rtools45 plus MinGW plus ISPC plus a hand-built OIDN, is worth weighing against what denoising actually buys you.

What a path tracer costs and where it is the wrong tool

The honest limitation of this project is inherent to what it is.

A path tracer estimates lighting by sampling paths and averaging, so image quality improves with the number of samples and there is no real-time equivalent. For a still image that is exactly right. For an interactive tool, a live preview, or a scene you intend to adjust over many iterations, the wait is the problem, and the answer is either to lower the sample count and accept noise, or to enable denoising and accept the OIDN setup, or to use a rasteriser instead.

The second limitation is the toolchain. The package compiles C++, so a machine without a compiler cannot install it, and the Windows denoising path needs a specific, dated toolchain in Rtools45 with a static-posix configuration that has to be adjusted to your own install path. This is not a pip install.

The third is that the licence is unknown. The repository listing shows the licence as one GitHub cannot classify and the README does not state one, so anyone intending to use this in a commercial or redistributed context has to resolve that with the author rather than assume a permissive grant.

None of that makes it a poor project, and the mitigations are clear: render at lower samples and denoise, keep the C++ build in a container if the toolchain is awkward, and treat the package as a rendering tool for stills and data visualisation rather than as a viewer.

Editorial conclusion

rayrender is a good fit for an R user who wants physically based renders without leaving the language, particularly for 3D data visualisation where a mesh is the subject rather than a model, because the pipeable interface means a scene is built by composing functions and the same call renders it. It is a poor fit if you need interactive or real-time output, since a pathtracer converges over many samples, and a poor fit for a machine without a C++ toolchain, since the package compiles native code and its Windows denoising path needs Rtools45. Before adopting, check the R-CMD-check and CRAN badges for the current state of the build, and decide whether denoising is worth the Intel Open Image Denoise setup, because that is by far the heaviest part of the install and it is optional.

Frequently asked questions

How do I install the rayrender R package?

The README shows the GitHub route with devtools::install_github("tylermorganwall/rayrender"), noting that devtools itself is installed with install.packages("devtools"). The package also has a CRAN version badge, and a pkgdown documentation site at rayrender.net.

Does rayrender require Intel Open Image Denoise?

No. The README states that if OIDN is not found, rayrender will still work, just without denoising support. To enable it you install OIDN separately and set the OIDN_PATH argument in your .Renviron file, then reinstall the package from source so that configure detects it.

What shading types does rayrender support?

Diffuse, metallic, dielectric for glass, glossy, microfacet and light emitting surfaces, together with procedural or user-specified image, roughness, bump and normal textures, and HDR environment lighting.

What shading types does rayrender support?

Scenes use a pipeable iterative interface. The usage example starts with library(rayrender), builds a scene with generate_ground(material=diffuse(checkercolor="grey20")) piped into add_object, and can include existing OBJ or PLY geometry with the included R.obj file located through r_obj().

Official sources

  1. Issues
  2. Project website
  3. README
  4. tylermorganwall/rayrender on GitHub

Was this useful?