From 389a0d73ff434366e0228f686af2dd033faf7208 Mon Sep 17 00:00:00 2001 From: Anderson Mancini Date: Wed, 19 Jul 2023 09:42:15 -0300 Subject: [PATCH 01/10] Fix color issue when using aditional streaks --- .storybook/stories/LensFlare.stories.tsx | 6 ++++-- src/effects/LensFlare.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.storybook/stories/LensFlare.stories.tsx b/.storybook/stories/LensFlare.stories.tsx index f0ea6ce..2f2d589 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) { diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index ee5bac6..68bb622 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -45,7 +45,7 @@ const LensFlareShader = { 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;} + 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)*16. + ams2/8.)*0.5+.5;vec3 f = c*clr;f += c1*clr;f += c2*clr;f += s*clr;return f;} 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;} From 5c0ffcbdb12356ec58415421db84cd6e033d327a Mon Sep 17 00:00:00 2001 From: Anderson Mancini Date: Wed, 19 Jul 2023 17:14:57 -0300 Subject: [PATCH 02/10] Unminified version of Lens Flare Shader Also adding some changes to the secondary story. --- .storybook/stories/LensFlare.stories.tsx | 4 +- src/effects/LensFlare.tsx | 416 ++++++++++++++++++++--- 2 files changed, 381 insertions(+), 39 deletions(-) diff --git a/.storybook/stories/LensFlare.stories.tsx b/.storybook/stories/LensFlare.stories.tsx index 2f2d589..da11f48 100644 --- a/.storybook/stories/LensFlare.stories.tsx +++ b/.storybook/stories/LensFlare.stories.tsx @@ -81,8 +81,10 @@ export const Secondary: Story = { + + ), - args: { starBurst: true }, + args: { starBurst: true, colorGain: new THREE.Color(56, 21, 9) }, } diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index 68bb622..2b0ea19 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -1,6 +1,5 @@ // 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' @@ -11,11 +10,11 @@ import { easing } from 'maath' import { EffectComposerContext } from '../EffectComposer' const LensFlareShader = { - fragmentShader: /* glsl */ ` + fragmentShader: ` - uniform float iTime; + uniform float time; uniform vec2 lensPosition; - uniform vec2 iResolution; + uniform vec2 screenRes; uniform vec3 colorGain; uniform float starPoints; uniform float glareSize; @@ -32,29 +31,370 @@ const LensFlareShader = { 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)*16. + ams2/8.)*0.5+.5;vec3 f = c*clr;f += c1*clr;f += c2*clr;f += s*clr;return f;} - 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);} + vec2 vTexCoord; + + float rand(float n){return fract(sin(n) * 43758.5453123);} + + 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); + } + } `, } @@ -64,7 +404,7 @@ export class LensFlareEffect extends Effect { enabled = true, glareSize = 0.2, lensPosition = [0.01, 0.01], - iResolution = [0, 0], + screenRes = [0, 0], starPoints = 6, flareSize = 0.01, flareSpeed = 0.01, @@ -86,8 +426,8 @@ export class LensFlareEffect extends Effect { ['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,9 +447,9 @@ 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 } } } @@ -176,10 +516,10 @@ export const LensFlare = forwardRef( }) useEffect(() => { - const iResolution = effect.uniforms.get('iResolution') - if (iResolution) { - iResolution.value.x = viewport.width - iResolution.value.y = viewport.height + const screenRes = effect.uniforms.get('screenRes') + if (screenRes) { + screenRes.value.x = viewport.width + screenRes.value.y = viewport.height } }, [effect, viewport]) From 51fbf4eb6adabf9a357a9c037063f24600a5d791 Mon Sep 17 00:00:00 2001 From: Antoine BERNIER Date: Thu, 20 Jul 2023 15:54:02 +0200 Subject: [PATCH 03/10] fix: JSDoc sb comments and default values --- docs/effects/lensflare.mdx | 25 +------ src/effects/LensFlare.tsx | 147 ++++++++++++++++++++++++++++++------- 2 files changed, 122 insertions(+), 50 deletions(-) diff --git a/docs/effects/lensflare.mdx b/docs/effects/lensflare.mdx index 3b38fbe..c4cefa6 100644 --- a/docs/effects/lensflare.mdx +++ b/docs/effects/lensflare.mdx @@ -10,30 +10,7 @@ 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 diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index 2b0ea19..7ae9757 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -398,28 +398,69 @@ const LensFlareShader = { `, } +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.Vector2 + /** 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], - screenRes = [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([ @@ -454,14 +495,46 @@ export class LensFlareEffect extends Effect { } } -type LensFlareProps = ConstructorParameters[0] & { +type LensFlareApi = LensFlareEffect + +type LensFlareProps = { + /** Position of the effect */ position?: THREE.Vector3 + /** Set it to follow the mouse, ignoring the lens position */ followMouse?: boolean + /** The time that it takes to fade the occlusion */ smoothTime?: number -} - -export const LensFlare = forwardRef( - ({ position = new THREE.Vector3(-25, 6, -60), followMouse = false, smoothTime = 0.07, ...props }, ref) => { +} & Partial + +export const LensFlare = forwardRef( + ( + { + position = new THREE.Vector3(-25, 6, -60), + followMouse = false, + smoothTime = 0.07, + // + blendFunction = BlendFunction.NORMAL, + enabled = true, + glareSize = 0.2, + lensPosition = new THREE.Vector2(0.01, 0.01), + 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, + }, + ref + ) => { const viewport = useThree(({ viewport }) => viewport) const raycaster = useThree(({ raycaster }) => raycaster) const pointer = useThree(({ pointer }) => pointer) @@ -470,7 +543,29 @@ export const LensFlare = forwardRef( const [projectedPosition] = useState(() => new THREE.Vector3()) const [mouse2d] = useState(() => new THREE.Vector2()) - const effect = useMemo(() => new LensFlareEffect(props), [props]) + const opts = { + blendFunction, + enabled, + glareSize, + lensPosition, + screenRes, + starPoints, + flareSize, + flareSpeed, + flareShape, + animated, + anamorphic, + colorGain, + lensDirtTexture, + haloScale, + secondaryGhosts, + aditionalStreaks, + ghostScale, + opacity, + starBurst, + } + // eslint-disable-next-line react-hooks/exhaustive-deps + const effect = useMemo(() => new LensFlareEffect(opts), [JSON.stringify(opts)]) useFrame((_, delta) => { const uLensPosition = effect.uniforms.get('lensPosition') From b8489a31c2020b8d327ede92ec48c49a5f913fda Mon Sep 17 00:00:00 2001 From: Antoine BERNIER Date: Thu, 20 Jul 2023 18:33:09 +0200 Subject: [PATCH 04/10] docs: csb ex --- docs/effects/lensflare.mdx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/effects/lensflare.mdx b/docs/effects/lensflare.mdx index c4cefa6..6af2dbf 100644 --- a/docs/effects/lensflare.mdx +++ b/docs/effects/lensflare.mdx @@ -13,22 +13,26 @@ import { LensFlare } from '@react-three/postprocessing' 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 + + From 1cb5ea784eaeba92ca136bfdfda2267d0d73ecae Mon Sep 17 00:00:00 2001 From: Antoine BERNIER Date: Fri, 21 Jul 2023 11:00:39 +0200 Subject: [PATCH 05/10] chore: using wrapEffect --- src/effects/LensFlare.tsx | 220 +++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 111 deletions(-) diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index 7ae9757..3e6dd9e 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -2,12 +2,13 @@ // 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: ` @@ -495,8 +496,6 @@ export class LensFlareEffect extends Effect { } } -type LensFlareApi = LensFlareEffect - type LensFlareProps = { /** Position of the effect */ position?: THREE.Vector3 @@ -506,118 +505,117 @@ type LensFlareProps = { smoothTime?: number } & Partial -export const LensFlare = forwardRef( - ( - { - position = new THREE.Vector3(-25, 6, -60), - followMouse = false, - smoothTime = 0.07, - // - blendFunction = BlendFunction.NORMAL, - enabled = true, - glareSize = 0.2, - lensPosition = new THREE.Vector2(0.01, 0.01), - 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, - }, - ref - ) => { - const viewport = useThree(({ viewport }) => viewport) - const raycaster = useThree(({ raycaster }) => raycaster) - const pointer = useThree(({ pointer }) => pointer) - const { scene, camera } = useContext(EffectComposerContext) - - const [projectedPosition] = useState(() => new THREE.Vector3()) - const [mouse2d] = useState(() => new THREE.Vector2()) - - const opts = { - blendFunction, - enabled, - glareSize, - lensPosition, - screenRes, - starPoints, - flareSize, - flareSpeed, - flareShape, - animated, - anamorphic, - colorGain, - lensDirtTexture, - haloScale, - secondaryGhosts, - aditionalStreaks, - ghostScale, - opacity, - starBurst, - } - // eslint-disable-next-line react-hooks/exhaustive-deps - const effect = useMemo(() => new LensFlareEffect(opts), [JSON.stringify(opts)]) - - useFrame((_, delta) => { - const uLensPosition = effect.uniforms.get('lensPosition') - const uOpacity = effect.uniforms.get('opacity') - if (!uLensPosition || !uOpacity) return - - let target = 1 - - if (followMouse) { - uLensPosition.value.x = pointer.x - uLensPosition.value.y = pointer.y - 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 - } +const LensFlareWrapped = wrapEffect(LensFlareEffect) + +export const LensFlare = ({ + position = new THREE.Vector3(-25, 6, -60), + followMouse = false, + smoothTime = 0.07, + // + blendFunction = BlendFunction.NORMAL, + enabled = true, + glareSize = 0.2, + lensPosition = new THREE.Vector2(0.01, 0.01), + 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 pointer = useThree(({ pointer }) => pointer) + const { scene, camera } = useContext(EffectComposerContext) + + const [projectedPosition] = useState(() => new THREE.Vector3()) + const [mouse2d] = useState(() => new THREE.Vector2()) + + const ref = useRef(null) + + 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 + + if (followMouse) { + uLensPosition.value.x = pointer.x + uLensPosition.value.y = pointer.y + 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 } } } + } - easing.damp(uOpacity, 'value', target, smoothTime, delta) - }) + easing.damp(uOpacity, 'value', target, smoothTime, delta) + }) - useEffect(() => { - const screenRes = effect.uniforms.get('screenRes') - if (screenRes) { - screenRes.value.x = viewport.width - screenRes.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]) + + const opts = { + blendFunction, + enabled, + glareSize, + lensPosition, + screenRes, + starPoints, + flareSize, + flareSpeed, + flareShape, + animated, + anamorphic, + colorGain, + lensDirtTexture, + haloScale, + secondaryGhosts, + aditionalStreaks, + ghostScale, + opacity, + starBurst, } -) + return +} From c9788b3d764d52d8b38710502aee993cebdd2d07 Mon Sep 17 00:00:00 2001 From: Antoine BERNIER Date: Sat, 22 Jul 2023 00:08:32 +0200 Subject: [PATCH 06/10] fix: non-null assertion for ref --- src/effects/LensFlare.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index 3e6dd9e..378b4fc 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -540,7 +540,7 @@ export const LensFlare = ({ const [projectedPosition] = useState(() => new THREE.Vector3()) const [mouse2d] = useState(() => new THREE.Vector2()) - const ref = useRef(null) + const ref = useRef(null!) useFrame((_, delta) => { if (!ref?.current) return From baf0b60d3efc0ee7bf940416212aca6d729d69ac Mon Sep 17 00:00:00 2001 From: Antoine BERNIER Date: Tue, 25 Jul 2023 00:57:37 +0200 Subject: [PATCH 07/10] chore: painfully trying to fix TS --- src/effects/ChromaticAberration.tsx | 2 +- src/effects/LensFlare.tsx | 2 +- src/util.tsx | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/effects/ChromaticAberration.tsx b/src/effects/ChromaticAberration.tsx index 0ef9594..ce0baf9 100644 --- a/src/effects/ChromaticAberration.tsx +++ b/src/effects/ChromaticAberration.tsx @@ -1,5 +1,5 @@ import { ChromaticAberrationEffect } from 'postprocessing' import { type EffectProps, wrapEffect } from '../util' -export type ChromaticAberrationProps = EffectProps +export type ChromaticAberrationProps = EffectProps export const ChromaticAberration = wrapEffect(ChromaticAberrationEffect) diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index 378b4fc..3e6dd9e 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -540,7 +540,7 @@ export const LensFlare = ({ const [projectedPosition] = useState(() => new THREE.Vector3()) const [mouse2d] = useState(() => new THREE.Vector2()) - const ref = useRef(null!) + const ref = useRef(null) useFrame((_, delta) => { if (!ref?.current) return diff --git a/src/util.tsx b/src/util.tsx index 198cd66..8ea2b77 100644 --- a/src/util.tsx +++ b/src/util.tsx @@ -7,13 +7,14 @@ import type { Effect, BlendFunction } from 'postprocessing' export const resolveRef = (ref: T | React.MutableRefObject) => typeof ref === 'object' && ref != null && 'current' in ref ? ref.current : ref -export type EffectConstructor = new (...args: any[]) => Effect +export type Constructor = new (...args: any[]) => T -export type EffectProps = ReactThreeFiber.Node< - T extends Function ? T['prototype'] : InstanceType, +export type EffectConstructor = Constructor +export type EffectProps = ReactThreeFiber.Node< + T extends Function ? T['prototype'] : InstanceType>, T > & - ConstructorParameters[0] & { + ConstructorParameters>[0] & { blendFunction?: BlendFunction opacity?: number } @@ -21,7 +22,7 @@ export type EffectProps = ReactThreeFiber.Node< let i = 0 const components = new WeakMap | string>() -export const wrapEffect = (effect: T, defaults?: EffectProps) => +export const wrapEffect = (effect: Constructor, defaults?: EffectProps) => /* @__PURE__ */ React.forwardRef>(function Effect( { blendFunction = defaults?.blendFunction, opacity = defaults?.opacity, ...props }, ref From be8721ab9bfca16e9d616944e847c3a2d29b9a50 Mon Sep 17 00:00:00 2001 From: Anderson Mancini Date: Fri, 18 Aug 2023 08:03:34 -0300 Subject: [PATCH 08/10] fix crash --- src/effects/LensFlare.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index 3e6dd9e..75cc9a8 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -564,7 +564,7 @@ export const LensFlare = ({ mouse2d.set(projectedPosition.x, projectedPosition.y) raycaster.setFromCamera(mouse2d, camera) const intersects = raycaster.intersectObjects(scene.children, true) - const { object } = intersects[0] + const { object } = intersects[0] || {} if (object) { if (object.userData?.lensflare === 'no-occlusion') { target = 0 From 1300f726e6735e1117365cb1d63164964fcec865 Mon Sep 17 00:00:00 2001 From: Anderson Mancini Date: Fri, 18 Aug 2023 10:00:06 -0300 Subject: [PATCH 09/10] removed follow mouse option - suggested by Paul --- src/effects/LensFlare.tsx | 67 ++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index 75cc9a8..96775e6 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -407,7 +407,7 @@ type LensFlareEffectOptions = { /** The glare size */ glareSize: number /** The position of the lens flare in 3d space */ - lensPosition: THREE.Vector2 + lensPosition: THREE.Vector3 /** Effect resolution */ screenRes: THREE.Vector2 /** The number of points for the star */ @@ -498,9 +498,7 @@ export class LensFlareEffect extends Effect { type LensFlareProps = { /** Position of the effect */ - position?: THREE.Vector3 - /** Set it to follow the mouse, ignoring the lens position */ - followMouse?: boolean + lensPosition?: THREE.Vector3 /** The time that it takes to fade the occlusion */ smoothTime?: number } & Partial @@ -508,14 +506,12 @@ type LensFlareProps = { const LensFlareWrapped = wrapEffect(LensFlareEffect) export const LensFlare = ({ - position = new THREE.Vector3(-25, 6, -60), - followMouse = false, smoothTime = 0.07, // blendFunction = BlendFunction.NORMAL, enabled = true, glareSize = 0.2, - lensPosition = new THREE.Vector2(0.01, 0.01), + lensPosition = new THREE.Vector3(-25, 6, -60), screenRes = new THREE.Vector2(0, 0), starPoints = 6, flareSize = 0.01, @@ -534,11 +530,9 @@ export const LensFlare = ({ }: LensFlareProps) => { const viewport = useThree(({ viewport }) => viewport) const raycaster = useThree(({ raycaster }) => raycaster) - const pointer = useThree(({ pointer }) => pointer) const { scene, camera } = useContext(EffectComposerContext) - + let raycasterPos = new THREE.Vector2() const [projectedPosition] = useState(() => new THREE.Vector3()) - const [mouse2d] = useState(() => new THREE.Vector2()) const ref = useRef(null) @@ -550,35 +544,30 @@ export const LensFlare = ({ let target = 1 - if (followMouse) { - uLensPosition.value.x = pointer.x - uLensPosition.value.y = pointer.y - 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 - } + 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 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 } } } From e25ec21b9c966039f257477d609b63fa09cc0137 Mon Sep 17 00:00:00 2001 From: Cody Bennett Date: Sat, 18 Jan 2025 15:50:54 -0600 Subject: [PATCH 10/10] chore: cleanup --- src/effects/ChromaticAberration.tsx | 2 +- src/effects/LensFlare.tsx | 738 ++++++++++++++-------------- src/util.tsx | 11 +- 3 files changed, 376 insertions(+), 375 deletions(-) diff --git a/src/effects/ChromaticAberration.tsx b/src/effects/ChromaticAberration.tsx index ce0baf9..0ef9594 100644 --- a/src/effects/ChromaticAberration.tsx +++ b/src/effects/ChromaticAberration.tsx @@ -1,5 +1,5 @@ import { ChromaticAberrationEffect } from 'postprocessing' import { type EffectProps, wrapEffect } from '../util' -export type ChromaticAberrationProps = EffectProps +export type ChromaticAberrationProps = EffectProps export const ChromaticAberration = wrapEffect(ChromaticAberrationEffect) diff --git a/src/effects/LensFlare.tsx b/src/effects/LensFlare.tsx index 96775e6..d41ca39 100644 --- a/src/effects/LensFlare.tsx +++ b/src/effects/LensFlare.tsx @@ -11,392 +11,391 @@ import { EffectComposerContext } from '../EffectComposer' import { wrapEffect } from '../util' const LensFlareShader = { - fragmentShader: ` - - 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);} - - 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 + 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);} - float internalStarPoints; + float noise(float p){ + float fl = floor(p); + float fc = fract(p); + return mix(rand(fl),rand(fl + 1.0), fc); + } - if(anamorphic){ - internalStarPoints = 1.0; - } else{ - internalStarPoints = starPoints; + 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 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 saturate(float x) + { + return clamp(x, 0.,1.); } - } - float dist(vec3 a, vec3 b) { return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z); } + vec2 rotateUV(vec2 uv, float rotation) + { + return vec2( + cos(rotation) * uv.x + sin(rotation) * uv.y, + cos(rotation) * uv.y - sin(rotation) * uv.x + ); + } - vec3 saturate(vec3 x) - { - return clamp(x, vec3(0.0), vec3(1.0)); - } + // 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 - // Based on https://www.shadertoy.com/view/XtKfRV - float glare(vec2 uv, vec2 pos, float size) - { - vec2 main; + float internalStarPoints; - if(animated){ - main = rotateUV(uv-pos, time * 0.1); - } else{ - main = uv-pos; + 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 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 dist(vec3 a, vec3 b) { return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z); } - 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); - } + vec3 saturate(vec3 x) + { + return clamp(x, vec3(0.0), vec3(1.0)); + } - //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; - } + // Based on https://www.shadertoy.com/view/XtKfRV + float glare(vec2 uv, vec2 pos, float size) + { + vec2 main; - 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); - } + 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); - // 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; + return f0+f0*(sin((ang))*.2 +.3); + } - 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)); + 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); + } - vec2 prot; + //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; + } - if(animated){ - prot = rotateUV(uv - pos, (time * 0.1)); - } else if(anamorphic){ - prot = rotateUV(uv - pos, 1.570796); - } else { - prot = uv - pos; + 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); } - 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; - } + // 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; - 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 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)); - float rnd(vec2 p) - { - float f = fract(sin(dot(p, vec2(12.1234, 72.8392) )*45123.2)); - return f; - } + vec2 prot; - float rnd(float w) - { - float f = fract(sin(w)*1000.); - return f; - } + if(animated){ + prot = rotateUV(uv - pos, (time * 0.1)); + } else if(anamorphic){ + prot = rotateUV(uv - pos, 1.570796); + } else { + prot = uv - pos; + } - 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; - } + 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; + } - // 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; - } + vec3 cc(vec3 color, float factor,float factor2) + { + float w = color.x+color.y+color.z; + return mix(color,vec3(w)*factor,w*factor2); + } - 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 rnd(vec2 p) + { + float f = fract(sin(dot(p, vec2(12.1234, 72.8392) )*45123.2)); + return f; + } - 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; - } + float rnd(float w) + { + float f = fract(sin(w)*1000.); + return f; + } - 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); - } + 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; + } - 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); - } + // 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 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 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); } - } - 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); - } + 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; + } - // 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.; + 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); + } - //Aditional streaks - if(aditionalStreaks){ - vec3 circColor = vec3(0.9, 0.2, 0.1); - vec3 circColor2 = vec3(0.3, 0.1, 0.9); + 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); + } - 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); + 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); } } - //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; + 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); } - - //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.; + // 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; - finalColor += clamp((lensMod.rgb * getStartBurst().rgb ), 0.01, 1.0); - } + //First Lens flare pass + vec3 finalColor = LensFlare(myUV, finalLensPosition) * 20.0 * colorGain / 256.; - //Final composed output - if(enabled){ - outputColor = vec4(mix(finalColor, vec3(.0), opacity) + inputColor.rgb, inputColor.a); - } else { - outputColor = vec4(inputColor); + //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 = { @@ -503,7 +502,7 @@ type LensFlareProps = { smoothTime?: number } & Partial -const LensFlareWrapped = wrapEffect(LensFlareEffect) +const LensFlareWrapped = /* @__PURE__ */ wrapEffect(LensFlareEffect) export const LensFlare = ({ smoothTime = 0.07, @@ -531,7 +530,7 @@ export const LensFlare = ({ const viewport = useThree(({ viewport }) => viewport) const raycaster = useThree(({ raycaster }) => raycaster) const { scene, camera } = useContext(EffectComposerContext) - let raycasterPos = new THREE.Vector2() + const [raycasterPos] = useState(() => new THREE.Vector2()) const [projectedPosition] = useState(() => new THREE.Vector3()) const ref = useRef(null) @@ -585,26 +584,29 @@ export const LensFlare = ({ } }, [viewport]) - const opts = { - blendFunction, - enabled, - glareSize, - lensPosition, - screenRes, - starPoints, - flareSize, - flareSpeed, - flareShape, - animated, - anamorphic, - colorGain, - lensDirtTexture, - haloScale, - secondaryGhosts, - aditionalStreaks, - ghostScale, - opacity, - starBurst, - } - return + return ( + + ) } diff --git a/src/util.tsx b/src/util.tsx index 8ea2b77..198cd66 100644 --- a/src/util.tsx +++ b/src/util.tsx @@ -7,14 +7,13 @@ import type { Effect, BlendFunction } from 'postprocessing' export const resolveRef = (ref: T | React.MutableRefObject) => typeof ref === 'object' && ref != null && 'current' in ref ? ref.current : ref -export type Constructor = new (...args: any[]) => T +export type EffectConstructor = new (...args: any[]) => Effect -export type EffectConstructor = Constructor -export type EffectProps = ReactThreeFiber.Node< - T extends Function ? T['prototype'] : InstanceType>, +export type EffectProps = ReactThreeFiber.Node< + T extends Function ? T['prototype'] : InstanceType, T > & - ConstructorParameters>[0] & { + ConstructorParameters[0] & { blendFunction?: BlendFunction opacity?: number } @@ -22,7 +21,7 @@ export type EffectProps = ReactThreeFiber.Node< let i = 0 const components = new WeakMap | string>() -export const wrapEffect = (effect: Constructor, defaults?: EffectProps) => +export const wrapEffect = (effect: T, defaults?: EffectProps) => /* @__PURE__ */ React.forwardRef>(function Effect( { blendFunction = defaults?.blendFunction, opacity = defaults?.opacity, ...props }, ref