From 573d980f2c6ea9b0bd39c64404c6288527f21146 Mon Sep 17 00:00:00 2001 From: dongho-shin Date: Wed, 12 Jul 2023 23:02:24 +0900 Subject: [PATCH 1/5] block memory alloc in target set --- src/effects/DepthOfField.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/effects/DepthOfField.tsx b/src/effects/DepthOfField.tsx index 9b8ca766..339b9420 100644 --- a/src/effects/DepthOfField.tsx +++ b/src/effects/DepthOfField.tsx @@ -26,14 +26,18 @@ export const DepthOfField = forwardRef(function DepthOfField( const maskMaterial = (effect as any).maskPass.getFullscreenMaterial() maskMaterial.maskFunction = MaskFunction.MULTIPLY_RGB_SET_ALPHA return effect + }, []) + const depthTarget = useMemo(() => new Vector3(), []) + useLayoutEffect(() => { + invalidate() }, [camera, props]) useLayoutEffect(() => { - if (target && typeof target !== 'number') { - const vec: Vector3 = - target instanceof Vector3 - ? new Vector3().set(target.x, target.y, target.z) - : new Vector3().set(target[0], target[1], target[2]) - effect.target = vec + if (target) { + if (typeof target === 'number') depthTarget.set(target, target, target) + else if (target.isVector3) depthTarget.copy(target) + else depthTarget.set(target[0], target[1], target[2]) + + effect.target = depthTarget } if (depthTexture) effect.setDepthTexture(depthTexture.texture, depthTexture.packing as DepthPackingStrategies) invalidate() From 9c0853012aa765bb1bfdea6903a149729645a86d Mon Sep 17 00:00:00 2001 From: dongho-shin Date: Sat, 29 Jul 2023 12:24:03 +0900 Subject: [PATCH 2/5] fix texture memory leak --- src/effects/DepthOfField.tsx | 63 +++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/src/effects/DepthOfField.tsx b/src/effects/DepthOfField.tsx index 339b9420..58d5bceb 100644 --- a/src/effects/DepthOfField.tsx +++ b/src/effects/DepthOfField.tsx @@ -1,4 +1,4 @@ -import { DepthOfFieldEffect, MaskFunction } from 'postprocessing' +import { BlendFunction, DepthOfFieldEffect, MaskFunction, Resolution } from 'postprocessing' import { Ref, forwardRef, useMemo, useLayoutEffect, useContext } from 'react' import { ReactThreeFiber, useThree } from '@react-three/fiber' import { type DepthPackingStrategies, type Texture, Vector3 } from 'three' @@ -19,7 +19,7 @@ export const DepthOfField = forwardRef(function DepthOfField( ref: Ref ) { const invalidate = useThree((state) => state.invalidate) - const { camera } = useContext(EffectComposerContext) + const { camera, scene } = useContext(EffectComposerContext) const effect = useMemo(() => { const effect = new DepthOfFieldEffect(camera, props) // Temporary fix that restores DOF 6.21.3 behavior, everything since then lets shapes leak through the blur @@ -27,17 +27,72 @@ export const DepthOfField = forwardRef(function DepthOfField( maskMaterial.maskFunction = MaskFunction.MULTIPLY_RGB_SET_ALPHA return effect }, []) - const depthTarget = useMemo(() => new Vector3(), []) + + useLayoutEffect(() => { + return () => { + const depthEffect = effect as any + depthEffect.blurPass.renderTargetA.dispose() + depthEffect.blurPass.renderTargetB.dispose() + depthEffect.maskPass.dispose() + depthEffect.cocPass.dispose() + depthEffect.renderTarget.dispose() + depthEffect.renderTargetCoC.dispose() + depthEffect.renderTargetCoCBlurred.dispose() + depthEffect.renderTargetMasked.dispose() + depthEffect.renderTargetNear.dispose() + depthEffect.renderTargetFar.dispose() + } + }, []) + + useLayoutEffect(() => { + effect.mainScene = scene + effect.mainCamera = camera + invalidate() + }, [camera, scene]) + + useLayoutEffect(() => { + effect.bokehScale = props.bokehScale ?? 1.0 + effect.resolution.width = props.resolutionX ?? props.width ?? Resolution.AUTO_SIZE + effect.resolution.height = props.resolutionY ?? props.height ?? Resolution.AUTO_SIZE + effect.resolution.scale = props.resolutionScale ?? 1.0 + effect.blendMode.blendFunction = props.blendFunction ?? BlendFunction.NORMAL + invalidate() + }, [ + props.blur, + props.width, + props.height, + props.blendFunction, + props.bokehScale, + props.resolutionScale, + props.resolutionX, + props.resolutionY, + ]) + + useLayoutEffect(() => { + effect.circleOfConfusionMaterial.focusDistance = props.focusDistance ?? 0.0 + effect.circleOfConfusionMaterial.focalLength = props.focalLength ?? 0.1 + effect.circleOfConfusionMaterial.focusRange = props.focusRange ?? 0.1 + invalidate() + }, [props.focusDistance, props.focusRange, props.focalLength]) + useLayoutEffect(() => { + effect.circleOfConfusionMaterial.worldFocusDistance = props.worldFocusDistance ?? 0.0 + effect.circleOfConfusionMaterial.worldFocusRange = props.worldFocusRange ?? 0.1 invalidate() - }, [camera, props]) + }, [props.worldFocusDistance, props.worldFocusRange]) useLayoutEffect(() => { if (target) { + const depthTarget = new Vector3() if (typeof target === 'number') depthTarget.set(target, target, target) + //@ts-ignore else if (target.isVector3) depthTarget.copy(target) + //@ts-ignore else depthTarget.set(target[0], target[1], target[2]) effect.target = depthTarget + } else { + //@ts-ignore + effect.target = null } if (depthTexture) effect.setDepthTexture(depthTexture.texture, depthTexture.packing as DepthPackingStrategies) invalidate() From 0c24dbf1bda19c94d0c044524d5c025f7673fbc6 Mon Sep 17 00:00:00 2001 From: Cody Bennett <23324155+CodyJasonBennett@users.noreply.github.com> Date: Wed, 23 Aug 2023 07:49:23 -0500 Subject: [PATCH 3/5] chore(DepthOfField): cleanup --- src/effects/DepthOfField.tsx | 135 ++++++++++++++++------------------- 1 file changed, 60 insertions(+), 75 deletions(-) diff --git a/src/effects/DepthOfField.tsx b/src/effects/DepthOfField.tsx index 58d5bceb..8ff92959 100644 --- a/src/effects/DepthOfField.tsx +++ b/src/effects/DepthOfField.tsx @@ -1,6 +1,6 @@ -import { BlendFunction, DepthOfFieldEffect, MaskFunction, Resolution } from 'postprocessing' -import { Ref, forwardRef, useMemo, useLayoutEffect, useContext } from 'react' -import { ReactThreeFiber, useThree } from '@react-three/fiber' +import { DepthOfFieldEffect, MaskFunction } from 'postprocessing' +import { Ref, forwardRef, useMemo, useEffect, useContext } from 'react' +import { ReactThreeFiber } from '@react-three/fiber' import { type DepthPackingStrategies, type Texture, Vector3 } from 'three' import { EffectComposerContext } from '../EffectComposer' @@ -9,93 +9,78 @@ type DOFProps = ConstructorParameters[1] & target: ReactThreeFiber.Vector3 depthTexture: { texture: Texture + // TODO: narrow to DepthPackingStrategies packing: number } + // TODO: not used blur: number }> export const DepthOfField = forwardRef(function DepthOfField( - { target, depthTexture, ...props }: DOFProps, + { + blendFunction, + worldFocusDistance, + worldFocusRange, + focusDistance, + focusRange, + focalLength, + bokehScale, + resolutionScale, + resolutionX, + resolutionY, + width, + height, + target, + depthTexture, + ...props + }: DOFProps, ref: Ref ) { - const invalidate = useThree((state) => state.invalidate) - const { camera, scene } = useContext(EffectComposerContext) + const { camera } = useContext(EffectComposerContext) const effect = useMemo(() => { - const effect = new DepthOfFieldEffect(camera, props) + const effect = new DepthOfFieldEffect(camera, { + blendFunction, + worldFocusDistance, + worldFocusRange, + focusDistance, + focusRange, + focalLength, + bokehScale, + resolutionScale, + resolutionX, + resolutionY, + width, + height, + }) + if (target) effect.target = new Vector3(...(target as number[])) + if (depthTexture) effect.setDepthTexture(depthTexture.texture, depthTexture.packing as DepthPackingStrategies) // Temporary fix that restores DOF 6.21.3 behavior, everything since then lets shapes leak through the blur const maskMaterial = (effect as any).maskPass.getFullscreenMaterial() maskMaterial.maskFunction = MaskFunction.MULTIPLY_RGB_SET_ALPHA return effect - }, []) - - useLayoutEffect(() => { - return () => { - const depthEffect = effect as any - depthEffect.blurPass.renderTargetA.dispose() - depthEffect.blurPass.renderTargetB.dispose() - depthEffect.maskPass.dispose() - depthEffect.cocPass.dispose() - depthEffect.renderTarget.dispose() - depthEffect.renderTargetCoC.dispose() - depthEffect.renderTargetCoCBlurred.dispose() - depthEffect.renderTargetMasked.dispose() - depthEffect.renderTargetNear.dispose() - depthEffect.renderTargetFar.dispose() - } - }, []) - - useLayoutEffect(() => { - effect.mainScene = scene - effect.mainCamera = camera - invalidate() - }, [camera, scene]) - - useLayoutEffect(() => { - effect.bokehScale = props.bokehScale ?? 1.0 - effect.resolution.width = props.resolutionX ?? props.width ?? Resolution.AUTO_SIZE - effect.resolution.height = props.resolutionY ?? props.height ?? Resolution.AUTO_SIZE - effect.resolution.scale = props.resolutionScale ?? 1.0 - effect.blendMode.blendFunction = props.blendFunction ?? BlendFunction.NORMAL - invalidate() }, [ - props.blur, - props.width, - props.height, - props.blendFunction, - props.bokehScale, - props.resolutionScale, - props.resolutionX, - props.resolutionY, + camera, + blendFunction, + worldFocusDistance, + worldFocusRange, + focusDistance, + focusRange, + focalLength, + bokehScale, + resolutionScale, + resolutionX, + resolutionY, + width, + height, + target, + depthTexture, ]) - useLayoutEffect(() => { - effect.circleOfConfusionMaterial.focusDistance = props.focusDistance ?? 0.0 - effect.circleOfConfusionMaterial.focalLength = props.focalLength ?? 0.1 - effect.circleOfConfusionMaterial.focusRange = props.focusRange ?? 0.1 - invalidate() - }, [props.focusDistance, props.focusRange, props.focalLength]) - - useLayoutEffect(() => { - effect.circleOfConfusionMaterial.worldFocusDistance = props.worldFocusDistance ?? 0.0 - effect.circleOfConfusionMaterial.worldFocusRange = props.worldFocusRange ?? 0.1 - invalidate() - }, [props.worldFocusDistance, props.worldFocusRange]) - useLayoutEffect(() => { - if (target) { - const depthTarget = new Vector3() - if (typeof target === 'number') depthTarget.set(target, target, target) - //@ts-ignore - else if (target.isVector3) depthTarget.copy(target) - //@ts-ignore - else depthTarget.set(target[0], target[1], target[2]) - - effect.target = depthTarget - } else { - //@ts-ignore - effect.target = null + useEffect(() => { + return () => { + effect.dispose() } - if (depthTexture) effect.setDepthTexture(depthTexture.texture, depthTexture.packing as DepthPackingStrategies) - invalidate() - }, [target, depthTexture, effect]) - return + }, [effect]) + + return }) From 6f7a616b51b0b9d03b0e96afbb996c6d742ac7b7 Mon Sep 17 00:00:00 2001 From: Cody Bennett <23324155+CodyJasonBennett@users.noreply.github.com> Date: Wed, 23 Aug 2023 07:53:05 -0500 Subject: [PATCH 4/5] chore: note params --- src/effects/DepthOfField.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/effects/DepthOfField.tsx b/src/effects/DepthOfField.tsx index 8ff92959..985e25f2 100644 --- a/src/effects/DepthOfField.tsx +++ b/src/effects/DepthOfField.tsx @@ -52,7 +52,9 @@ export const DepthOfField = forwardRef(function DepthOfField( width, height, }) - if (target) effect.target = new Vector3(...(target as number[])) + // Creating a target enables autofocus, R3F will set via props + if (target) effect.target = new Vector3() + // Depth texture for depth picking with optional packing strategy if (depthTexture) effect.setDepthTexture(depthTexture.texture, depthTexture.packing as DepthPackingStrategies) // Temporary fix that restores DOF 6.21.3 behavior, everything since then lets shapes leak through the blur const maskMaterial = (effect as any).maskPass.getFullscreenMaterial() @@ -82,5 +84,5 @@ export const DepthOfField = forwardRef(function DepthOfField( } }, [effect]) - return + return }) From 3d33957a0ba23095a61c2edfe09f993e69be2f8e Mon Sep 17 00:00:00 2001 From: Cody Bennett <23324155+CodyJasonBennett@users.noreply.github.com> Date: Wed, 23 Aug 2023 07:54:35 -0500 Subject: [PATCH 5/5] perf: derive autofocus --- src/effects/DepthOfField.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/effects/DepthOfField.tsx b/src/effects/DepthOfField.tsx index 985e25f2..9a05ad37 100644 --- a/src/effects/DepthOfField.tsx +++ b/src/effects/DepthOfField.tsx @@ -37,6 +37,7 @@ export const DepthOfField = forwardRef(function DepthOfField( ref: Ref ) { const { camera } = useContext(EffectComposerContext) + const autoFocus = target != null const effect = useMemo(() => { const effect = new DepthOfFieldEffect(camera, { blendFunction, @@ -53,7 +54,7 @@ export const DepthOfField = forwardRef(function DepthOfField( height, }) // Creating a target enables autofocus, R3F will set via props - if (target) effect.target = new Vector3() + if (autoFocus) effect.target = new Vector3() // Depth texture for depth picking with optional packing strategy if (depthTexture) effect.setDepthTexture(depthTexture.texture, depthTexture.packing as DepthPackingStrategies) // Temporary fix that restores DOF 6.21.3 behavior, everything since then lets shapes leak through the blur @@ -74,7 +75,7 @@ export const DepthOfField = forwardRef(function DepthOfField( resolutionY, width, height, - target, + autoFocus, depthTexture, ])