Three.js a470d3 - WebGPU PCF blur samples
by Joe Pea
HTML
<!-- set up a custom patch of the three/webgpu import to patch PCFShadowFilter -->
<script>{
const gitCommit = 'a470d32cdbdfe23399af3a237a9879f2614fb5d6'
const xhr = new XMLHttpRequest()
xhr.addEventListener( 'load', () => writeImportmap( patchTsl() ) )
xhr.open( 'GET', `https://cdn.jsdelivr.net/gh/mrdoob/three.js@${gitCommit}/build/three.webgpu.js`, false )
xhr.send()
function writeImportmap( patchedTslUrl ) {
document.write( `
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/gh/mrdoob/three.js@${gitCommit}/build/three.module.js",
"three/core": "https://cdn.jsdelivr.net/gh/mrdoob/three.js@${gitCommit}/build/three.core.js",
"three/webgpu": "${patchedTslUrl}",
"three/tsl": "https://cdn.jsdelivr.net/gh/mrdoob/three.js@${gitCommit}/build/three.tsl.js",
"three/addons/": "https://cdn.jsdelivr.net/gh/mrdoob/three.js@${gitCommit}/examples/jsm/"
}
}
<\/script>
` )
}
function patchTsl() {
let source = xhr.responseText
source = source.replaceAll('./three.core.js', 'three/core')
source = source.replace(
'let _rendererState',
`
_shadowFilterLib[ 1 ] = Fn( ( { depthTexture, shadowCoord, shadow, depthLayer } ) => {
const depthCompare = (uv, compare) => {
let depth = texture(depthTexture, uv);
if (depthTexture.isArrayTexture) {
depth = depth.depth(depthLayer);
}
return depth.compare(compare);
};
const mapSize = reference('mapSize', 'vec2', shadow).setGroup(renderGroup);
const radius = reference('radius', 'float', shadow).setGroup(renderGroup);
const texelSize = vec2(1).div(mapSize);
const radiusScaled = radius.mul(texelSize.x);
// Use IGN to rotate sampling pattern per pixel (phi = IGN * 2Ď€)
...
JavaScript
import * as THREE from 'three/webgpu';
import { Inspector } from 'three/addons/inspector/Inspector.js';
import { PLYLoader } from 'three/addons/loaders/PLYLoader.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
let camera, scene, renderer, clock;
let dirLight, spotLight;
let dirGroup;
const config = {
spotlightResolution: 256,
spotlightRadius: 4,
spotlightSamples: 8,
spotlightBias: 0,
spotlightNormalBias: 0,
spotlightIntensity: 1,
spotlightFocus: 1,
dirlightResolution: 256,
dirlightRadius: 4,
dirlightSamples: 50,
dirlightBias: 0,
dirlightNormalBias: 0,
dirlightIntensity: 1,
animationSpeed: 1,
};
init();
function init() {
initScene();
initMisc();
// Init gui
const gui = renderer.inspector.createParameters( 'Settings' );
const resolutions = [ 64, 128, 256, 512, 1024, 2048 ];
const spotlightFolder = gui.addFolder( 'Spotlight Shadow' );
spotlightFolder.add( config, 'spotlightResolution', resolutions ).name( 'resolution' ).onChange( function ( value ) {
// WIP this is not working, changing the size freezes the rendering
spotLight.shadow.mapSize.width = value;
spotLight.shadow.mapSize.height = value;
spotLight.needsUpdate = true;
} );
spotlightFolder.add( config, 'spotlightRadius', 0, 20 ).name( 'radius' ).onChange( function ( value ) {
spotLight.shadow.radius = value;
} );
spotlightFolder.add( config, 'spotlightSamples', 1, 50, 1 ).name( 'samples' ).onChange( function ( value ) {
spotLight.shadow.blurSamples = value;
// spotLight.shadow.dispose()
} );
spotlightFolder.add( config, 'spotlightBias', -0.05, 0.05, 0.001 ).name( 'bias' ).onChange( function ( value ) {
spotLight.shadow.bias = value;
} );
spotlightFolder.add( config, 'spotlightNormalBias', -1, 1, 0.001 ).name( 'normal bias' ).onChange( function ( value ) {
spotLight.shadow.normalBias =...