Path tracing project using three-mesh-bvh and WebGL 2 to accelerate high quality, physically based rendering on the GPU. Features include support for GGX surface model, material information, textures, normal maps, emission, environment maps, tiled rendering, and more!
More features and capabilities in progress!
Beauty Demos
Features
Test Scenes
Light Baking
import * as THREE from 'three';
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
import {
PathTracingSceneGenerator,
PathTracingRenderer,
PhysicalPathTracingMaterial,
} from 'three-gpu-pathtracer';
// init scene, renderer, camera, controls, etc
// initialize the path tracing material and renderer
const ptMaterial = new PhysicalPathTracingMaterial();
const ptRenderer = new PathTracingRenderer( renderer );
ptRenderer.camera = camera;
ptRenderer.material = ptMaterial;
// init quad for rendering to the canvas
const fsQuad = new FullScreenQuad( new THREE.MeshBasicMaterial( {
map: ptRenderer.target.texture,
} ) );
// initialize the scene and update the material properties with the bvh, materials, etc
const generator = new PathTracingSceneGenerator();
const { bvh, textures, materials } = generator.generate( scene );
// update bvh and geometry attribute textures
ptMaterial.bvh.updateFrom( bvh );
ptMaterial.normalAttribute.updateFrom( geometry.attributes.normal );
ptMaterial.tangentAttribute.updateFrom( geometry.attributes.tangent );
ptMaterial.uvAttribute.updateFrom( geometry.attributes.uv );
// update materials and texture arrays
ptMaterial.materialIndexAttribute.updateFrom( geometry.attributes.materialIndex );
ptMaterial.textures.setTextures( renderer, 2048, 2048, textures );
ptMaterial.materials.updateFrom( materials, textures );
ptMaterial.setDefine( 'MATERIAL_LENGTH', materials.length );
// set the environment map
const texture = await new RGBELoader().loadAsync( envMapUrl );
const pmremGenerator = new THREE.PMREMGenerator( renderer );
const envMap = pmremGenerator.fromEquirectangular( texture );
ptRenderer.material.environmentMap = envMap.texture;
animate();
// ...
function animate() {
// if the camera position changes call "ptRenderer.reset()"
// update the camera and render one sample
camera.updateMatrixWorld();
ptRenderer.update();
// copy the current state of the path tracer to canvas to display
renderer.autoClear = false;
fsQuad.material.map = ptRenderer.target.texture;
fsQuad.render( renderer );
renderer.autoClear = true;
}
Using the dynamic scene generator the same, frequently updated scene can be converted into a single reusable geometry multiple times and BVH refit which greatly improves subsequent scene updates. See DynamicPathTracingSceneGenerator
docs for more info.
import { DynamicPathTracingSceneGenerator } from 'three-gpu-pathtracer';
// ... initialize scene etc
const generator = new DynamicPathTracingSceneGenerator( scene );
const { bvh, textures, materials } = generator.generate( scene );
// ... update path tracer and render
NOTE WebWorker syntax is inconsistently supported across bundlers and sometimes not supported at all so the PathTracingSceneWorker class is not exported from the package root. If needed the code from src/worker can be copied and modified to accomodate a particular build process.
import { PathTracingSceneWorker } from 'three-gpu-pathtracer/src/workers/PathTracingSceneWorker.js';
// ...
// initialize the scene and update the material properties with the bvh, materials, etc
const generator = new PathTracingSceneWorker();
const { bvh, textures, materials } = await generator.generate( scene );
// ...
Utility class for tracking and rendering a path traced scene to a render target.
readonly samples : Number
Number of samples per pixel that have been rendered to the target.
readonly target : WebGLRenderTarget
The target being rendered to. The size of the target is updated with setSize
and is initialized to a FloatType texture.
camera = null : Camera
The camera to render with. The view offset of the camera will be updated every sample to enable anti aliasing.
material = null : ShaderMaterial
The Path Tracing material to render. This is expected to be a full screen quad material that respects the "opacity" field for every pixel so samples can be accumulated over time. The material is also expected to have cameraWorldMatrix
and invProjectionMatrix
fields of type Matrix4
.
tiles = ( 1, 1 ) : Vector2
Number of tiles on x and y to render to. Can be used to improve the responsiveness of a page while still rendering a high resolution target.
stableNoise = false
Whether to reset the random seed to 0
when restarting the render. If true then a consistent random sample pattern will appear when moving the camera, for example.
constructor( renderer : WebGLRenderer )
setSize( size : Vector2 ) : void
Sets the size of the target to render to.
update()
Renders a single sample to the target.
reset() : void
Resets and restarts the render from scratch.
Utility class for generating the set of data required for initializing the path tracing material with a bvh, geometry, materials, and textures.
generate( scene : Object3D, options = {} : Object ) : {
bvh : MeshBVH,
materials : Array<Material>,
textures : Array<Texture>
}
Merges the geometry in the given scene with an additional "materialIndex" attribute that references the associated material array. Also produces a set of textures referenced by the scene materials.
extends PathTracingSceneGenerator
See note in Asyncronous Generation use snippet.
async generate( scene : Object3D, options = {} : Object ) : {
bvh : MeshBVH,
materials : Array<Material>,
textures : Array<Texture>
}
dispose() : void
extends THREE.PerspectiveCamera
An extension of the three.js PerspectiveCamera with some other parameters associated with depth of field. These parameters otherwise do not affect the camera behavior are are for convenience of use with the PhysicalCameraUniform and pathtracer.
focusDistance = 25 : Number
The distance from the camera in meters that everything is is perfect focus.
fStop = 1.4 : Number
The fstop value of the camera. If this is changed then the bokehSize
field is implicitly updated.
bokehSize : Number
The bokeh size as derived from the fStop and focal length in millimeters. If this is set then the fStop is implicitly updated.
apertureBlades = 0 : Number
The number of sides / blades on the aperture.
apertureRotation = 0 : Number
The rotation of the aperture shape in radians.
anamorphicRatio = 1 : Number
The anamorphic ratio of the lens. A higher value will stretch the bokeh effect horizontally.
A variation of the path tracing scene generator intended for quickly regenerating a scene BVH representation that updates frequently. Ie those with animated objects or animated skinned geometry.
In order to quickly update a dynamic scene the same BVH is reused across updates by refitting rather than regenerating. This is significantly faster but also results in a less optimal BVH after significant changes.
If geometry or materials are added or removed from the scene then reset
must be called.
constructor( scene : Object3D )
Takes the scene to convert.
generate() : {
bvh : MeshBVH,
materials : Array<Material>,
textures : Array<Texture>
}
Generates and refits the bvh to the current scene state. The same bvh, materials, and textures objects are returns after the initial call until reset
is called.
reset() : void
Resets the generator so a new BVH is generated. This must be called when geometry, objects, or materials are added or removed from the scene.
extends THREE.ShaderMaterial
Convenience base class that adds additional functions and implicitly adds object definitions for all uniforms of the shader to the object.
setDefine( name : string, value = undefined : any ) : void
Sets the define of the given name to the provided value. If the value is set to null or undefined then it is deleted from the defines of the material. If the define changed from the previous value then Material.needsUpdate
is set to true
.
extends MaterialBase
Uniforms
{
// The number of ray bounces to test. Higher is better quality but slower performance.
bounces = 3 : Number,
// The physical camera parameters to use
physicalCamera : PhysicalCameraUniform,
// Geometry and BVH information,
bvh: MeshBVHUniformStruct,
normalAttribute: FloatVertexAttributeTexture,
tangentAttribute: FloatVertexAttributeTexture,
uvAttribute: FloatVertexAttributeTexture,
materialIndexAttribute: UIntVertexAttributeTexture,
materials: MaterialStructArrayUniform,
textures: RenderTarget2DArray,
// PMREM-processed Environment Map,
environmentMap: Texture,
environmentRotaton: Matrix3,
// Environment Map information,
environmentBlur = 0: Number,
environmentIntensity = 1: Number,
// Factor for alleviating bright pixels from rays that hit diffuse surfaces then
// specular surfaces. Setting this higher alleviates fireflies but will remove some
// specular caustics.
filterGlossyFactor = 0: Number,
// The colors to use for the gradient env lighting when no environment map is provided.
gradientTop: Color,
gradientBottom: Color,
// The colors to use for the gradient background when enabled.
bgGradientTop: Color,
bgGradientBottom: Color,
}
Defines
{
// Whether the shader should include logic for physical camera and depth of field
DOF_SUPPORT = 1 : Number,
// The number of transparent pixels to allow on top of existing bounces for object transparency.
TRANSPARENT_TRAVERSALS = 5 : Number,
// Whether to use the "bg" gradient fields to sample for the backround
GRADIENT_BG = 0 : Number
// The number of materials provided in the "materials" uniform.
MATERIAL_LENGTH : Number,
}
extends WebGLArrayRenderTarget
A convenience extension from WebGLArrayRenderTarget
that affords easily creating a uniform texture array from an array of textures.
setTextures(
renderer : WebGLRenderer,
width : Number,
height : Number,
textures : Array<Texture>
) : void
Takes the rendering context to updateh the target for, the target dimensions of the texture array, and the array of textures to render into the 2D texture array. Every texture is stretched to the dimensions of the texture array at the same index they are provided in.
Uniform for storing the camera parameters for use with the shader.
updateFrom( camera : PerspectiveCamera | PhysicalCamera ) : void
Copies all fields from the passed PhysicalCamera if available otherwise the defaults are used.
extends Array
Array of MaterialStructUniform
definitions for use as a Shader uniform.
updateFrom( materials : Array<Material>, textures : Array<Texture> ) : void
Updates the value of the uniform to align with the provided set of materials and textures.
Struct definiton for representing material information as a uniform. See the implementation for full struct definition information.
side = 0 : Number
This is the only field that needs to be set explicitly and is not derived from the Material setting. It defaults to rendering double sided triangles since transmissive volumes require solid, double sided geometry. The possible options are as follows:
0 // Double Sided
1 // Front Sided
-1 // Back Sided
updateFrame( material : Material, textures : Array<Texture> ) : void
Updates the uniform with the information from the passed material. Texture fields are set to the index of the texture in the provided textures array.
mergeMeshes( meshes : Array<Mesh> ) : {
materials : Array<Material>,
textures : Array<Textures>,
geometry : BufferGeometry
}
Merges the set of meshes into a single geometry with a materialIndex
vertex attribute included on the geometry identifying the associated material in the returned materials
array.
shaderMaterialSampling
Set of functions for performing material scatter and PDF sampling. See the implementation for full list of functions.
shaderStructs
Material struct definition for use with uniforms. See the implementation for full list of functions.
shaderUtils
Set of randomness and other light transmport utilities for use in a shader. See the implementation for full list of functions.
- The project requires use of WebGL2.
- All textures must use the same wrap and interpolation flags.
- Texture repeat, rotation, and center properties are not supported.
Sample materials
"SD Macross City Standoff Diorama" scene by tipatat
"Interior Scene" model by Allay Design
Perseverance Rover, Ingenuity Helicopter models by NASA / JPL-Caltech
Gelatinous Cube model by glenatron
Lego models courtesy of the LDraw Official Model Repository
Octopus Tea model by AzTiZ