Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
27da4a6
Port pbr bsdf from webgl to webgpu. Use it in pathtracers
TheBlek Feb 16, 2026
60d3a9e
Pass pcg state between stages. Properly account for invalid scatters.
TheBlek Feb 18, 2026
90f2878
Add viewer example
TheBlek Feb 19, 2026
7f1cedf
Collect attributes into one storage array, sample it
TheBlek Feb 19, 2026
12d73c3
Add texture support for megakernel pathtracer
TheBlek Feb 19, 2026
c082fe1
Support attributes and textures in wavefront pathtracer
TheBlek Feb 19, 2026
0252226
Add support for normal maps
TheBlek Feb 19, 2026
caaba88
Cleanup
TheBlek Feb 19, 2026
5069336
Cleanup
TheBlek Feb 21, 2026
6f5b5ba
Merge branch 'webgpu-pathtracer' into webgpu-pbr-materials
TheBlek Mar 2, 2026
b90e438
Merge branch 'webgpu-pathtracer' into webgpu-pbr-materials
TheBlek Mar 11, 2026
39e53ac
Add pathtracing material, implement simple disney-like pbr brdf in a …
TheBlek Mar 12, 2026
779db23
Remove webgpu_viewerTest example
TheBlek Mar 12, 2026
90f81cd
Fix specular fireflies from reflecting under the macronormal plane
TheBlek Mar 12, 2026
6a99097
Return mix of dielectric and metallic
TheBlek Mar 13, 2026
7e05467
Merge branch 'webgpu-pbr-materials' of https://github.com/TheBlek/thr…
TheBlek Mar 13, 2026
e2547c4
Use wi instead of result.direction
TheBlek Mar 13, 2026
bb6c7db
Cleanup
TheBlek Mar 13, 2026
10fdd6c
Use PathTracingMaterial in wavefront pathtracer + Add setMaterial fun…
TheBlek Mar 13, 2026
75f84e8
Fix zero padding values in sample count being taken into account
TheBlek Mar 13, 2026
af41235
Try to remove all fireflies and other artifacts
TheBlek Mar 13, 2026
9237cca
Cleanup
TheBlek Mar 13, 2026
efd5a86
More cleanup
TheBlek Mar 13, 2026
9584446
Add setMaterial on WebGPUPathtracer, cleanup
TheBlek Mar 13, 2026
69dd27f
Add furnace test page
gkjohnson Mar 14, 2026
49a8340
Extend furnace test to webgl pathtracer
TheBlek Mar 14, 2026
dd32908
Add energy scaling term into disney diffuse brdf to conserve energy
TheBlek Mar 14, 2026
cccd3bd
Add material initialization stage. Implement ggx multiscatter compens…
TheBlek Mar 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions example/furnace_test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<html>
<head>
<title>Furnace Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

<style>
html, body {
margin: 0;
padding: 0;
}
</style>

</head>
<body>
<script src="./furnace_test.js" type="module"></script>
</body>
</html>
157 changes: 157 additions & 0 deletions example/furnace_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { Scene, SphereGeometry, MeshStandardMaterial, Mesh, PerspectiveCamera, WebGPURenderer } from 'three/webgpu';
import { WebGLRenderer } from 'three';
import { GradientEquirectTexture } from 'three-gpu-pathtracer';
import { WebGPUPathTracer } from 'three-gpu-pathtracer/webgpu';
import { WebGLPathTracer } from 'three-gpu-pathtracer';
import GUI from 'three/examples/jsm/libs/lil-gui.module.min.js';

const options = {
enable: true,
useMegakernel: true,
isWebGPU: true,
};

// init scene
const scene = new Scene();

// build an 11x11 grid of spheres:
// roughness increases left to right
// metalness increases top to bottom
const sphereGeom = new SphereGeometry( 0.4, 100, 50 );
for ( let x = 0; x <= 10; x ++ ) {

for ( let y = 0; y <= 10; y ++ ) {

const mesh = new Mesh(
sphereGeom,
new MeshStandardMaterial( {
color: 0xffffff,
roughness: x / 10,
metalness: y / 10,
} )
);

mesh.position.x = x - 5;
mesh.position.y = 5 - y;
scene.add( mesh );

}

}

const texture = new GradientEquirectTexture();
texture.topColor.set( 0xcccccc );
texture.bottomColor.set( 0xcccccc );
texture.update();

scene.environment = texture;
scene.background = texture;

const camera = new PerspectiveCamera( 40, 1, 1, 100 );
camera.position.set( 0, 0, 18 );

let renderer;
let pathTracer;

function createRendererAndPathTracer() {

if ( renderer ) {

renderer.dispose();
pathTracer.dispose();
document.body.removeChild( renderer.domElement );

}

if ( options.isWebGPU ) {

renderer = new WebGPURenderer( { antialias: true, trackTimestamp: false } );
renderer.init();
pathTracer = new WebGPUPathTracer( renderer );
pathTracer.useMegakernel( options.useMegakernel );

} else {

renderer = new WebGLRenderer( { antialias: true } );
pathTracer = new WebGLPathTracer( renderer );

}

document.body.appendChild( renderer.domElement );
renderer.setSize( innerWidth, innerHeight );
renderer.setPixelRatio( devicePixelRatio );
renderer.setAnimationLoop( animate );
pathTracer.setScene( scene, camera );
pathTracer.reset();

}

createRendererAndPathTracer();

const gui = new GUI();
gui.add( options, 'enable' );
const megakernelController = gui.add( options, 'useMegakernel' ).onChange( () => {

if ( options.isWebGPU ) {

pathTracer.useMegakernel( options.useMegakernel );

}

pathTracer.setScene( scene, camera );
pathTracer.reset();

} );
gui.add( options, 'isWebGPU' ).onChange( () => {

createRendererAndPathTracer();

if ( ! options.isWebGPU ) {

megakernelController.hide();

} else {

megakernelController.show();

}

} );

onResize();

window.addEventListener( 'resize', onResize );

function animate() {

if ( options.enable ) {

if ( ! pathTracer.dynamicLowRes && pathTracer.fadeState !== 1 ) {

renderer.render( scene, camera );

}

pathTracer.renderSample();

} else {

renderer.render( scene, camera );

}

}

function onResize() {

const w = window.innerWidth;
const h = window.innerHeight;

renderer.setSize( w, h );
renderer.setPixelRatio( window.devicePixelRatio );

const aspect = w / h;
camera.aspect = aspect;
camera.updateProjectionMatrix();

}
Loading