22// From https://github.com/ektogamat/R3F-Ultimate-Lens-Flare
33
44import * as THREE from 'three'
5- import { useMemo , useEffect , forwardRef , useState , useContext } from 'react'
5+ import { useEffect , useState , useContext , useRef } from 'react'
66import { useFrame , useThree } from '@react-three/fiber'
77import { BlendFunction , Effect } from 'postprocessing'
88import { easing } from 'maath'
99
1010import { EffectComposerContext } from '../EffectComposer'
11+ import { wrapEffect } from '../util'
1112
1213const LensFlareShader = {
1314 fragmentShader : `
@@ -495,8 +496,6 @@ export class LensFlareEffect extends Effect {
495496 }
496497}
497498
498- type LensFlareApi = LensFlareEffect
499-
500499type LensFlareProps = {
501500 /** Position of the effect */
502501 position ?: THREE . Vector3
@@ -506,118 +505,117 @@ type LensFlareProps = {
506505 smoothTime ?: number
507506} & Partial < LensFlareEffectOptions >
508507
509- export const LensFlare = forwardRef < LensFlareApi , LensFlareProps > (
510- (
511- {
512- position = new THREE . Vector3 ( - 25 , 6 , - 60 ) ,
513- followMouse = false ,
514- smoothTime = 0.07 ,
515- //
516- blendFunction = BlendFunction . NORMAL ,
517- enabled = true ,
518- glareSize = 0.2 ,
519- lensPosition = new THREE . Vector2 ( 0.01 , 0.01 ) ,
520- screenRes = new THREE . Vector2 ( 0 , 0 ) ,
521- starPoints = 6 ,
522- flareSize = 0.01 ,
523- flareSpeed = 0.01 ,
524- flareShape = 0.01 ,
525- animated = true ,
526- anamorphic = false ,
527- colorGain = new THREE . Color ( 20 , 20 , 20 ) ,
528- lensDirtTexture = null ,
529- haloScale = 0.5 ,
530- secondaryGhosts = true ,
531- aditionalStreaks = true ,
532- ghostScale = 0.0 ,
533- opacity = 1.0 ,
534- starBurst = false ,
535- } ,
536- ref
537- ) => {
538- const viewport = useThree ( ( { viewport } ) => viewport )
539- const raycaster = useThree ( ( { raycaster } ) => raycaster )
540- const pointer = useThree ( ( { pointer } ) => pointer )
541- const { scene, camera } = useContext ( EffectComposerContext )
542-
543- const [ projectedPosition ] = useState ( ( ) => new THREE . Vector3 ( ) )
544- const [ mouse2d ] = useState ( ( ) => new THREE . Vector2 ( ) )
545-
546- const opts = {
547- blendFunction,
548- enabled,
549- glareSize,
550- lensPosition,
551- screenRes,
552- starPoints,
553- flareSize,
554- flareSpeed,
555- flareShape,
556- animated,
557- anamorphic,
558- colorGain,
559- lensDirtTexture,
560- haloScale,
561- secondaryGhosts,
562- aditionalStreaks,
563- ghostScale,
564- opacity,
565- starBurst,
566- }
567- // eslint-disable-next-line react-hooks/exhaustive-deps
568- const effect = useMemo ( ( ) => new LensFlareEffect ( opts ) , [ JSON . stringify ( opts ) ] )
569-
570- useFrame ( ( _ , delta ) => {
571- const uLensPosition = effect . uniforms . get ( 'lensPosition' )
572- const uOpacity = effect . uniforms . get ( 'opacity' )
573- if ( ! uLensPosition || ! uOpacity ) return
574-
575- let target = 1
576-
577- if ( followMouse ) {
578- uLensPosition . value . x = pointer . x
579- uLensPosition . value . y = pointer . y
580- target = 0
581- } else {
582- projectedPosition . copy ( position ) . project ( camera )
583- if ( projectedPosition . z > 1 ) return
584-
585- uLensPosition . value . x = projectedPosition . x
586- uLensPosition . value . y = projectedPosition . y
587-
588- mouse2d . set ( projectedPosition . x , projectedPosition . y )
589- raycaster . setFromCamera ( mouse2d , camera )
590- const intersects = raycaster . intersectObjects ( scene . children , true )
591- const { object } = intersects [ 0 ]
592- if ( object ) {
593- if ( object . userData ?. lensflare === 'no-occlusion' ) {
594- target = 0
595- } else if ( object instanceof THREE . Mesh ) {
596- if ( object . material . uniforms ?. _transmission ?. value > 0.2 ) {
597- //Check for MeshTransmissionMaterial
598- target = 0.2
599- } else if ( object . material . _transmission && object . material . _transmission > 0.2 ) {
600- //Check for MeshPhysicalMaterial with transmission setting
601- target = 0.2
602- } else if ( object . material . transparent ) {
603- // Check for OtherMaterials with transparent parameter
604- target = object . material . opacity
605- }
508+ const LensFlareWrapped = wrapEffect ( LensFlareEffect )
509+
510+ export const LensFlare = ( {
511+ position = new THREE . Vector3 ( - 25 , 6 , - 60 ) ,
512+ followMouse = false ,
513+ smoothTime = 0.07 ,
514+ //
515+ blendFunction = BlendFunction . NORMAL ,
516+ enabled = true ,
517+ glareSize = 0.2 ,
518+ lensPosition = new THREE . Vector2 ( 0.01 , 0.01 ) ,
519+ screenRes = new THREE . Vector2 ( 0 , 0 ) ,
520+ starPoints = 6 ,
521+ flareSize = 0.01 ,
522+ flareSpeed = 0.01 ,
523+ flareShape = 0.01 ,
524+ animated = true ,
525+ anamorphic = false ,
526+ colorGain = new THREE . Color ( 20 , 20 , 20 ) ,
527+ lensDirtTexture = null ,
528+ haloScale = 0.5 ,
529+ secondaryGhosts = true ,
530+ aditionalStreaks = true ,
531+ ghostScale = 0.0 ,
532+ opacity = 1.0 ,
533+ starBurst = false ,
534+ } : LensFlareProps ) => {
535+ const viewport = useThree ( ( { viewport } ) => viewport )
536+ const raycaster = useThree ( ( { raycaster } ) => raycaster )
537+ const pointer = useThree ( ( { pointer } ) => pointer )
538+ const { scene, camera } = useContext ( EffectComposerContext )
539+
540+ const [ projectedPosition ] = useState ( ( ) => new THREE . Vector3 ( ) )
541+ const [ mouse2d ] = useState ( ( ) => new THREE . Vector2 ( ) )
542+
543+ const ref = useRef < LensFlareEffect > ( null )
544+
545+ useFrame ( ( _ , delta ) => {
546+ if ( ! ref ?. current ) return
547+ const uLensPosition = ref . current . uniforms . get ( 'lensPosition' )
548+ const uOpacity = ref . current . uniforms . get ( 'opacity' )
549+ if ( ! uLensPosition || ! uOpacity ) return
550+
551+ let target = 1
552+
553+ if ( followMouse ) {
554+ uLensPosition . value . x = pointer . x
555+ uLensPosition . value . y = pointer . y
556+ target = 0
557+ } else {
558+ projectedPosition . copy ( position ) . project ( camera )
559+ if ( projectedPosition . z > 1 ) return
560+
561+ uLensPosition . value . x = projectedPosition . x
562+ uLensPosition . value . y = projectedPosition . y
563+
564+ mouse2d . set ( projectedPosition . x , projectedPosition . y )
565+ raycaster . setFromCamera ( mouse2d , camera )
566+ const intersects = raycaster . intersectObjects ( scene . children , true )
567+ const { object } = intersects [ 0 ]
568+ if ( object ) {
569+ if ( object . userData ?. lensflare === 'no-occlusion' ) {
570+ target = 0
571+ } else if ( object instanceof THREE . Mesh ) {
572+ if ( object . material . uniforms ?. _transmission ?. value > 0.2 ) {
573+ //Check for MeshTransmissionMaterial
574+ target = 0.2
575+ } else if ( object . material . _transmission && object . material . _transmission > 0.2 ) {
576+ //Check for MeshPhysicalMaterial with transmission setting
577+ target = 0.2
578+ } else if ( object . material . transparent ) {
579+ // Check for OtherMaterials with transparent parameter
580+ target = object . material . opacity
606581 }
607582 }
608583 }
584+ }
609585
610- easing . damp ( uOpacity , 'value' , target , smoothTime , delta )
611- } )
586+ easing . damp ( uOpacity , 'value' , target , smoothTime , delta )
587+ } )
612588
613- useEffect ( ( ) => {
614- const screenRes = effect . uniforms . get ( 'screenRes' )
615- if ( screenRes ) {
616- screenRes . value . x = viewport . width
617- screenRes . value . y = viewport . height
618- }
619- } , [ effect , viewport ] )
589+ useEffect ( ( ) => {
590+ if ( ! ref ?. current ) return
620591
621- return < primitive ref = { ref } object = { effect } dispose = { null } />
592+ const screenRes = ref . current . uniforms . get ( 'screenRes' )
593+ if ( screenRes ) {
594+ screenRes . value . x = viewport . width
595+ screenRes . value . y = viewport . height
596+ }
597+ } , [ viewport ] )
598+
599+ const opts = {
600+ blendFunction,
601+ enabled,
602+ glareSize,
603+ lensPosition,
604+ screenRes,
605+ starPoints,
606+ flareSize,
607+ flareSpeed,
608+ flareShape,
609+ animated,
610+ anamorphic,
611+ colorGain,
612+ lensDirtTexture,
613+ haloScale,
614+ secondaryGhosts,
615+ aditionalStreaks,
616+ ghostScale,
617+ opacity,
618+ starBurst,
622619 }
623- )
620+ return < LensFlareWrapped ref = { ref } { ...opts } />
621+ }
0 commit comments