Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
61 changes: 61 additions & 0 deletions examples/jsm/tsl/display/boxBlur.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Fn, vec2, uv, Loop, vec4, premultiplyAlpha, unpremultiplyAlpha, max, int, textureSize, nodeObject } from 'three/tsl';

/**
* Applies a box blur effect to the given texture node.
*
* Compared to Gaussian blur, box blur produces a more blocky result but with better performance when correctly
* configured. It is intended for mobile device or performance restricted use cases where Gaussian is too heavy.
*
* The (kernel) `size` parameter should be small (1, 2 or 3) since it determines the number of samples based on (size * 2 + 1)^2.
* This implementation uses a single pass approach so the kernel is not applied as a separate filter. That means larger
* kernels won't perform well. Use Gaussian instead if you need a more high-quality blur.
*
* To produce wider blurs, increase the `separation` parameter instead which has no influence on the performance.
*
* Reference: {@link https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/box-blur.frag}.
*
* @function
* @param {Node<vec4>} textureNode - The texture node that should be blurred.
* @param {Object} [options={}] - Additional options for the hash blur effect.
* @param {Node<int>} [options.size=int(1)] - Controls the blur's kernel. For performant results, the range should within [1, 3].
* @param {Node<int>} [options.separation=int(1)] - Spreads out the blur without having to sample additional fragments. Ranges from [1, Infinity].
* @param {boolean} [options.premultipliedAlpha=false] - Whether to use premultiplied alpha for the blur effect.
* @return {Node<vec4>} The blurred texture node.
*/
export const boxBlur = /*#__PURE__*/ Fn( ( [ textureNode, options = {} ] ) => {

const size = nodeObject( options.size ) || int( 1 );
const separation = nodeObject( options.separation ) || int( 1 );
const premultipliedAlpha = options.premultipliedAlpha || false;

const tap = ( uv ) => {

const sample = textureNode.sample( uv );
return premultipliedAlpha ? premultiplyAlpha( sample ) : sample;

};

const targetUV = textureNode.uvNode || uv();

const result = vec4( 0 );
const sep = max( separation, 1 );
const count = int( 0 );
const pixelStep = vec2( 1 ).div( textureSize( textureNode ) );

Loop( { start: size.negate(), end: size, name: 'i', condition: '<=' }, ( { i } ) => {

Loop( { start: size.negate(), end: size, name: 'j', condition: '<=' }, ( { j } ) => {

const uvs = targetUV.add( vec2( i, j ).mul( pixelStep ).mul( sep ) );
result.addAssign( tap( uvs ) );
count.addAssign( 1 );

} );

} );

result.divAssign( count );

return premultipliedAlpha ? unpremultiplyAlpha( result ) : result;

} );
Binary file modified examples/screenshots/webgpu_postprocessing_dof_basic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 9 additions & 5 deletions examples/webgpu_postprocessing_dof_basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

import * as THREE from 'three/webgpu';
import { mix, pass, renderOutput, smoothstep, uniform, vec3 } from 'three/tsl';
import { gaussianBlur } from 'three/addons/tsl/display/GaussianBlurNode.js';
import { boxBlur } from 'three/addons/tsl/display/boxBlur.js';
import { fxaa } from 'three/addons/tsl/display/FXAANode.js';

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
Expand Down Expand Up @@ -115,20 +115,23 @@

// DOF uniforms

const maxBlur = uniform( 2 ); // maximum amount of blur
const blurSize = uniform( 2 ); // determines the kernel size of the blur
const blurSpread = uniform( 4 ); // determines how far the blur is spread
const minDistance = uniform( 1 ); // all positions at or below minDistance will be completely in focus.
const maxDistance = uniform( 3 ); // all positions at or beyond maxDistance will be completely out of focus.

// beauty and blur/out-of-focus pass

const scenePass = pass( scene, camera );

const scenePassColor = scenePass.getTextureNode();
const scenePassViewZ = scenePass.getViewZNode();
const scenePassBlurred = gaussianBlur( scenePass, maxBlur );
const scenePassBlurred = boxBlur( scenePassColor, { size: blurSize, separation: blurSpread } );

// simple DOF from https://lettier.github.io/3d-game-shaders-for-beginners/depth-of-field.html

const blur = smoothstep( minDistance, maxDistance, scenePassViewZ.sub( focusPointView.z ).abs() );
const dofPass = mix( scenePass, scenePassBlurred, blur );
const dofPass = mix( scenePassColor, scenePassBlurred, blur );

const outputPass = renderOutput( dofPass );
const fxaaPass = fxaa( outputPass );
Expand All @@ -140,7 +143,8 @@
const gui = new GUI();
gui.add( minDistance, 'value', 0, 3 ).name( 'min distance' );
gui.add( maxDistance, 'value', 0, 5 ).name( 'max distance' );
gui.add( maxBlur, 'value', 0, 5 ).name( 'max blur' );
gui.add( blurSize, 'value', 1, 3, 1 ).name( 'blur size' );
gui.add( blurSpread, 'value', 1, 7, 1 ).name( 'blur spread' );

//

Expand Down
Loading