/r3f-raymarching

Raymarching abstraction for creating simple SDF animations with threejs.

Primary LanguageTypeScriptMIT LicenseMIT

⚠️ This library is under heavy development

📚More info and documentation will come soon

💡 Purpose of fork

The goal of this fork and library is to create more convinient and elegant way of describing scenes rendered with raymarching approach

Be sure to check original library three-raymarcher by Daniel Esteban ☝🏻

Usage

// TODO


Original repo description lies below, however it may be outdated. 🚩


Examples

Installation

npm i three-raymarcher

Basic usage

import {
  Color,
  PerspectiveCamera,
  Quaternion,
  Scene,
  Vector3,
  WebGLRenderer,
} from "three";
import Raymarcher from "three-raymarcher";

const aspect = window.innerWidth / window.innerHeight;
const camera = new PerspectiveCamera(70, aspect, 0.01, 1000);
const renderer = new WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new Scene();
const raymarcher = new Raymarcher({
  layers: [
    [
      {
        color: new Color(0xff0000),
        operation: Raymarcher.operations.union,
        position: new Vector3(-1.5, 0, -4),
        rotation: new Quaternion(0, 0, 0, 1),
        scale: new Vector3(1, 1, 1),
        shape: Raymarcher.shapes.box,
      },
    ],
    [
      {
        color: new Color(0x00ff00),
        operation: Raymarcher.operations.union,
        position: new Vector3(0, 0, -4),
        rotation: new Quaternion(0, 0, 0, 1),
        scale: new Vector3(0.5, 1, 0.5),
        shape: Raymarcher.shapes.capsule,
      },
    ],
    [
      {
        color: new Color(0x0000ff),
        operation: Raymarcher.operations.union,
        position: new Vector3(1.5, 0, -4),
        rotation: new Quaternion(0, 0, 0, 1),
        scale: new Vector3(1, 1, 1),
        shape: Raymarcher.shapes.sphere,
      },
    ],
  ],
});
scene.add(raymarcher);

renderer.setAnimationLoop(() => renderer.render(scene, camera));

Lighting

three-raymarcher uses indirect PBR lighting only. Direct light support (DirectionalLight/PointLight/SpotLight) will come in future versions.

Assign a CubeUVMap texture to userData.envMap and control it's intensity with userData.envMapIntensity:

new RGBELoader().load("environment.hdr", (texture) => {
  raymarcher.userData.envMap = new PMREMGenerator(renderer).fromEquirectangular(
    texture
  ).texture;
  raymarcher.userData.envMapIntensity = 0.7;
});

userData.metalness controls the global metalness of the material.

userData.roughness controls the global roughness of the material.

If you don't set an envMap, the shader will use vec3(envMapIntensity) as the ambient light.

Raymarching

userData.blending controls the global smoothing of the union and substraction operations.

userData.conetracing enables/disables conetracing (sort of antialias).

You can increase the performance by setting userData.resolution to something less than 1. In most of the examples is set to 0.5 (2x downsampling), which seems to give the best quality/performance trade-off.

Raycasting

three-raymarcher supports the three.js Raycaster out of the box:

const [hit] = raycaster.intersectObject(raymarcher);
if (hit) {
  console.log(
    hit.entityId, // The index of the intersected entity
    hit.entity, // A reference to the intersected entity
    hit.layerId, // The index of the intersected entity layer
    hit.layer // A reference to the intersected entity layer
  );
}

Want to contribute?

Here's how to setup the module dev environment:

# clone this repo
git clone https://github.com/danielesteban/three-raymarcher.git
cd three-raymarcher
# install dependencies
npm install
# start the environment:
npm start
# open http://localhost:8080/examples/animation in your browser