Looks like the TriangleBlurShader
works a lot better. Here’s an fiddle using triangle blur: Edit fiddle - JSFiddle - Code Playground.
The function is:
const {OrthographicCamera, Scene, WebGLRenderTarget, ShaderMaterial, UniformsUtils, PlaneGeometry, Mesh, TriangleBlurShader, Vector2} = THREE
function makeTriangleBlurShader(iterations = 10) {
// Remove texture, because texture is a reserved word in WebGL 2
const {texture, ...uniforms} = TriangleBlurShader.uniforms
const TriangleBlurShader2 = {
...TriangleBlurShader,
name: 'TriangleBlurShader2',
uniforms: {
...uniforms,
// Replace texture with blurTexture for WebGL 2
blurTexture: {value: null},
},
}
// Replace texture with blurTexture for WebGL 2
TriangleBlurShader2.fragmentShader = TriangleBlurShader2.fragmentShader.replace(
'uniform sampler2D texture;',
'uniform sampler2D blurTexture;',
)
TriangleBlurShader2.fragmentShader = TriangleBlurShader2.fragmentShader.replace(
'texture2D( texture',
'texture2D( blurTexture',
)
// Make iterations configurable.
TriangleBlurShader2.fragmentShader = TriangleBlurShader2.fragmentShader.replace(
'#define ITERATIONS 10.0',
'#define ITERATIONS ' + iterations + '.0',
)
console.log('shader:', TriangleBlurShader2.fragmentShader)
return TriangleBlurShader2
}
function triangleBlurTexture(
renderer,
texture,
radius = 10,
passes = 1,
iterations = 10,
) {
const width = texture.image.width
const height = texture.image.height
// renderer = new WebGLRenderer()
const cameraRTT = new OrthographicCamera(-1, 1, 1, -1, 0, 1)
const sceneRTT = new Scene()
// render targets
const renderTarget1 = new WebGLRenderTarget(width, height)
const renderTarget2 = new WebGLRenderTarget(width, height)
// shader materials
const shader = makeTriangleBlurShader(iterations)
const blurMaterial = new ShaderMaterial({
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader,
uniforms: UniformsUtils.clone(shader.uniforms),
})
blurMaterial.uniforms.delta.value = new Vector2(1, 1)
// fullscreen quad
const planeGeometry = new PlaneGeometry(2, 2)
const fullScreenQuad = new Mesh(planeGeometry, blurMaterial)
sceneRTT.add(fullScreenQuad)
// passes
let lastTexture = texture
while (passes--) {
// vertical pass
blurMaterial.uniforms.blurTexture.value = lastTexture
blurMaterial.uniforms.delta.value = new Vector2(radius / width, 0)
renderer.setRenderTarget(renderTarget1)
renderer.render(sceneRTT, cameraRTT)
renderer.setRenderTarget(null)
lastTexture = renderTarget1.texture
// horizontal pass
blurMaterial.uniforms.blurTexture.value = lastTexture
blurMaterial.uniforms.delta.value = new Vector2(0, radius / height)
renderer.setRenderTarget(renderTarget2)
renderer.render(sceneRTT, cameraRTT)
renderer.setRenderTarget(null)
lastTexture = renderTarget2.texture
}
//
return lastTexture
}
The radius is a lot easier to control with the triangle blur, here for example a value of 40: Edit fiddle - JSFiddle - Code Playground