kovacsv
December 20, 2022, 10:16am
1
I’m trying to implement contact shadows based on this example . I managed to create a render target (shadowRenderTarget
) where the base of the contact shadow appears. Now I’d like to blur it like in the example. I have another render target (blurRenderTarget
) to achieve this.
When I do the horizontal blur it seems working:
blurPlaneMesh.material = horizontalBlurMaterial;
blurPlaneMesh.material.uniforms.tDiffuse.value = shadowRenderTarget.texture;
horizontalBlurMaterial.uniforms.h.value = amount * 1 / 256;
renderer.setRenderTarget (blurRenderTarget);
renderer.render (blurPlaneMesh, shadowCamera);
The blurred shadow appears on the blurPlaneMesh
. But when I try to do the vertical blur targeting the original render target it becomes completely white.
blurPlaneMesh.material = verticalBlurMaterial;
blurPlaneMesh.material.uniforms.tDiffuse.value = blurRenderTarget.texture;
verticalBlurMaterial.uniforms.v.value = amount * 1 / 256;
renderer.setRenderTarget (shadowRenderTarget);
renderer.render (blurPlaneMesh, shadowCamera);
I have no idea what I’m doing wrong. Here is a JSFiddle with my result. If you comment out the blurring part at the end you can see that it seems working fine without the blurring.
drcmda
December 20, 2022, 10:51am
2
i struggled a lot with that example, it’s very cryptic, maybe it helps to compare notes with this one. it’s a slightly improved implementation, it looks better and can handle color falloff .
import { HorizontalBlurShader, VerticalBlurShader } from 'three-stdlib'
const smooth = true
const renderer = ...
const scene = ...
const blur = 1
const color = "black"
const resolution = 512
const width = 10
const height = 10
const renderTarget = new THREE.WebGLRenderTarget(resolution, resolution)
const renderTargetBlur = new THREE.WebGLRenderTarget(resolution, resolution)
renderTargetBlur.texture.generateMipmaps = renderTarget.texture.generateMipmaps = false
const planeGeometry = new THREE.PlaneGeometry(width, height).rotateX(Math.PI / 2)
const blurPlane = new THREE.Mesh(planeGeometry)
const depthMaterial = new THREE.MeshDepthMaterial()
depthMaterial.depthTest = depthMaterial.depthWrite = false
depthMaterial.onBeforeCompile = (shader) => {
shader.uniforms = {
...shader.uniforms,
ucolor: { value: new THREE.Color(color) },
}
shader.fragmentShader = shader.fragmentShader.replace(
`void main() {`, //
`uniform vec3 ucolor;
void main() {
`
)
shader.fragmentShader = shader.fragmentShader.replace(
'vec4( vec3( 1.0 - fragCoordZ ), opacity );',
// Colorize the shadow, multiply by the falloff so that the center can remain darker
'vec4( ucolor * fragCoordZ * 2.0, ( 1.0 - fragCoordZ ) * 1.0 );'
)
}
const horizontalBlurMaterial = new THREE.ShaderMaterial(HorizontalBlurShader)
const verticalBlurMaterial = new THREE.ShaderMaterial(VerticalBlurShader)
verticalBlurMaterial.depthTest = horizontalBlurMaterial.depthTest = false
const blurShadows = (blur) => {
blurPlane.visible = true
blurPlane.material = horizontalBlurMaterial
horizontalBlurMaterial.uniforms.tDiffuse.value = renderTarget.texture
horizontalBlurMaterial.uniforms.h.value = (blur * 1) / 256
renderer.setRenderTarget(renderTargetBlur)
renderer.render(blurPlane, shadowCamera.current)
blurPlane.material = verticalBlurMaterial
verticalBlurMaterial.uniforms.tDiffuse.value = renderTargetBlur.texture
verticalBlurMaterial.uniforms.v.value = (blur * 1) / 256
renderer.setRenderTarget(renderTarget)
renderer.render(blurPlane, shadowCamera.current)
blurPlane.visible = false
}
function renderloop() {
const initialBackground = scene.background
scene.background = null
const initialOverrideMaterial = scene.overrideMaterial
scene.overrideMaterial = depthMaterial
renderer.setRenderTarget(renderTarget)
renderer.render(scene, shadowCamera.current)
scene.overrideMaterial = initialOverrideMaterial
blurShadows(blur)
if (smooth) blurShadows(blur * 0.4)
renderer.setRenderTarget(null)
scene.background = initialBackground
you would need the following structure, i’ll leave this in jsx because you most likely have that already, the rotations are necessary.
<group rotation-x={Math.PI / 2} {...props} ref={ref as any}>
<mesh renderOrder={renderOrder} geometry={planeGeometry} scale={[1, -1, 1]} rotation={[-Math.PI / 2, 0, 0]}>
<meshBasicMaterial
map={renderTarget.texture}
map-encoding={gl.outputEncoding}
transparent
opacity={opacity}
depthWrite={depthWrite}
/>
</mesh>
<orthographicCamera ref={shadowCamera} args={[-width / 2, width / 2, height / 2, -height / 2, 0, far]} />
</group>
kovacsv
December 20, 2022, 1:59pm
3
Thanks for the link! Finally I managed to solve the situation, something was off with my camera so I ended up using a completely separate camera for blurring, and now it seems working.