diff --git a/.storybook/stories/LensFlare.stories.tsx b/.storybook/stories/LensFlare.stories.tsx
index f0ea6ce..da11f48 100644
--- a/.storybook/stories/LensFlare.stories.tsx
+++ b/.storybook/stories/LensFlare.stories.tsx
@@ -5,7 +5,7 @@ import { BackSide } from 'three'
import { Box, useTexture } from '@react-three/drei'
import { Setup } from '../Setup'
-import { EffectComposer, LensFlare, Vignette, Bloom } from '../../src'
+import { EffectComposer, LensFlare, Vignette, Bloom, BrightnessContrast } from '../../src'
function SkyBox() {
const texture = useTexture('digital_painting_golden_hour_sunset.jpg')
@@ -54,10 +54,12 @@ export const Primary: Story = {
+
+
>
),
- args: {},
+ args: { colorGain: new THREE.Color(56, 21, 9) },
}
function DirtLensFlare(props) {
@@ -79,8 +81,10 @@ export const Secondary: Story = {
+
+
>
),
- args: { starBurst: true },
+ args: { starBurst: true, colorGain: new THREE.Color(56, 21, 9) },
}
diff --git a/docs/effects/lensflare.mdx b/docs/effects/lensflare.mdx
index 3b38fbe..6af2dbf 100644
--- a/docs/effects/lensflare.mdx
+++ b/docs/effects/lensflare.mdx
@@ -10,48 +10,29 @@ Based on [ektogamat/R3F-Ultimate-Lens-Flare](https://github.com/ektogamat/R3F-Ul
```jsx
import { LensFlare } from '@react-three/postprocessing'
-return (
-
-)
+return
```
-#### Ignoring occlusion on some objects
+## Ignoring occlusion on some objects
To disable the occlusion effect, simply add `userData={{ lensflare: 'no-occlusion' }}` to your object/mesh props.
-#### Improving performance
+## Improving performance
Use bvh `` to enhance the internal raycaster performance.
-#### Limitations
+## Limitations
The Ultimate Lens Flare leverages the raycaster to examine the material type of objects and determine if they are `MeshTransmissionMaterial` or `MeshPhysicalMaterial`. It checks for the transmission parameter to identify glass-like materials. Therefore, for an object to behave like glass, its material should have either `transmission = 1` or `transparent = true` and `opacity = NUMBER`. The effect automatically interprets the opacity `NUMBER` value to determine the brightness of the flare.
-#### Credits
+## Credits
- https://www.shadertoy.com/view/4sK3W3
- https://www.shadertoy.com/view/4sX3Rs
- https://www.shadertoy.com/view/dllSRX
- https://www.shadertoy.com/view/Xlc3D2
- https://www.shadertoy.com/view/XtKfRV
+
+## Example
+
+
diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx
index ee5bac6..d41ca39 100644
--- a/src/effects/LensFlare.tsx
+++ b/src/effects/LensFlare.tsx
@@ -1,93 +1,474 @@
// Created by Anderson Mancini 2023
-// React Three Fiber Ultimate LensFlare
-// To be used Effect together with react-three/postprocessing
+// From https://github.com/ektogamat/R3F-Ultimate-Lens-Flare
import * as THREE from 'three'
-import { useMemo, useEffect, forwardRef, useState, useContext } from 'react'
+import { useEffect, useState, useContext, useRef } from 'react'
import { useFrame, useThree } from '@react-three/fiber'
import { BlendFunction, Effect } from 'postprocessing'
import { easing } from 'maath'
import { EffectComposerContext } from '../EffectComposer'
+import { wrapEffect } from '../util'
const LensFlareShader = {
fragmentShader: /* glsl */ `
+ uniform float time;
+ uniform vec2 lensPosition;
+ uniform vec2 screenRes;
+ uniform vec3 colorGain;
+ uniform float starPoints;
+ uniform float glareSize;
+ uniform float flareSize;
+ uniform float flareSpeed;
+ uniform float flareShape;
+ uniform float haloScale;
+ uniform float opacity;
+ uniform bool animated;
+ uniform bool anamorphic;
+ uniform bool enabled;
+ uniform bool secondaryGhosts;
+ uniform bool starBurst;
+ uniform float ghostScale;
+ uniform bool aditionalStreaks;
+ uniform sampler2D lensDirtTexture;
+ vec2 vTexCoord;
+
+ float rand(float n){return fract(sin(n) * 43758.5453123);}
- uniform float iTime;
- uniform vec2 lensPosition;
- uniform vec2 iResolution;
- uniform vec3 colorGain;
- uniform float starPoints;
- uniform float glareSize;
- uniform float flareSize;
- uniform float flareSpeed;
- uniform float flareShape;
- uniform float haloScale;
- uniform float opacity;
- uniform bool animated;
- uniform bool anamorphic;
- uniform bool enabled;
- uniform bool secondaryGhosts;
- uniform bool starBurst;
- uniform float ghostScale;
- uniform bool aditionalStreaks;
- uniform sampler2D lensDirtTexture;
- vec2 vxtC;
-
- float rndf(float n){return fract(sin(n) * 43758.5453123);}float niz(float p){float fl = floor(p);float fc = fract(p);return mix(rndf(fl),rndf(fl + 1.0), fc);}
- vec3 hsv2rgb(vec3 c){vec4 k = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);vec3 p = abs(fract(c.xxx + k.xyz) * 6.0 - k.www);return c.z * mix(k.xxx, clamp(p - k.xxx, 0.0, 1.0), c.y);}
- float satU(float x){return clamp(x, 0.,1.);}vec2 rtU(vec2 naz, float rtn){return vec2(cos(rtn) * naz.x + sin(rtn) * naz.y,cos(rtn) * naz.y - sin(rtn) * naz.x);}
- vec3 drwF(vec2 p, float intensity, float rnd, float speed, int id){float flhos = (1. / 32.) * float(id) * 0.1;float lingrad = distance(vec2(0.), p);float expg = 1. / exp(lingrad * (fract(rnd) * 0.66 + 0.33));vec3 qzTg = hsv2rgb(vec3( fract( (expg * 8.) + speed * flareSpeed + flhos), pow(1.-abs(expg*2.-1.), 0.45), 20.0 * expg * intensity));float internalStarPoints;if(anamorphic){internalStarPoints = 1.0;} else{internalStarPoints = starPoints;}float ams = length(p * flareShape * sin(internalStarPoints * atan(p.x, p.y)));float kJhg = pow(1.-satU(ams), ( anamorphic ? 100. : 12.));kJhg += satU(expg-0.9) * 3.;kJhg = pow(kJhg * expg, 8. + (1.-intensity) * 5.);if(flareSpeed > 0.0){return vec3(kJhg) * qzTg;} else{return vec3(kJhg) * flareSize * 15.;}}
- float ams2(vec3 a, vec3 b) { return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);}vec3 satU(vec3 x){return clamp(x, vec3(0.0), vec3(1.0));}
- float glR(vec2 naz, vec2 pos, float zsi){vec2 mni;if(animated){mni = rtU(naz-pos, iTime * 0.1);} else{mni = naz-pos;}float ang = atan(mni.y, mni.x) * (anamorphic ? 1.0 : starPoints);float ams2 = length(mni);ams2 = pow(ams2, .9);float f0 = 1.0/(length(naz-pos)*(1.0/zsi*16.0)+.2);return f0+f0*(sin((ang))*.2 +.3);}
- float sdHex(vec2 p){p = abs(p);vec2 q = vec2(p.x*2.0*0.5773503, p.y + p.x*0.5773503);return dot(step(q.xy,q.yx), 1.0-q.yx);}float fpow(float x, float k){return x > k ? pow((x-k)/(1.0-k),2.0) : 0.0;}
- vec3 rHx(vec2 naz, vec2 p, float s, vec3 col){naz -= p;if (abs(naz.x) < 0.2*s && abs(naz.y) < 0.2*s){return mix(vec3(0),mix(vec3(0),col,0.1 + fpow(length(naz/s),0.1)*10.0),smoothstep(0.0,0.1,sdHex(naz*20.0/s)));}return vec3(0);}
- vec3 mLs(vec2 naz, vec2 pos){vec2 mni = naz-pos;vec2 zxMp = naz*(length(naz));float ang = atan(mni.x,mni.y);float f0 = .3/(length(naz-pos)*16.0+1.0);f0 = f0*(sin(niz(sin(ang*3.9-(animated ? iTime : 0.0) * 0.3) * starPoints))*.2 );float f1 = max(0.01-pow(length(naz+1.2*pos),1.9),.0)*7.0;float f2 = max(.9/(10.0+32.0*pow(length(zxMp+0.99*pos),2.0)),.0)*0.35;float f22 = max(.9/(11.0+32.0*pow(length(zxMp+0.85*pos),2.0)),.0)*0.23;float f23 = max(.9/(12.0+32.0*pow(length(zxMp+0.95*pos),2.0)),.0)*0.6;vec2 ztX = mix(naz,zxMp, 0.1);float f4 = max(0.01-pow(length(ztX+0.4*pos),2.9),.0)*4.02;float f42 = max(0.0-pow(length(ztX+0.45*pos),2.9),.0)*4.1;float f43 = max(0.01-pow(length(ztX+0.5*pos),2.9),.0)*4.6;ztX = mix(naz,zxMp,-.4);float f5 = max(0.01-pow(length(ztX+0.1*pos),5.5),.0)*2.0;float f52 = max(0.01-pow(length(ztX+0.2*pos),5.5),.0)*2.0;float f53 = max(0.01-pow(length(ztX+0.1*pos),5.5),.0)*2.0;ztX = mix(naz,zxMp, 2.1);float f6 = max(0.01-pow(length(ztX-0.3*pos),1.61),.0)*3.159;float f62 = max(0.01-pow(length(ztX-0.325*pos),1.614),.0)*3.14;float f63 = max(0.01-pow(length(ztX-0.389*pos),1.623),.0)*3.12;vec3 c = vec3(glR(naz,pos, glareSize));vec2 prot;if(animated){prot = rtU(naz - pos, (iTime * 0.1));} else if(anamorphic){prot = rtU(naz - pos, 1.570796);} else {prot = naz - pos;}c += drwF(prot, (anamorphic ? flareSize * 10. : flareSize), 0.1, iTime, 1);c.r+=f1+f2+f4+f5+f6; c.g+=f1+f22+f42+f52+f62; c.b+=f1+f23+f43+f53+f63;c = c*1.3 * vec3(length(zxMp)+.09);c+=vec3(f0);return c;}
- vec3 cc(vec3 clr, float fct,float fct2){float w = clr.x+clr.y+clr.z;return mix(clr,vec3(w)*fct,w*fct2);}float rnd(vec2 p){float f = fract(sin(dot(p, vec2(12.1234, 72.8392) )*45123.2));return f;}float rnd(float w){float f = fract(sin(w)*1000.);return f;}
- float rShp(vec2 p, int N){float f;float a=atan(p.x,p.y)+.2;float b=6.28319/float(N);f=smoothstep(.5,.51, cos(floor(.5+a/b)*b-a)*length(p.xy)* 2.0 -ghostScale);return f;}
- vec3 drC(vec2 p, float zsi, float dCy, vec3 clr, vec3 clr2, float ams2, vec2 esom){float l = length(p + esom*(ams2*2.))+zsi/2.;float l2 = length(p + esom*(ams2*4.))+zsi/3.;float c = max(0.01-pow(length(p + esom*ams2), zsi*ghostScale), 0.0)*10.;float c1 = max(0.001-pow(l-0.3, 1./40.)+sin(l*20.), 0.0)*3.;float c2 = max(0.09/pow(length(p-esom*ams2/.5)*1., .95), 0.0)/20.;float s = max(0.02-pow(rShp(p*5. + esom*ams2*5. + dCy, 6) , 1.), 0.0)*1.5;clr = cos(vec3(0.44, .24, .2)*8. + ams2*4.)*0.5+.5;vec3 f = c*clr;f += c1*clr;f += c2*clr;f += s*clr;return f-0.01;}
- vec4 geLC(float x){return vec4(vec3(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(vec3(0., 0., 0.),vec3(0., 0., 0.), smoothstep(0.0, 0.063, x)),vec3(0., 0., 0.), smoothstep(0.063, 0.125, x)),vec3(0.0, 0., 0.), smoothstep(0.125, 0.188, x)),vec3(0.188, 0.131, 0.116), smoothstep(0.188, 0.227, x)),vec3(0.31, 0.204, 0.537), smoothstep(0.227, 0.251, x)),vec3(0.192, 0.106, 0.286), smoothstep(0.251, 0.314, x)),vec3(0.102, 0.008, 0.341), smoothstep(0.314, 0.392, x)),vec3(0.086, 0.0, 0.141), smoothstep(0.392, 0.502, x)),vec3(1.0, 0.31, 0.0), smoothstep(0.502, 0.604, x)),vec3(.1, 0.1, 0.1), smoothstep(0.604, 0.643, x)),vec3(1.0, 0.929, 0.0), smoothstep(0.643, 0.761, x)),vec3(1.0, 0.086, 0.424), smoothstep(0.761, 0.847, x)),vec3(1.0, 0.49, 0.0), smoothstep(0.847, 0.89, x)),vec3(0.945, 0.275, 0.475), smoothstep(0.89, 0.941, x)),vec3(0.251, 0.275, 0.796), smoothstep(0.941, 1.0, x))),1.0);}
- float diTN(vec2 p){vec2 f = fract(p);f = (f * f) * (3.0 - (2.0 * f));float n = dot(floor(p), vec2(1.0, 157.0));vec4 a = fract(sin(vec4(n + 0.0, n + 1.0, n + 157.0, n + 158.0)) * 43758.5453123);return mix(mix(a.x, a.y, f.x), mix(a.z, a.w, f.x), f.y);}
- float fbm(vec2 p){const mat2 m = mat2(0.80, -0.60, 0.60, 0.80);float f = 0.0;f += 0.5000*diTN(p); p = m*p*2.02;f += 0.2500*diTN(p); p = m*p*2.03;f += 0.1250*diTN(p); p = m*p*2.01;f += 0.0625*diTN(p);return f/0.9375;}
- vec4 geLS(vec2 p){vec2 pp = (p - vec2(0.5)) * 2.0;float a = atan(pp.y, pp.x);vec4 cp = vec4(sin(a * 1.0), length(pp), sin(a * 13.0), sin(a * 53.0));float d = sin(clamp(pow(length(vec2(0.5) - p) * 0.5 + haloScale /2., 5.0), 0.0, 1.0) * 3.14159);vec3 c = vec3(d) * vec3(fbm(cp.xy * 16.0) * fbm(cp.zw * 9.0) * max(max(max(max(0.5, sin(a * 1.0)), sin(a * 3.0) * 0.8), sin(a * 7.0) * 0.8), sin(a * 9.0) * 10.6));c *= vec3(mix(2.0, (sin(length(pp.xy) * 256.0) * 0.5) + 0.5, sin((clamp((length(pp.xy) - 0.875) / 0.1, 0.0, 1.0) + 0.0) * 2.0 * 3.14159) * 1.5) + 0.5) * 0.3275;return vec4(vec3(c * 1.0), d);}
- vec4 geLD(vec2 p){p.xy += vec2(fbm(p.yx * 3.0), fbm(p.yx * 2.0)) * 0.0825;vec3 o = vec3(mix(0.125, 0.25, max(max(smoothstep(0.1, 0.0, length(p - vec2(0.25))),smoothstep(0.4, 0.0, length(p - vec2(0.75)))),smoothstep(0.8, 0.0, length(p - vec2(0.875, 0.125))))));o += vec3(max(fbm(p * 1.0) - 0.5, 0.0)) * 0.5;o += vec3(max(fbm(p * 2.0) - 0.5, 0.0)) * 0.5;o += vec3(max(fbm(p * 4.0) - 0.5, 0.0)) * 0.25;o += vec3(max(fbm(p * 8.0) - 0.75, 0.0)) * 1.0;o += vec3(max(fbm(p * 16.0) - 0.75, 0.0)) * 0.75;o += vec3(max(fbm(p * 64.0) - 0.75, 0.0)) * 0.5;return vec4(clamp(o, vec3(0.15), vec3(1.0)), 1.0);}
- vec4 txL(sampler2D tex, vec2 xtC){if(((xtC.x < 0.) || (xtC.y < 0.)) || ((xtC.x > 1.) || (xtC.y > 1.))){return vec4(0.0);}else{return texture(tex, xtC); }}
- vec4 txD(sampler2D tex, vec2 xtC, vec2 dir, vec3 ditn) {return vec4(txL(tex, (xtC + (dir * ditn.r))).r,txL(tex, (xtC + (dir * ditn.g))).g,txL(tex, (xtC + (dir * ditn.b))).b,1.0);}
- vec4 strB(){vec2 aspXtc = vec2(1.0) - (((vxtC - vec2(0.5)) * vec2(1.0)) + vec2(0.5)); vec2 xtC = vec2(1.0) - vxtC; vec2 ghvc = (vec2(0.5) - xtC) * 0.3 - lensPosition; vec2 ghNm = normalize(ghvc * vec2(1.0)) * vec2(1.0);vec2 haloVec = normalize(ghvc) * 0.6;vec2 hlNm = ghNm * 0.6;vec2 texelSize = vec2(1.0) / vec2(iResolution.xy);vec3 ditn = vec3(-(texelSize.x * 1.5), 0.2, texelSize.x * 1.5);vec4 c = vec4(0.0);for (int i = 0; i < 8; i++) {vec2 offset = xtC + (ghvc * float(i));c += txD(lensDirtTexture, offset, ghNm, ditn) * pow(max(0.0, 1.0 - (length(vec2(0.5) - offset) / length(vec2(0.5)))), 10.0);}vec2 uyTrz = xtC + hlNm; return (c * geLC((length(vec2(0.5) - aspXtc) / length(vec2(haloScale))))) +(txD(lensDirtTexture, uyTrz, ghNm, ditn) * pow(max(0.0, 1.0 - (length(vec2(0.5) - uyTrz) / length(vec2(0.5)))), 10.0));}
- void mainImage(vec4 v,vec2 r,out vec4 i){vec2 g=r-.5;g.y*=iResolution.y/iResolution.x;vec2 l=lensPosition*.5;l.y*=iResolution.y/iResolution.x;vec3 f=mLs(g,l)*20.*colorGain/256.;if(aditionalStreaks){vec3 o=vec3(.9,.2,.1),p=vec3(.3,.1,.9);for(float n=0.;n<10.;n++)f+=drC(g,pow(rnd(n*2e3)*2.8,.1)+1.41,0.,o+n,p+n,rnd(n*20.)*3.+.2-.5,lensPosition);}if(secondaryGhosts){vec3 n=vec3(0);n+=rHx(g,-lensPosition*.25,ghostScale*1.4,vec3(.25,.35,0));n+=rHx(g,lensPosition*.25,ghostScale*.5,vec3(1,.5,.5));n+=rHx(g,lensPosition*.1,ghostScale*1.6,vec3(1));n+=rHx(g,lensPosition*1.8,ghostScale*2.,vec3(0,.5,.75));n+=rHx(g,lensPosition*1.25,ghostScale*.8,vec3(1,1,.5));n+=rHx(g,-lensPosition*1.25,ghostScale*5.,vec3(.5,.5,.25));n+=fpow(1.-abs(distance(lensPosition*.8,g)-.7),.985)*colorGain/2100.;f+=n;}if(starBurst){vxtC=g+.5;vec4 n=geLD(g);float o=1.-clamp(0.5,0.,.5)*2.;n+=mix(n,pow(n*2.,vec4(2))*.5,o);float s=(g.x+g.y)*(1./6.);vec2 d=mat2(cos(s),-sin(s),sin(s),cos(s))*vxtC;n+=geLS(d)*2.;f+=clamp(n.xyz*strB().xyz,.01,1.);}i=enabled?vec4(mix(f,vec3(0),opacity)+v.xyz,v.w):vec4(v);}
-`,
+ float noise(float p){
+ float fl = floor(p);
+ float fc = fract(p);
+ return mix(rand(fl),rand(fl + 1.0), fc);
+ }
+
+ vec3 hsv2rgb(vec3 c)
+ {
+ vec4 k = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
+ vec3 p = abs(fract(c.xxx + k.xyz) * 6.0 - k.www);
+ return c.z * mix(k.xxx, clamp(p - k.xxx, 0.0, 1.0), c.y);
+ }
+
+ float saturate(float x)
+ {
+ return clamp(x, 0.,1.);
+ }
+
+ vec2 rotateUV(vec2 uv, float rotation)
+ {
+ return vec2(
+ cos(rotation) * uv.x + sin(rotation) * uv.y,
+ cos(rotation) * uv.y - sin(rotation) * uv.x
+ );
+ }
+
+ // Based on https://www.shadertoy.com/view/XtKfRV
+ vec3 drawflare(vec2 p, float intensity, float rnd, float speed, int id)
+ {
+ float flarehueoffset = (1. / 32.) * float(id) * 0.1;
+ float lingrad = distance(vec2(0.), p);
+ float expgrad = 1. / exp(lingrad * (fract(rnd) * 0.66 + 0.33));
+ vec3 colgrad = hsv2rgb(vec3( fract( (expgrad * 8.) + speed * flareSpeed + flarehueoffset), pow(1.-abs(expgrad*2.-1.), 0.45), 20.0 * expgrad * intensity)); //rainbow spectrum effect
+
+ float internalStarPoints;
+
+ if(anamorphic){
+ internalStarPoints = 1.0;
+ } else{
+ internalStarPoints = starPoints;
+ }
+
+ float blades = length(p * flareShape * sin(internalStarPoints * atan(p.x, p.y)));
+
+ float comp = pow(1.-saturate(blades), ( anamorphic ? 100. : 12.));
+ comp += saturate(expgrad-0.9) * 3.;
+ comp = pow(comp * expgrad, 8. + (1.-intensity) * 5.);
+
+ if(flareSpeed > 0.0){
+ return vec3(comp) * colgrad;
+ } else{
+ return vec3(comp) * flareSize * 15.;
+ }
+ }
+
+ float dist(vec3 a, vec3 b) { return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z); }
+
+ vec3 saturate(vec3 x)
+ {
+ return clamp(x, vec3(0.0), vec3(1.0));
+ }
+
+ // Based on https://www.shadertoy.com/view/XtKfRV
+ float glare(vec2 uv, vec2 pos, float size)
+ {
+ vec2 main;
+
+ if(animated){
+ main = rotateUV(uv-pos, time * 0.1);
+ } else{
+ main = uv-pos;
+ }
+
+ float ang = atan(main.y, main.x) * (anamorphic ? 1.0 : starPoints);
+ float dist = length(main);
+ dist = pow(dist, .9);
+
+ float f0 = 1.0/(length(uv-pos)*(1.0/size*16.0)+.2);
+
+ return f0+f0*(sin((ang))*.2 +.3);
+ }
+
+ float sdHex(vec2 p){
+ p = abs(p);
+ vec2 q = vec2(p.x*2.0*0.5773503, p.y + p.x*0.5773503);
+ return dot(step(q.xy,q.yx), 1.0-q.yx);
+ }
+
+ //Based on https://www.shadertoy.com/view/dllSRX
+ float fpow(float x, float k){
+ return x > k ? pow((x-k)/(1.0-k),2.0) : 0.0;
+ }
+
+ vec3 renderhex(vec2 uv, vec2 p, float s, vec3 col){
+ uv -= p;
+ if (abs(uv.x) < 0.2*s && abs(uv.y) < 0.2*s){
+ return mix(vec3(0),mix(vec3(0),col,0.1 + fpow(length(uv/s),0.1)*10.0),smoothstep(0.0,0.1,sdHex(uv*20.0/s)));
+ }
+ return vec3(0);
+ }
+
+ // Based on https://www.shadertoy.com/view/4sX3Rs
+ vec3 LensFlare(vec2 uv, vec2 pos)
+ {
+ vec2 main = uv-pos;
+ vec2 uvd = uv*(length(uv));
+
+ float ang = atan(main.x,main.y);
+
+ float f0 = .3/(length(uv-pos)*16.0+1.0);
+
+ f0 = f0*(sin(noise(sin(ang*3.9-(animated ? time : 0.0) * 0.3) * starPoints))*.2 );
+
+ float f1 = max(0.01-pow(length(uv+1.2*pos),1.9),.0)*7.0;
+
+ float f2 = max(.9/(10.0+32.0*pow(length(uvd+0.99*pos),2.0)),.0)*0.35;
+ float f22 = max(.9/(11.0+32.0*pow(length(uvd+0.85*pos),2.0)),.0)*0.23;
+ float f23 = max(.9/(12.0+32.0*pow(length(uvd+0.95*pos),2.0)),.0)*0.6;
+
+ vec2 uvx = mix(uv,uvd, 0.1);
+
+ float f4 = max(0.01-pow(length(uvx+0.4*pos),2.9),.0)*4.02;
+ float f42 = max(0.0-pow(length(uvx+0.45*pos),2.9),.0)*4.1;
+ float f43 = max(0.01-pow(length(uvx+0.5*pos),2.9),.0)*4.6;
+
+ uvx = mix(uv,uvd,-.4);
+
+ float f5 = max(0.01-pow(length(uvx+0.1*pos),5.5),.0)*2.0;
+ float f52 = max(0.01-pow(length(uvx+0.2*pos),5.5),.0)*2.0;
+ float f53 = max(0.01-pow(length(uvx+0.1*pos),5.5),.0)*2.0;
+
+ uvx = mix(uv,uvd, 2.1);
+
+ float f6 = max(0.01-pow(length(uvx-0.3*pos),1.61),.0)*3.159;
+ float f62 = max(0.01-pow(length(uvx-0.325*pos),1.614),.0)*3.14;
+ float f63 = max(0.01-pow(length(uvx-0.389*pos),1.623),.0)*3.12;
+
+ vec3 c = vec3(glare(uv,pos, glareSize));
+
+ vec2 prot;
+
+ if(animated){
+ prot = rotateUV(uv - pos, (time * 0.1));
+ } else if(anamorphic){
+ prot = rotateUV(uv - pos, 1.570796);
+ } else {
+ prot = uv - pos;
+ }
+
+ c += drawflare(prot, (anamorphic ? flareSize * 10. : flareSize), 0.1, time, 1);
+
+ c.r+=f1+f2+f4+f5+f6; c.g+=f1+f22+f42+f52+f62; c.b+=f1+f23+f43+f53+f63;
+ c = c*1.3 * vec3(length(uvd)+.09);
+ c+=vec3(f0);
+
+ return c;
+ }
+
+ vec3 cc(vec3 color, float factor,float factor2)
+ {
+ float w = color.x+color.y+color.z;
+ return mix(color,vec3(w)*factor,w*factor2);
+ }
+
+ float rnd(vec2 p)
+ {
+ float f = fract(sin(dot(p, vec2(12.1234, 72.8392) )*45123.2));
+ return f;
+ }
+
+ float rnd(float w)
+ {
+ float f = fract(sin(w)*1000.);
+ return f;
+ }
+
+ float regShape(vec2 p, int N)
+ {
+ float f;
+
+ float a=atan(p.x,p.y)+.2;
+ float b=6.28319/float(N);
+ f=smoothstep(.5,.51, cos(floor(.5+a/b)*b-a)*length(p.xy)* 2.0 -ghostScale);
+
+ return f;
+ }
+
+ // Based on https://www.shadertoy.com/view/Xlc3D2
+ vec3 circle(vec2 p, float size, float decay, vec3 color, vec3 color2, float dist, vec2 position)
+ {
+ float l = length(p + position*(dist*2.))+size/2.;
+ float l2 = length(p + position*(dist*4.))+size/3.;
+
+ float c = max(0.01-pow(length(p + position*dist), size*ghostScale), 0.0)*10.;
+ float c1 = max(0.001-pow(l-0.3, 1./40.)+sin(l*20.), 0.0)*3.;
+ float c2 = max(0.09/pow(length(p-position*dist/.5)*1., .95), 0.0)/20.;
+ float s = max(0.02-pow(regShape(p*5. + position*dist*5. + decay, 6) , 1.), 0.0)*1.5;
+
+ color = cos(vec3(0.44, .24, .2)*16. + dist/8.)*0.5+.5;
+ vec3 f = c*color;
+ f += c1*color;
+ f += c2*color;
+ f += s*color;
+ return f;
+ }
+
+ vec4 getLensColor(float x){
+ return vec4(vec3(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(mix(vec3(0., 0., 0.),
+ vec3(0., 0., 0.), smoothstep(0.0, 0.063, x)),
+ vec3(0., 0., 0.), smoothstep(0.063, 0.125, x)),
+ vec3(0.0, 0., 0.), smoothstep(0.125, 0.188, x)),
+ vec3(0.188, 0.131, 0.116), smoothstep(0.188, 0.227, x)),
+ vec3(0.31, 0.204, 0.537), smoothstep(0.227, 0.251, x)),
+ vec3(0.192, 0.106, 0.286), smoothstep(0.251, 0.314, x)),
+ vec3(0.102, 0.008, 0.341), smoothstep(0.314, 0.392, x)),
+ vec3(0.086, 0.0, 0.141), smoothstep(0.392, 0.502, x)),
+ vec3(1.0, 0.31, 0.0), smoothstep(0.502, 0.604, x)),
+ vec3(.1, 0.1, 0.1), smoothstep(0.604, 0.643, x)),
+ vec3(1.0, 0.929, 0.0), smoothstep(0.643, 0.761, x)),
+ vec3(1.0, 0.086, 0.424), smoothstep(0.761, 0.847, x)),
+ vec3(1.0, 0.49, 0.0), smoothstep(0.847, 0.89, x)),
+ vec3(0.945, 0.275, 0.475), smoothstep(0.89, 0.941, x)),
+ vec3(0.251, 0.275, 0.796), smoothstep(0.941, 1.0, x))),
+ 1.0);
+ }
+
+ float dirtNoise(vec2 p){
+ vec2 f = fract(p);
+ f = (f * f) * (3.0 - (2.0 * f));
+ float n = dot(floor(p), vec2(1.0, 157.0));
+ vec4 a = fract(sin(vec4(n + 0.0, n + 1.0, n + 157.0, n + 158.0)) * 43758.5453123);
+ return mix(mix(a.x, a.y, f.x), mix(a.z, a.w, f.x), f.y);
+ }
+
+ float fbm(vec2 p){
+ const mat2 m = mat2(0.80, -0.60, 0.60, 0.80);
+ float f = 0.0;
+ f += 0.5000*dirtNoise(p); p = m*p*2.02;
+ f += 0.2500*dirtNoise(p); p = m*p*2.03;
+ f += 0.1250*dirtNoise(p); p = m*p*2.01;
+ f += 0.0625*dirtNoise(p);
+ return f/0.9375;
+ }
+
+ vec4 getLensStar(vec2 p){
+ vec2 pp = (p - vec2(0.5)) * 2.0;
+ float a = atan(pp.y, pp.x);
+ vec4 cp = vec4(sin(a * 1.0), length(pp), sin(a * 13.0), sin(a * 53.0));
+ float d = sin(clamp(pow(length(vec2(0.5) - p) * 0.5 + haloScale /2., 5.0), 0.0, 1.0) * 3.14159);
+ vec3 c = vec3(d) * vec3(fbm(cp.xy * 16.0) * fbm(cp.zw * 9.0) * max(max(max(max(0.5, sin(a * 1.0)), sin(a * 3.0) * 0.8), sin(a * 7.0) * 0.8), sin(a * 9.0) * 10.6));
+ c *= vec3(mix(2.0, (sin(length(pp.xy) * 256.0) * 0.5) + 0.5, sin((clamp((length(pp.xy) - 0.875) / 0.1, 0.0, 1.0) + 0.0) * 2.0 * 3.14159) * 1.5) + 0.5) * 0.3275;
+ return vec4(vec3(c * 1.0), d);
+ }
+
+ vec4 getLensDirt(vec2 p){
+ p.xy += vec2(fbm(p.yx * 3.0), fbm(p.yx * 2.0)) * 0.0825;
+ vec3 o = vec3(mix(0.125, 0.25, max(max(smoothstep(0.1, 0.0, length(p - vec2(0.25))),
+ smoothstep(0.4, 0.0, length(p - vec2(0.75)))),
+ smoothstep(0.8, 0.0, length(p - vec2(0.875, 0.125))))));
+ o += vec3(max(fbm(p * 1.0) - 0.5, 0.0)) * 0.5;
+ o += vec3(max(fbm(p * 2.0) - 0.5, 0.0)) * 0.5;
+ o += vec3(max(fbm(p * 4.0) - 0.5, 0.0)) * 0.25;
+ o += vec3(max(fbm(p * 8.0) - 0.75, 0.0)) * 1.0;
+ o += vec3(max(fbm(p * 16.0) - 0.75, 0.0)) * 0.75;
+ o += vec3(max(fbm(p * 64.0) - 0.75, 0.0)) * 0.5;
+ return vec4(clamp(o, vec3(0.15), vec3(1.0)), 1.0);
+ }
+
+ vec4 textureLimited(sampler2D tex, vec2 texCoord){
+ if(((texCoord.x < 0.) || (texCoord.y < 0.)) || ((texCoord.x > 1.) || (texCoord.y > 1.))){
+ return vec4(0.0);
+ }else{
+ return texture(tex, texCoord);
+ }
+ }
+
+ vec4 textureDistorted(sampler2D tex, vec2 texCoord, vec2 direction, vec3 distortion) {
+ return vec4(textureLimited(tex, (texCoord + (direction * distortion.r))).r,
+ textureLimited(tex, (texCoord + (direction * distortion.g))).g,
+ textureLimited(tex, (texCoord + (direction * distortion.b))).b,
+ 1.0);
+ }
+
+ // Based on https://www.shadertoy.com/view/4sK3W3
+ vec4 getStartBurst(){
+ vec2 aspectTexCoord = vec2(1.0) - (((vTexCoord - vec2(0.5)) * vec2(1.0)) + vec2(0.5));
+ vec2 texCoord = vec2(1.0) - vTexCoord;
+ vec2 ghostVec = (vec2(0.5) - texCoord) * 0.3 - lensPosition;
+ vec2 ghostVecAspectNormalized = normalize(ghostVec * vec2(1.0)) * vec2(1.0);
+ vec2 haloVec = normalize(ghostVec) * 0.6;
+ vec2 haloVecAspectNormalized = ghostVecAspectNormalized * 0.6;
+ vec2 texelSize = vec2(1.0) / vec2(screenRes.xy);
+ vec3 distortion = vec3(-(texelSize.x * 1.5), 0.2, texelSize.x * 1.5);
+ vec4 c = vec4(0.0);
+ for (int i = 0; i < 8; i++) {
+ vec2 offset = texCoord + (ghostVec * float(i));
+ c += textureDistorted(lensDirtTexture, offset, ghostVecAspectNormalized, distortion) * pow(max(0.0, 1.0 - (length(vec2(0.5) - offset) / length(vec2(0.5)))), 10.0);
+ }
+ vec2 haloOffset = texCoord + haloVecAspectNormalized;
+ return (c * getLensColor((length(vec2(0.5) - aspectTexCoord) / length(vec2(haloScale))))) +
+ (textureDistorted(lensDirtTexture, haloOffset, ghostVecAspectNormalized, distortion) * pow(max(0.0, 1.0 - (length(vec2(0.5) - haloOffset) / length(vec2(0.5)))), 10.0));
+ }
+
+ void mainImage(vec4 inputColor, vec2 uv, out vec4 outputColor)
+ {
+ vec2 myUV = uv -0.5;
+ myUV.y *= screenRes.y/screenRes.x;
+ vec2 finalLensPosition = lensPosition * 0.5;
+ finalLensPosition.y *= screenRes.y/screenRes.x;
+
+ //First Lens flare pass
+ vec3 finalColor = LensFlare(myUV, finalLensPosition) * 20.0 * colorGain / 256.;
+
+ //Aditional streaks
+ if(aditionalStreaks){
+ vec3 circColor = vec3(0.9, 0.2, 0.1);
+ vec3 circColor2 = vec3(0.3, 0.1, 0.9);
+
+ for(float i=0.;i<10.;i++){
+ finalColor += circle(myUV, pow(rnd(i*2000.)*2.8, .1)+1.41, 0.0, circColor+i , circColor2+i, rnd(i*20.)*3.+0.2-.5, lensPosition);
+ }
+ }
+
+ //Alternative ghosts
+ if(secondaryGhosts){
+ vec3 altGhosts = vec3(0);
+ altGhosts += renderhex(myUV, -lensPosition*0.25, ghostScale * 1.4, vec3(0.25,0.35,0));
+ altGhosts += renderhex(myUV, lensPosition*0.25, ghostScale * 0.5, vec3(1,0.5,0.5));
+ altGhosts += renderhex(myUV, lensPosition*0.1, ghostScale * 1.6, vec3(1,1,1));
+ altGhosts += renderhex(myUV, lensPosition*1.8, ghostScale * 2.0, vec3(0,0.5,0.75));
+ altGhosts += renderhex(myUV, lensPosition*1.25, ghostScale * 0.8, vec3(1,1,0.5));
+ altGhosts += renderhex(myUV, -lensPosition*1.25, ghostScale * 5.0, vec3(0.5,0.5,0.25));
+
+ //Circular ghosts
+ altGhosts += fpow(1.0 - abs(distance(lensPosition*0.8,myUV) - 0.7),0.985)*colorGain / 2100.;
+ finalColor += altGhosts;
+ }
+
+
+ //Starburst
+ if(starBurst){
+ vTexCoord = myUV + 0.5;
+ vec4 lensMod = getLensDirt(myUV);
+ float tooBright = 1.0 - (clamp(0.5, 0.0, 0.5) * 2.0);
+ float tooDark = clamp(0.5 - 0.5, 0.0, 0.5) * 2.0;
+ lensMod += mix(lensMod, pow(lensMod * 2.0, vec4(2.0)) * 0.5, tooBright);
+ float lensStarRotationAngle = ((myUV.x + myUV.y)) * (1.0 / 6.0);
+ vec2 lensStarTexCoord = (mat2(cos(lensStarRotationAngle), -sin(lensStarRotationAngle), sin(lensStarRotationAngle), cos(lensStarRotationAngle)) * vTexCoord);
+ lensMod += getLensStar(lensStarTexCoord) * 2.;
+
+ finalColor += clamp((lensMod.rgb * getStartBurst().rgb ), 0.01, 1.0);
+ }
+
+ //Final composed output
+ if(enabled){
+ outputColor = vec4(mix(finalColor, vec3(.0), opacity) + inputColor.rgb, inputColor.a);
+ } else {
+ outputColor = vec4(inputColor);
+ }
+ }
+ `,
+}
+
+type LensFlareEffectOptions = {
+ /** The blend function of this effect */
+ blendFunction: BlendFunction
+ /** Boolean to enable/disable the effect */
+ enabled: boolean
+ /** The glare size */
+ glareSize: number
+ /** The position of the lens flare in 3d space */
+ lensPosition: THREE.Vector3
+ /** Effect resolution */
+ screenRes: THREE.Vector2
+ /** The number of points for the star */
+ starPoints: number
+ /** The flare side */
+ flareSize: number
+ /** The flare animation speed */
+ flareSpeed: number
+ /** Changes the appearance to anamorphic */
+ flareShape: number
+ /** Animated flare */
+ animated: boolean
+ /** Set the appearance to full anamorphic */
+ anamorphic: boolean
+ /** Set the color gain for the lens flare. Must be a THREE.Color in RBG format */
+ colorGain: THREE.Color
+ /** Texture to be used as color dirt for starburst effect */
+ lensDirtTexture: THREE.Texture | null
+ /** The halo scale */
+ haloScale: number
+ /** Option to enable/disable secondary ghosts */
+ secondaryGhosts: boolean
+ /** Option to enable/disable aditional streaks */
+ aditionalStreaks: boolean
+ /** Option to enable/disable secondary ghosts */
+ ghostScale: number
+ /** TODO The opacity for this effect */
+ opacity: number
+ /** Boolean to enable/disable the start burst effect. Can be disabled to improve performance */
+ starBurst: boolean
}
export class LensFlareEffect extends Effect {
constructor({
- blendFunction = BlendFunction.NORMAL,
- enabled = true,
- glareSize = 0.2,
- lensPosition = [0.01, 0.01],
- iResolution = [0, 0],
- starPoints = 6,
- flareSize = 0.01,
- flareSpeed = 0.01,
- flareShape = 0.01,
- animated = true,
- anamorphic = false,
- colorGain = new THREE.Color(20, 20, 20),
- lensDirtTexture = null as THREE.Texture | null,
- haloScale = 0.5,
- secondaryGhosts = true,
- aditionalStreaks = true,
- ghostScale = 0.0,
- opacity = 1.0,
- starBurst = false,
- } = {}) {
+ blendFunction,
+ enabled,
+ glareSize,
+ lensPosition,
+ screenRes,
+ starPoints,
+ flareSize,
+ flareSpeed,
+ flareShape,
+ animated,
+ anamorphic,
+ colorGain,
+ lensDirtTexture,
+ haloScale,
+ secondaryGhosts,
+ aditionalStreaks,
+ ghostScale,
+ opacity,
+ starBurst,
+ }: LensFlareEffectOptions) {
super('LensFlareEffect', LensFlareShader.fragmentShader, {
blendFunction,
uniforms: new Map([
['enabled', new THREE.Uniform(enabled)],
['glareSize', new THREE.Uniform(glareSize)],
['lensPosition', new THREE.Uniform(lensPosition)],
- ['iTime', new THREE.Uniform(0)],
- ['iResolution', new THREE.Uniform(iResolution)],
+ ['time', new THREE.Uniform(0)],
+ ['screenRes', new THREE.Uniform(screenRes)],
['starPoints', new THREE.Uniform(starPoints)],
['flareSize', new THREE.Uniform(flareSize)],
['flareSpeed', new THREE.Uniform(flareSpeed)],
@@ -107,82 +488,125 @@ export class LensFlareEffect extends Effect {
}
update(_renderer: any, _inputBuffer: any, deltaTime: number) {
- const iTime = this.uniforms.get('iTime')
- if (iTime) {
- iTime.value += deltaTime
+ const time = this.uniforms.get('time')
+ if (time) {
+ time.value += deltaTime
}
}
}
-type LensFlareProps = ConstructorParameters[0] & {
- position?: THREE.Vector3
- followMouse?: boolean
+type LensFlareProps = {
+ /** Position of the effect */
+ lensPosition?: THREE.Vector3
+ /** The time that it takes to fade the occlusion */
smoothTime?: number
-}
+} & Partial
-export const LensFlare = forwardRef(
- ({ position = new THREE.Vector3(-25, 6, -60), followMouse = false, smoothTime = 0.07, ...props }, ref) => {
- const viewport = useThree(({ viewport }) => viewport)
- const raycaster = useThree(({ raycaster }) => raycaster)
- const pointer = useThree(({ pointer }) => pointer)
- const { scene, camera } = useContext(EffectComposerContext)
+const LensFlareWrapped = /* @__PURE__ */ wrapEffect(LensFlareEffect)
- const [projectedPosition] = useState(() => new THREE.Vector3())
- const [mouse2d] = useState(() => new THREE.Vector2())
+export const LensFlare = ({
+ smoothTime = 0.07,
+ //
+ blendFunction = BlendFunction.NORMAL,
+ enabled = true,
+ glareSize = 0.2,
+ lensPosition = new THREE.Vector3(-25, 6, -60),
+ screenRes = new THREE.Vector2(0, 0),
+ starPoints = 6,
+ flareSize = 0.01,
+ flareSpeed = 0.01,
+ flareShape = 0.01,
+ animated = true,
+ anamorphic = false,
+ colorGain = new THREE.Color(20, 20, 20),
+ lensDirtTexture = null,
+ haloScale = 0.5,
+ secondaryGhosts = true,
+ aditionalStreaks = true,
+ ghostScale = 0.0,
+ opacity = 1.0,
+ starBurst = false,
+}: LensFlareProps) => {
+ const viewport = useThree(({ viewport }) => viewport)
+ const raycaster = useThree(({ raycaster }) => raycaster)
+ const { scene, camera } = useContext(EffectComposerContext)
+ const [raycasterPos] = useState(() => new THREE.Vector2())
+ const [projectedPosition] = useState(() => new THREE.Vector3())
- const effect = useMemo(() => new LensFlareEffect(props), [props])
+ const ref = useRef(null)
- useFrame((_, delta) => {
- const uLensPosition = effect.uniforms.get('lensPosition')
- const uOpacity = effect.uniforms.get('opacity')
- if (!uLensPosition || !uOpacity) return
+ useFrame((_, delta) => {
+ if (!ref?.current) return
+ const uLensPosition = ref.current.uniforms.get('lensPosition')
+ const uOpacity = ref.current.uniforms.get('opacity')
+ if (!uLensPosition || !uOpacity) return
- let target = 1
+ let target = 1
- if (followMouse) {
- uLensPosition.value.x = pointer.x
- uLensPosition.value.y = pointer.y
+ projectedPosition.copy(lensPosition).project(camera)
+ if (projectedPosition.z > 1) return
+
+ uLensPosition.value.x = projectedPosition.x
+ uLensPosition.value.y = projectedPosition.y
+ raycasterPos.x = projectedPosition.x
+ raycasterPos.y = projectedPosition.y
+ raycaster.setFromCamera(raycasterPos, camera)
+
+ const intersects = raycaster.intersectObjects(scene.children, true)
+ const { object } = intersects[0] || {}
+ if (object) {
+ if (object.userData?.lensflare === 'no-occlusion') {
target = 0
- } else {
- projectedPosition.copy(position).project(camera)
- if (projectedPosition.z > 1) return
-
- uLensPosition.value.x = projectedPosition.x
- uLensPosition.value.y = projectedPosition.y
-
- mouse2d.set(projectedPosition.x, projectedPosition.y)
- raycaster.setFromCamera(mouse2d, camera)
- const intersects = raycaster.intersectObjects(scene.children, true)
- const { object } = intersects[0]
- if (object) {
- if (object.userData?.lensflare === 'no-occlusion') {
- target = 0
- } else if (object instanceof THREE.Mesh) {
- if (object.material.uniforms?._transmission?.value > 0.2) {
- //Check for MeshTransmissionMaterial
- target = 0.2
- } else if (object.material._transmission && object.material._transmission > 0.2) {
- //Check for MeshPhysicalMaterial with transmission setting
- target = 0.2
- } else if (object.material.transparent) {
- // Check for OtherMaterials with transparent parameter
- target = object.material.opacity
- }
- }
+ } else if (object instanceof THREE.Mesh) {
+ if (object.material.uniforms?._transmission?.value > 0.2) {
+ //Check for MeshTransmissionMaterial
+ target = 0.2
+ } else if (object.material._transmission && object.material._transmission > 0.2) {
+ //Check for MeshPhysicalMaterial with transmission setting
+ target = 0.2
+ } else if (object.material.transparent) {
+ // Check for OtherMaterials with transparent parameter
+ target = object.material.opacity
}
}
+ }
- easing.damp(uOpacity, 'value', target, smoothTime, delta)
- })
+ easing.damp(uOpacity, 'value', target, smoothTime, delta)
+ })
- useEffect(() => {
- const iResolution = effect.uniforms.get('iResolution')
- if (iResolution) {
- iResolution.value.x = viewport.width
- iResolution.value.y = viewport.height
- }
- }, [effect, viewport])
+ useEffect(() => {
+ if (!ref?.current) return
- return
- }
-)
+ const screenRes = ref.current.uniforms.get('screenRes')
+ if (screenRes) {
+ screenRes.value.x = viewport.width
+ screenRes.value.y = viewport.height
+ }
+ }, [viewport])
+
+ return (
+
+ )
+}