@tresjs/post-processing 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/pmndrs/BarrelBlurPmndrs.vue.d.ts +26 -0
- package/dist/core/pmndrs/{Bloom.vue.d.ts → BloomPmndrs.vue.d.ts} +8 -8
- package/dist/core/pmndrs/ChromaticAberrationPmndrs.vue.d.ts +27 -0
- package/dist/core/pmndrs/ColorAveragePmndrs.vue.d.ts +16 -0
- package/dist/core/pmndrs/{DepthOfField.vue.d.ts → DepthOfFieldPmndrs.vue.d.ts} +3 -3
- package/dist/core/pmndrs/DotScreenPmndrs.vue.d.ts +22 -0
- package/dist/core/pmndrs/{EffectComposer.vue.d.ts → EffectComposerPmndrs.vue.d.ts} +3 -3
- package/dist/core/pmndrs/{Glitch.vue.d.ts → GlitchPmndrs.vue.d.ts} +3 -3
- package/dist/core/pmndrs/HueSaturationPmndrs.vue.d.ts +22 -0
- package/dist/core/pmndrs/KuwaharaPmndrs.vue.d.ts +27 -0
- package/dist/core/pmndrs/LensDistortionPmndrs.vue.d.ts +25 -0
- package/dist/core/pmndrs/LinocutPmndrs.vue.d.ts +15 -0
- package/dist/core/pmndrs/{Noise.vue.d.ts → NoisePmndrs.vue.d.ts} +3 -4
- package/dist/core/pmndrs/{Outline.vue.d.ts → OutlinePmndrs.vue.d.ts} +3 -3
- package/dist/core/pmndrs/{Pixelation.vue.d.ts → PixelationPmndrs.vue.d.ts} +3 -3
- package/dist/core/pmndrs/ScanlinePmndrs.vue.d.ts +24 -0
- package/dist/core/pmndrs/SepiaPmndrs.vue.d.ts +16 -0
- package/dist/core/pmndrs/ShockWavePmndrs.vue.d.ts +29 -0
- package/dist/core/pmndrs/TiltShiftPmndrs.vue.d.ts +49 -0
- package/dist/core/pmndrs/ToneMappingPmndrs.vue.d.ts +36 -0
- package/dist/core/pmndrs/{Vignette.vue.d.ts → VignettePmndrs.vue.d.ts} +6 -11
- package/dist/core/pmndrs/composables/{useEffect.d.ts → useEffectPmndrs.d.ts} +1 -1
- package/dist/core/pmndrs/custom/barrel-blur/index.d.ts +36 -0
- package/dist/core/pmndrs/custom/kuwahara/index.d.ts +31 -0
- package/dist/core/pmndrs/custom/linocut/index.d.ts +27 -0
- package/dist/core/pmndrs/index.d.ts +23 -10
- package/dist/core/three/UnrealBloom.vue.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/tres-post-processing.d.ts +2 -0
- package/dist/{three.js → tres-post-processing.js} +1324 -258
- package/dist/tres-post-processing.umd.cjs +1209 -0
- package/package.json +24 -27
- package/dist/pmndrs.d.ts +0 -2
- package/dist/pmndrs.js +0 -352
- package/dist/prop-BjrXLDuj.js +0 -43
- package/dist/three.d.ts +0 -2
|
@@ -0,0 +1,1209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* name: @tresjs/post-processing
|
|
3
|
+
* version: v2.1.0
|
|
4
|
+
* (c) 2025
|
|
5
|
+
* description: Post-processing library for TresJS
|
|
6
|
+
* author: Alvaro Saburido <hola@alvarosaburido.dev> (https://github.com/alvarosabu/)
|
|
7
|
+
*/
|
|
8
|
+
(function(u,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("vue"),require("postprocessing"),require("@tresjs/core"),require("three"),require("@vueuse/core")):typeof define=="function"&&define.amd?define(["exports","vue","postprocessing","@tresjs/core","three","@vueuse/core"],n):(u=typeof globalThis<"u"?globalThis:u||self,n(u["tres-post-processing"]={},u.Vue,u.Postprocessing,u.TresjsCore,u.Three,u.VueUseCore))})(this,function(u,n,f,g,s,F){"use strict";const z=/([^[.\]])+/g,J=(r,e)=>{if(!e)return;const t=Array.isArray(e)?e:e.match(z);return t==null?void 0:t.reduce((o,a)=>o&&o[a],r)},U=(r,e,t)=>{const o=Array.isArray(e)?e:e.match(z);o&&o.reduce((a,i,l)=>(a[i]===void 0&&(a[i]={}),l===o.length-1&&(a[i]=t),a[i]),r)},O=(r,e)=>{const t={...r};return e.forEach(o=>delete t[o]),t},B=(r,e,t,o,a={})=>n.watch(r,i=>{var l;if(e.value)if(i===void 0){const c=o();U(e.value,t,J(c,t)),(l=c.dispose)==null||l.call(c)}else U(e.value,t,r())},a),b=(r,e,t)=>r.map(([o,a])=>B(o,e,a,t)),C=(r,e,t)=>Object.keys(r).map(o=>B(()=>r[o],e,o,t));class W{static isWebGL2Available(){try{const e=document.createElement("canvas");return!!(window.WebGL2RenderingContext&&e.getContext("webgl2"))}catch{return!1}}static isColorSpaceAvailable(e){try{const t=document.createElement("canvas"),o=window.WebGL2RenderingContext&&t.getContext("webgl2");return o.drawingBufferColorSpace=e,o.drawingBufferColorSpace===e}catch{return!1}}static getWebGL2ErrorMessage(){return this.getErrorMessage(2)}static getErrorMessage(e){const t={1:"WebGL",2:"WebGL 2"},o={1:window.WebGLRenderingContext,2:window.WebGL2RenderingContext};let a='Your $0 does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">$1</a>';const i=document.createElement("div");return i.id="webglmessage",i.style.fontFamily="monospace",i.style.fontSize="13px",i.style.fontWeight="normal",i.style.textAlign="center",i.style.background="#fff",i.style.color="#000",i.style.padding="1.5em",i.style.width="400px",i.style.margin="5em auto 0",o[e]?a=a.replace("$0","graphics card"):a=a.replace("$0","browser"),a=a.replace("$1",t[e]),i.innerHTML=a,i}static isWebGLAvailable(){console.warn("isWebGLAvailable() has been deprecated and will be removed in r178. Use isWebGL2Available() instead.");try{const e=document.createElement("canvas");return!!(window.WebGLRenderingContext&&(e.getContext("webgl")||e.getContext("experimental-webgl")))}catch{return!1}}static getWebGLErrorMessage(){return console.warn("getWebGLErrorMessage() has been deprecated and will be removed in r178. Use getWebGL2ErrorMessage() instead."),this.getErrorMessage(1)}}const H=Symbol("effectComposerPmndrs"),Z=n.defineComponent({__name:"EffectComposerPmndrs",props:{enabled:{type:Boolean,default:!0},depthBuffer:{type:Boolean,default:void 0},disableNormalPass:{type:Boolean,default:!1},stencilBuffer:{type:Boolean,default:void 0},resolutionScale:{},autoClear:{type:Boolean,default:!0},multisampling:{default:0},frameBufferType:{default:s.HalfFloatType}},emits:["render"],setup(r,{expose:e,emit:t}){const o=r,a=t,{scene:i,camera:l,renderer:c,sizes:d,render:S}=g.useTresContext(),h=n.shallowRef(null);let v=null,m=null;n.provide(H,h),e({composer:h});const A=()=>{h.value&&(m=new f.NormalPass(i.value,l.value),m.enabled=!1,h.value.addPass(m),o.resolutionScale!==void 0&&W.isWebGL2Available()&&(v=new f.DepthDownsamplingPass({normalBuffer:m.texture,resolutionScale:o.resolutionScale}),v.enabled=!1,h.value.addPass(v)))},R=n.computed(()=>{const x=new f.EffectComposer,E={depthBuffer:o.depthBuffer!==void 0?o.depthBuffer:x.inputBuffer.depthBuffer,stencilBuffer:o.stencilBuffer!==void 0?o.stencilBuffer:x.inputBuffer.stencilBuffer,multisampling:W.isWebGL2Available()?o.multisampling!==void 0?o.multisampling:x.multisampling:0,frameBufferType:o.frameBufferType!==void 0?o.frameBufferType:s.HalfFloatType};return x.dispose(),E}),K=()=>{var x;!c.value&&!i.value&&!l.value||((x=h.value)==null||x.dispose(),h.value=new f.EffectComposer(c.value,R.value),h.value.addPass(new f.RenderPass(i.value,l.value)),o.disableNormalPass||A())};n.watch([c,i,l,()=>o.disableNormalPass],()=>{!d.width.value||!d.height.value||K()}),n.watch(()=>[d.width.value,d.height.value],([x,E])=>{!x&&!E||(h.value?h.value.setSize(x,E):K())},{immediate:!0});const{render:We}=g.useLoop();return We(()=>{if(o.enabled&&c.value&&h.value&&d.width.value&&d.height.value&&S.frames.value>0){const x=c.value.autoClear;c.value.autoClear=o.autoClear,o.stencilBuffer&&!o.autoClear&&c.value.clearStencil(),h.value.render(),a("render",h.value),c.value.autoClear=x}S.frames.value=S.mode.value==="always"?1:Math.max(0,S.frames.value-1)}),n.onUnmounted(()=>{var x;(x=h.value)==null||x.dispose()}),(x,E)=>n.renderSlot(x.$slots,"default")}}),p=(r,e)=>{const t=n.inject(H),o=n.shallowRef(null),a=n.shallowRef(null),{scene:i,camera:l,invalidate:c}=g.useTresContext();e&&n.watch(e,()=>c()),n.watchEffect(()=>{!l.value||!(a!=null&&a.value)||(a.value.mainCamera=l.value)});const d=n.watchEffect(()=>{!l.value||!(t!=null&&t.value)||!i.value||(n.nextTick(()=>d()),!a.value&&(a.value=r(),o.value=new f.EffectPass(l.value,a.value),t.value.addPass(o.value)))});return n.onUnmounted(()=>{var S,h,v;o.value&&((S=t==null?void 0:t.value)==null||S.removePass(o.value)),(h=a.value)==null||h.dispose(),(v=o.value)==null||v.dispose()}),{pass:o,effect:a}},_=n.defineComponent({__name:"BloomPmndrs",props:{blendFunction:{},intensity:{},kernelSize:{},luminanceThreshold:{},luminanceSmoothing:{},mipmapBlur:{type:Boolean,default:void 0}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.BloomEffect(t),t);return e({pass:o,effect:a}),b([[()=>t.intensity,"intensity"],[()=>t.kernelSize,"kernelSize"],[()=>t.luminanceSmoothing,"luminanceMaterial.smoothing"],[()=>t.luminanceThreshold,"luminanceMaterial.threshold"]],a,()=>new f.BloomEffect),()=>{}}}),$=n.defineComponent({__name:"DepthOfFieldPmndrs",props:{blendFunction:{},worldFocusDistance:{},worldFocusRange:{},focusDistance:{},focusRange:{},bokehScale:{},resolutionScale:{},resolutionX:{},resolutionY:{}},setup(r,{expose:e}){const t=r,{camera:o}=g.useTresContext(),{pass:a,effect:i}=p(()=>new f.DepthOfFieldEffect(o.value,t),t);return e({pass:a,effect:i}),b([[()=>t.worldFocusDistance,"circleOfConfusionMaterial.worldFocusDistance"],[()=>t.focusDistance,"circleOfConfusionMaterial.focusDistance"],[()=>t.worldFocusRange,"circleOfConfusionMaterial.worldFocusRange"],[()=>t.focusRange,"circleOfConfusionMaterial.focusRange"],[()=>t.bokehScale,"bokehScale"],[()=>t.resolutionScale,"blurPass.resolution.scale"],[()=>t.resolutionX,"resolution.width"],[()=>t.resolutionY,"resolution.height"]],i,()=>new f.DepthOfFieldEffect),()=>{}}}),ee=n.defineComponent({__name:"GlitchPmndrs",props:{blendFunction:{},delay:{},duration:{},strength:{},mode:{},active:{type:Boolean},ratio:{},columns:{},chromaticAberrationOffset:{},perturbationMap:{},dtSize:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.GlitchEffect(t),t);e({pass:o,effect:a});const{onBeforeRender:i}=g.useLoop();return i(({invalidate:l})=>l()),n.watchEffect(()=>{const l=()=>{if(t.mode!==void 0)return t.active===!1?f.GlitchMode.DISABLED:t.mode;const c=new f.GlitchEffect,d=c.mode;return c.dispose(),d};a.value&&(a.value.mode=l())}),C(O(t,["active","mode","blendFunction"]),a,()=>new f.GlitchEffect),()=>{}}}),te=n.defineComponent({__name:"NoisePmndrs",props:{premultiply:{type:Boolean,default:void 0},blendFunction:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.NoiseEffect(t),t);e({pass:o,effect:a});const{onBeforeRender:i}=g.useLoop();return i(({invalidate:l})=>l()),C(O(t,["blendFunction"]),a,()=>new f.NoiseEffect),()=>{}}}),oe=n.defineComponent({__name:"OutlinePmndrs",props:{outlinedObjects:{},blur:{type:Boolean,default:void 0},xRay:{type:Boolean,default:void 0},kernelSize:{},pulseSpeed:{},resolutionX:{},resolutionY:{},edgeStrength:{},patternScale:{},multisampling:{},blendFunction:{},patternTexture:{},resolutionScale:{},hiddenEdgeColor:{},visibleEdgeColor:{}},setup(r,{expose:e}){const t=r,o=h=>h!==void 0?g.normalizeColor(h).getHex():void 0,{camera:a,scene:i}=g.useTresContext(),l={blur:t.blur,xRay:t.xRay,kernelSize:t.kernelSize,pulseSpeed:t.pulseSpeed,resolutionX:t.resolutionX,resolutionY:t.resolutionY,patternScale:t.patternScale,edgeStrength:t.edgeStrength,blendFunction:t.blendFunction,multisampling:t.multisampling,patternTexture:t.patternTexture,resolutionScale:t.resolutionScale,hiddenEdgeColor:o(t.hiddenEdgeColor),visibleEdgeColor:o(t.visibleEdgeColor)},{pass:c,effect:d}=p(()=>new f.OutlineEffect(i.value,a.value,l),t);e({pass:c,effect:d}),n.watch([()=>t.outlinedObjects,d],()=>{var h;(h=d.value)==null||h.selection.set(t.outlinedObjects||[])},{immediate:!0});const S=n.computed(()=>({hiddenEdgeColor:t.hiddenEdgeColor?g.normalizeColor(t.hiddenEdgeColor):void 0,visibleEdgeColor:t.visibleEdgeColor?g.normalizeColor(t.visibleEdgeColor):void 0}));return b([[()=>t.blur,"blur"],[()=>t.xRay,"xRay"],[()=>t.pulseSpeed,"pulseSpeed"],[()=>t.kernelSize,"kernelSize"],[()=>t.edgeStrength,"edgeStrength"],[()=>t.patternScale,"patternScale"],[()=>t.multisampling,"multisampling"],[()=>S.value.hiddenEdgeColor,"hiddenEdgeColor"],[()=>S.value.visibleEdgeColor,"visibleEdgeColor"]],d,()=>new f.OutlineEffect),()=>{}}}),ae=n.defineComponent({__name:"PixelationPmndrs",props:{granularity:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.PixelationEffect(t.granularity),t);return e({pass:o,effect:a}),C(t,a,()=>new f.PixelationEffect),()=>{}}}),ie=n.defineComponent({__name:"VignettePmndrs",props:{technique:{},blendFunction:{},offset:{},darkness:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.VignetteEffect(t),t);return e({pass:o,effect:a}),C(O(t,["blendFunction"]),a,()=>new f.VignetteEffect),()=>{}}});class G extends f.Effect{constructor({blendFunction:e=f.BlendFunction.NORMAL,amount:t=.15,offset:o=new s.Vector2(.5,.5)}={}){super("BarrelBlurEffect",`
|
|
9
|
+
uniform float amount;
|
|
10
|
+
uniform vec2 offset;
|
|
11
|
+
|
|
12
|
+
#define NUM_ITER 16
|
|
13
|
+
#define RECIP_NUM_ITER 0.0625
|
|
14
|
+
#define GAMMA 1.0
|
|
15
|
+
|
|
16
|
+
vec3 spectrum_offset(float t) {
|
|
17
|
+
float lo = step(t, 0.5);
|
|
18
|
+
float hi = 1.0 - lo;
|
|
19
|
+
float w = 1.0 - abs(2.0 * t - 1.0);
|
|
20
|
+
return pow(vec3(lo, 1.0, hi) * vec3(1.0 - w, w, 1.0 - w), vec3(1.0 / GAMMA));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
vec2 barrelDistortion(vec2 p, float amt) {
|
|
24
|
+
p = p - offset;
|
|
25
|
+
float theta = atan(p.y, p.x);
|
|
26
|
+
float radius = pow(length(p), 1.0 + 3.0 * amt);
|
|
27
|
+
return vec2(cos(theta), sin(theta)) * radius + offset;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
void mainUv(inout vec2 uv) {
|
|
31
|
+
uv = barrelDistortion(uv, amount * 0.5);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
|
|
35
|
+
vec3 sumcol = vec3(0.0);
|
|
36
|
+
vec3 sumw = vec3(0.0);
|
|
37
|
+
|
|
38
|
+
for (int i = 0; i < NUM_ITER; ++i) {
|
|
39
|
+
float t = float(i) * RECIP_NUM_ITER;
|
|
40
|
+
vec3 w = spectrum_offset(t);
|
|
41
|
+
vec2 distortedUV = barrelDistortion(uv, amount * t);
|
|
42
|
+
sumcol += w * texture(inputBuffer, distortedUV).rgb;
|
|
43
|
+
sumw += w;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
vec3 outcol = pow(sumcol / sumw, vec3(1.0 / GAMMA));
|
|
47
|
+
|
|
48
|
+
outcol = clamp(outcol, 0.0, 1.0); // Ensures normalized color values
|
|
49
|
+
|
|
50
|
+
outputColor = vec4(outcol, inputColor.a); // Preserves original alpha
|
|
51
|
+
}
|
|
52
|
+
`,{blendFunction:e,uniforms:new Map([["amount",new s.Uniform(t)],["offset",new s.Uniform(o)]])})}get amount(){var e;return(e=this.uniforms.get("amount"))==null?void 0:e.value}set amount(e){this.uniforms.get("amount").value=e}get offset(){var e;return(e=this.uniforms.get("offset"))==null?void 0:e.value}set offset(e){this.uniforms.get("offset").value=e}}const se=n.defineComponent({__name:"BarrelBlurPmndrs",props:{blendFunction:{},amount:{},offset:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new G({...t,offset:Array.isArray(t.offset)?new s.Vector2(...t.offset):t.offset}),t);return e({pass:o,effect:a}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.amount,"amount"],[()=>t.offset,"offset"]],a,()=>new G),()=>{}}}),re=n.defineComponent({__name:"ToneMappingPmndrs",props:{mode:{},blendFunction:{},resolution:{},averageLuminance:{},middleGrey:{},minLuminance:{},whitePoint:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.ToneMappingEffect(t),t);return e({pass:o,effect:a}),b([[()=>t.mode,"mode"],[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.resolution,"resolution"],[()=>t.averageLuminance,"averageLuminance"],[()=>t.middleGrey,"middleGrey"],[()=>t.minLuminance,"adaptiveLuminanceMaterial.minLuminance"],[()=>t.whitePoint,"whitePoint"]],a,()=>new f.ToneMappingEffect),()=>{}}}),ne=n.defineComponent({__name:"ChromaticAberrationPmndrs",props:{blendFunction:{},offset:{},radialModulation:{type:Boolean,default:void 0},modulationOffset:{}},setup(r,{expose:e}){const t=r,o=new f.ChromaticAberrationEffect,{pass:a,effect:i}=p(()=>new f.ChromaticAberrationEffect({...t,radialModulation:t.radialModulation??o.radialModulation,modulationOffset:t.modulationOffset??o.modulationOffset}),t);return o.dispose(),e({pass:a,effect:i}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.offset,"offset"],[()=>t.radialModulation,"radialModulation"],[()=>t.modulationOffset,"modulationOffset"]],i,()=>new f.ChromaticAberrationEffect),()=>{}}}),le=n.defineComponent({__name:"HueSaturationPmndrs",props:{saturation:{},hue:{},blendFunction:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.HueSaturationEffect(t),t);return e({pass:o,effect:a}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.hue,"hue"],[()=>t.saturation,"saturation"]],a,()=>new f.HueSaturationEffect),()=>{}}}),ce=n.defineComponent({__name:"ScanlinePmndrs",props:{blendFunction:{},density:{},scrollSpeed:{},opacity:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.ScanlineEffect(t),t);return e({pass:o,effect:a}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.density,"density"],[()=>t.scrollSpeed,"scrollSpeed"]],a,()=>new f.ScanlineEffect),n.watch([()=>t.opacity],()=>{var i,l;if(t.opacity!==void 0)(i=a.value)==null||i.blendMode.setOpacity(t.opacity);else{const c=new f.ScanlineEffect;(l=a.value)==null||l.blendMode.setOpacity(c.blendMode.getOpacity()),c.dispose()}},{immediate:!0}),()=>{}}}),fe=`
|
|
53
|
+
uniform float radius;
|
|
54
|
+
uniform int sectorCount;
|
|
55
|
+
|
|
56
|
+
const int MAX_SECTOR_COUNT = 8;
|
|
57
|
+
|
|
58
|
+
float polynomialWeight(float x, float y, float eta, float lambda) {
|
|
59
|
+
float polyValue = (x + eta) - lambda * (y * y);
|
|
60
|
+
return max(0.0, polyValue * polyValue);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
void getSectorVarianceAndAverageColor(mat2 anisotropyMat, float angle, float radius, out vec3 avgColor, out float variance) {
|
|
64
|
+
vec3 weightedColorSum = vec3(0.0);
|
|
65
|
+
vec3 weightedSquaredColorSum = vec3(0.0);
|
|
66
|
+
float totalWeight = 0.0;
|
|
67
|
+
|
|
68
|
+
float eta = 0.1;
|
|
69
|
+
float lambda = 0.5;
|
|
70
|
+
float angleStep = 0.196349; // Precompute angle step
|
|
71
|
+
float halfAngleRange = 0.392699; // Precompute half angle range
|
|
72
|
+
|
|
73
|
+
float cosAngle = cos(angle);
|
|
74
|
+
float sinAngle = sin(angle);
|
|
75
|
+
|
|
76
|
+
for (float r = 1.0; r <= radius; r += 1.0) {
|
|
77
|
+
float rCosAngle = r * cosAngle;
|
|
78
|
+
float rSinAngle = r * sinAngle;
|
|
79
|
+
for (float a = -halfAngleRange; a <= halfAngleRange; a += angleStep) {
|
|
80
|
+
float cosA = cos(a);
|
|
81
|
+
float sinA = sin(a);
|
|
82
|
+
vec2 sampleOffset = vec2(rCosAngle * cosA - rSinAngle * sinA, rCosAngle * sinA + rSinAngle * cosA) / resolution;
|
|
83
|
+
sampleOffset *= anisotropyMat;
|
|
84
|
+
|
|
85
|
+
vec3 color = texture2D(inputBuffer, vUv + sampleOffset).rgb;
|
|
86
|
+
float weight = polynomialWeight(sampleOffset.x, sampleOffset.y, eta, lambda);
|
|
87
|
+
|
|
88
|
+
weightedColorSum += color * weight;
|
|
89
|
+
weightedSquaredColorSum += color * color * weight;
|
|
90
|
+
totalWeight += weight;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Calculate average color and variance
|
|
95
|
+
avgColor = weightedColorSum / totalWeight;
|
|
96
|
+
vec3 varianceRes = (weightedSquaredColorSum / totalWeight) - (avgColor * avgColor);
|
|
97
|
+
variance = dot(varianceRes, vec3(0.299, 0.587, 0.114)); // Convert to luminance
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
vec4 getDominantOrientation(vec4 structureTensor) {
|
|
101
|
+
float Jxx = structureTensor.r;
|
|
102
|
+
float Jyy = structureTensor.g;
|
|
103
|
+
float Jxy = structureTensor.b;
|
|
104
|
+
|
|
105
|
+
float trace = Jxx + Jyy;
|
|
106
|
+
float det = Jxx * Jyy - Jxy * Jxy;
|
|
107
|
+
float lambda1 = 0.5 * (trace + sqrt(trace * trace - 4.0 * det));
|
|
108
|
+
float lambda2 = 0.5 * (trace - sqrt(trace * trace - 4.0 * det));
|
|
109
|
+
|
|
110
|
+
float dominantOrientation = atan(2.0 * Jxy, Jxx - Jyy) / 2.0;
|
|
111
|
+
return vec4(dominantOrientation, lambda1, lambda2, 0.0);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
|
|
115
|
+
vec4 structureTensor = texture2D(inputBuffer, uv);
|
|
116
|
+
|
|
117
|
+
vec3 sectorAvgColors[MAX_SECTOR_COUNT];
|
|
118
|
+
float sectorVariances[MAX_SECTOR_COUNT];
|
|
119
|
+
|
|
120
|
+
vec4 orientationAndAnisotropy = getDominantOrientation(structureTensor);
|
|
121
|
+
vec2 orientation = orientationAndAnisotropy.xy;
|
|
122
|
+
|
|
123
|
+
float anisotropy = (orientationAndAnisotropy.z - orientationAndAnisotropy.w) / (orientationAndAnisotropy.z + orientationAndAnisotropy.w + 1e-7);
|
|
124
|
+
|
|
125
|
+
float alpha = 25.0;
|
|
126
|
+
float scaleX = alpha / (anisotropy + alpha);
|
|
127
|
+
float scaleY = (anisotropy + alpha) / alpha;
|
|
128
|
+
|
|
129
|
+
mat2 anisotropyMat = mat2(orientation.x, -orientation.y, orientation.y, orientation.x) * mat2(scaleX, 0.0, 0.0, scaleY);
|
|
130
|
+
|
|
131
|
+
for (int i = 0; i < sectorCount; i++) {
|
|
132
|
+
float angle = float(i) * 6.28318 / float(sectorCount); // 2π / sectorCount
|
|
133
|
+
getSectorVarianceAndAverageColor(anisotropyMat, angle, float(radius), sectorAvgColors[i], sectorVariances[i]);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
float minVariance = sectorVariances[0];
|
|
137
|
+
vec3 finalColor = sectorAvgColors[0];
|
|
138
|
+
|
|
139
|
+
for (int i = 1; i < sectorCount; i++) {
|
|
140
|
+
if (sectorVariances[i] < minVariance) {
|
|
141
|
+
minVariance = sectorVariances[i];
|
|
142
|
+
finalColor = sectorAvgColors[i];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
outputColor = vec4(finalColor, inputColor.a);
|
|
147
|
+
}
|
|
148
|
+
`;class V extends f.Effect{constructor({blendFunction:e=f.BlendFunction.NORMAL,radius:t=1,sectorCount:o=4}={}){super("KuwaharaEffect",fe,{blendFunction:e,uniforms:new Map([["radius",new s.Uniform(t)],["sectorCount",new s.Uniform(o)]])})}get radius(){var e;return(e=this.uniforms.get("radius"))==null?void 0:e.value}set radius(e){this.uniforms.get("radius").value=e}get sectorCount(){var e;return(e=this.uniforms.get("sectorCount"))==null?void 0:e.value}set sectorCount(e){this.uniforms.get("sectorCount").value=e}}const ue=n.defineComponent({__name:"KuwaharaPmndrs",props:{blendFunction:{},radius:{},sectorCount:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new V(t),t);return e({pass:o,effect:a}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.radius,"radius"],[()=>t.sectorCount,"sectorCount"]],a,()=>new V),()=>{}}}),de=n.defineComponent({__name:"ColorAveragePmndrs",props:{blendFunction:{},opacity:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.ColorAverageEffect(t.blendFunction),t);return e({pass:o,effect:a}),B(()=>t.blendFunction,a,"blendMode.blendFunction",()=>new f.ColorAverageEffect),n.watch([a,()=>t.opacity],()=>{var i,l;if(a.value)if(t.opacity!==void 0)(i=a.value)==null||i.blendMode.setOpacity(t.opacity);else{const c=new f.ColorAverageEffect;(l=a.value)==null||l.blendMode.setOpacity(c.blendMode.getOpacity()),c.dispose()}}),()=>{}}}),he=n.defineComponent({__name:"LensDistortionPmndrs",props:{distortion:{},principalPoint:{},focalLength:{},skew:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.LensDistortionEffect({...t,distortion:t.distortion?Array.isArray(t.distortion)?new s.Vector2(...t.distortion):t.distortion:new s.Vector2,principalPoint:t.principalPoint?Array.isArray(t.principalPoint)?new s.Vector2(...t.principalPoint):t.principalPoint:new s.Vector2,focalLength:t.focalLength?Array.isArray(t.focalLength)?new s.Vector2(...t.focalLength):t.focalLength:new s.Vector2}),t);return e({pass:o,effect:a}),C(t,a,()=>new f.LensDistortionEffect),()=>{}}}),me=n.defineComponent({__name:"ShockWavePmndrs",props:{position:{},amplitude:{},speed:{},maxRadius:{},waveSize:{}},setup(r,{expose:e}){const t=r,{camera:o}=g.useTresContext(),{pass:a,effect:i}=p(()=>new f.ShockWaveEffect(o.value,Array.isArray(t.position)?new s.Vector3(...t.position):t.position,t),t);return e({pass:a,effect:i}),n.watch(()=>t.position,l=>{i.value&&(Array.isArray(l)?i.value.position.set(...l):l instanceof s.Vector3&&i.value.position.copy(l))},{immediate:!0}),b([[()=>t.amplitude,"amplitude"],[()=>t.waveSize,"waveSize"],[()=>t.maxRadius,"maxRadius"],[()=>t.speed,"speed"]],i,()=>new f.ShockWaveEffect),()=>{}}}),pe=n.defineComponent({__name:"TiltShiftPmndrs",props:{blendFunction:{},offset:{},rotation:{},focusArea:{},feather:{},kernelSize:{},resolutionScale:{},resolutionX:{},resolutionY:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.TiltShiftEffect(t),t);return e({pass:o,effect:a}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.offset,"offset"],[()=>t.rotation,"rotation"],[()=>t.focusArea,"focusArea"],[()=>t.feather,"feather"],[()=>t.kernelSize,"kernelSize"],[()=>t.resolutionScale,"resolution.scale"],[()=>t.resolutionX,"resolution.width"],[()=>t.resolutionY,"resolution.height"]],a,()=>new f.TiltShiftEffect),()=>{}}}),ge=n.defineComponent({__name:"DotScreenPmndrs",props:{angle:{},scale:{},blendFunction:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.DotScreenEffect(t),t);return e({pass:o,effect:a}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.angle,"angle"],[()=>t.scale,"scale"]],a,()=>new f.DotScreenEffect),()=>{}}}),ve=n.defineComponent({__name:"SepiaPmndrs",props:{blendFunction:{},intensity:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new f.SepiaEffect(t),t);return e({pass:o,effect:a}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.intensity,"intensity"]],a,()=>new f.SepiaEffect),()=>{}}});class X extends f.Effect{constructor({blendFunction:e=f.BlendFunction.NORMAL,scale:t=.85,noiseScale:o=0,center:a=[.5,.5],rotation:i=0}={}){const l=Array.isArray(a)?new s.Vector2().fromArray(a):a;super("LinocutEffect",`
|
|
149
|
+
uniform float scale;
|
|
150
|
+
uniform float noiseScale;
|
|
151
|
+
uniform vec2 center;
|
|
152
|
+
uniform float rotation;
|
|
153
|
+
|
|
154
|
+
float luma(vec3 color) {
|
|
155
|
+
return dot(color, vec3(0.299, 0.587, 0.114));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
float luma(vec4 color) {
|
|
159
|
+
return dot(color.rgb, vec3(0.299, 0.587, 0.114));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Simple pseudo-random noise function
|
|
163
|
+
float noise(vec2 p) {
|
|
164
|
+
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453123);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
|
|
168
|
+
// Calculate the center based on center
|
|
169
|
+
vec2 fragCoord = uv * resolution.xy;
|
|
170
|
+
|
|
171
|
+
// Apply rotation to the coordinates
|
|
172
|
+
vec2 d = fragCoord - center * resolution.xy;
|
|
173
|
+
mat2 rotMat = mat2(cos(rotation), -sin(rotation), sin(rotation), cos(rotation));
|
|
174
|
+
vec2 rotatedD = d * rotMat;
|
|
175
|
+
|
|
176
|
+
// Calculate radial distance and angle
|
|
177
|
+
float r = length(rotatedD) / (1000.0 / max(scale, 0.01)); // Normalization to avoid artifacts
|
|
178
|
+
float a = atan(rotatedD.y, rotatedD.x) + scale * (0.5 - r) / 0.5;
|
|
179
|
+
|
|
180
|
+
// Calculate transformed coordinates
|
|
181
|
+
vec2 uvt = center * resolution.xy + r * vec2(cos(a), sin(a));
|
|
182
|
+
|
|
183
|
+
// Normalize UV coordinates
|
|
184
|
+
vec2 uv2 = fragCoord / resolution.xy;
|
|
185
|
+
|
|
186
|
+
// Generate sinusoidal line patterns
|
|
187
|
+
float c = (0.75 + 0.25 * sin(uvt.x * 1000.0 * max(scale, 0.01))); // Prevent excessive distortions
|
|
188
|
+
|
|
189
|
+
// Load the texture and convert to grayscale
|
|
190
|
+
vec4 color = texture(inputBuffer, uv2);
|
|
191
|
+
color.rgb = color.rgb * color.rgb; // Convert from sRGB to linear
|
|
192
|
+
float l = luma(color);
|
|
193
|
+
|
|
194
|
+
// Add noise based on noiseScale
|
|
195
|
+
float n = noise(uv2 * 10.0); // Generate noise
|
|
196
|
+
l += noiseScale * (n - 0.5); // Apply noise as a perturbation
|
|
197
|
+
|
|
198
|
+
// Apply smoothing to achieve the linocut effect
|
|
199
|
+
float f = smoothstep(0.5 * c, c, l);
|
|
200
|
+
f = smoothstep(0.0, 0.5, f);
|
|
201
|
+
|
|
202
|
+
// Convert the final value back to sRGB
|
|
203
|
+
f = sqrt(f);
|
|
204
|
+
|
|
205
|
+
// Output the final color in black and white
|
|
206
|
+
outputColor = vec4(vec3(f), 1.0);
|
|
207
|
+
}
|
|
208
|
+
`,{blendFunction:e,uniforms:new Map([["scale",new s.Uniform(t)],["noiseScale",new s.Uniform(o)],["center",new s.Uniform(l)],["rotation",new s.Uniform(i)]])})}get scale(){var e;return(e=this.uniforms.get("scale"))==null?void 0:e.value}set scale(e){this.uniforms.get("scale").value=e}get noiseScale(){var e;return(e=this.uniforms.get("noiseScale"))==null?void 0:e.value}set noiseScale(e){this.uniforms.get("noiseScale").value=e}get center(){var e;return(e=this.uniforms.get("center"))==null?void 0:e.value}set center(e){this.uniforms.get("center").value=Array.isArray(e)?new s.Vector2().fromArray(e):e}get rotation(){var e;return(e=this.uniforms.get("rotation"))==null?void 0:e.value}set rotation(e){this.uniforms.get("rotation").value=e}}const xe=n.defineComponent({__name:"LinocutPmndrs",props:{blendFunction:{},scale:{},noiseScale:{},center:{},rotation:{}},setup(r,{expose:e}){const t=r,{pass:o,effect:a}=p(()=>new X({...t,center:t.center instanceof s.Vector2?[t.center.x,t.center.y]:t.center}),t);return e({pass:o,effect:a}),b([[()=>t.blendFunction,"blendMode.blendFunction"],[()=>t.scale,"scale"],[()=>t.noiseScale,"noiseScale"],[()=>t.center,"center"],[()=>t.rotation,"rotation"]],a,()=>new X),()=>{}}}),I={name:"CopyShader",uniforms:{tDiffuse:{value:null},opacity:{value:1}},vertexShader:`
|
|
209
|
+
|
|
210
|
+
varying vec2 vUv;
|
|
211
|
+
|
|
212
|
+
void main() {
|
|
213
|
+
|
|
214
|
+
vUv = uv;
|
|
215
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
216
|
+
|
|
217
|
+
}`,fragmentShader:`
|
|
218
|
+
|
|
219
|
+
uniform float opacity;
|
|
220
|
+
|
|
221
|
+
uniform sampler2D tDiffuse;
|
|
222
|
+
|
|
223
|
+
varying vec2 vUv;
|
|
224
|
+
|
|
225
|
+
void main() {
|
|
226
|
+
|
|
227
|
+
vec4 texel = texture2D( tDiffuse, vUv );
|
|
228
|
+
gl_FragColor = opacity * texel;
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
}`};class w{constructor(){this.isPass=!0,this.enabled=!0,this.needsSwap=!0,this.clear=!1,this.renderToScreen=!1}setSize(){}render(){console.error("THREE.Pass: .render() must be implemented in derived pass.")}dispose(){}}const be=new s.OrthographicCamera(-1,1,1,-1,0,1);class Se extends s.BufferGeometry{constructor(){super(),this.setAttribute("position",new s.Float32BufferAttribute([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new s.Float32BufferAttribute([0,2,0,0,2,0],2))}}const we=new Se;class T{constructor(e){this._mesh=new s.Mesh(we,e)}dispose(){this._mesh.geometry.dispose()}render(e){e.render(this._mesh,be)}get material(){return this._mesh.material}set material(e){this._mesh.material=e}}class Ae extends w{constructor(e,t){super(),this.textureID=t!==void 0?t:"tDiffuse",e instanceof s.ShaderMaterial?(this.uniforms=e.uniforms,this.material=e):e&&(this.uniforms=s.UniformsUtils.clone(e.uniforms),this.material=new s.ShaderMaterial({name:e.name!==void 0?e.name:"unspecified",defines:Object.assign({},e.defines),uniforms:this.uniforms,vertexShader:e.vertexShader,fragmentShader:e.fragmentShader})),this.fsQuad=new T(this.material)}render(e,t,o){this.uniforms[this.textureID]&&(this.uniforms[this.textureID].value=o.texture),this.fsQuad.material=this.material,this.renderToScreen?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(t),this.clear&&e.clear(e.autoClearColor,e.autoClearDepth,e.autoClearStencil),this.fsQuad.render(e))}dispose(){this.material.dispose(),this.fsQuad.dispose()}}class j extends w{constructor(e,t){super(),this.scene=e,this.camera=t,this.clear=!0,this.needsSwap=!1,this.inverse=!1}render(e,t,o){const a=e.getContext(),i=e.state;i.buffers.color.setMask(!1),i.buffers.depth.setMask(!1),i.buffers.color.setLocked(!0),i.buffers.depth.setLocked(!0);let l,c;this.inverse?(l=0,c=1):(l=1,c=0),i.buffers.stencil.setTest(!0),i.buffers.stencil.setOp(a.REPLACE,a.REPLACE,a.REPLACE),i.buffers.stencil.setFunc(a.ALWAYS,l,4294967295),i.buffers.stencil.setClear(c),i.buffers.stencil.setLocked(!0),e.setRenderTarget(o),this.clear&&e.clear(),e.render(this.scene,this.camera),e.setRenderTarget(t),this.clear&&e.clear(),e.render(this.scene,this.camera),i.buffers.color.setLocked(!1),i.buffers.depth.setLocked(!1),i.buffers.color.setMask(!0),i.buffers.depth.setMask(!0),i.buffers.stencil.setLocked(!1),i.buffers.stencil.setFunc(a.EQUAL,1,4294967295),i.buffers.stencil.setOp(a.KEEP,a.KEEP,a.KEEP),i.buffers.stencil.setLocked(!0)}}class Te extends w{constructor(){super(),this.needsSwap=!1}render(e){e.state.buffers.stencil.setLocked(!1),e.state.buffers.stencil.setTest(!1)}}class Me{constructor(e,t){if(this.renderer=e,this._pixelRatio=e.getPixelRatio(),t===void 0){const o=e.getSize(new s.Vector2);this._width=o.width,this._height=o.height,t=new s.WebGLRenderTarget(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:s.HalfFloatType}),t.texture.name="EffectComposer.rt1"}else this._width=t.width,this._height=t.height;this.renderTarget1=t,this.renderTarget2=t.clone(),this.renderTarget2.texture.name="EffectComposer.rt2",this.writeBuffer=this.renderTarget1,this.readBuffer=this.renderTarget2,this.renderToScreen=!0,this.passes=[],this.copyPass=new Ae(I),this.copyPass.material.blending=s.NoBlending,this.clock=new s.Clock}swapBuffers(){const e=this.readBuffer;this.readBuffer=this.writeBuffer,this.writeBuffer=e}addPass(e){this.passes.push(e),e.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}insertPass(e,t){this.passes.splice(t,0,e),e.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}removePass(e){const t=this.passes.indexOf(e);t!==-1&&this.passes.splice(t,1)}isLastEnabledPass(e){for(let t=e+1;t<this.passes.length;t++)if(this.passes[t].enabled)return!1;return!0}render(e){e===void 0&&(e=this.clock.getDelta());const t=this.renderer.getRenderTarget();let o=!1;for(let a=0,i=this.passes.length;a<i;a++){const l=this.passes[a];if(l.enabled!==!1){if(l.renderToScreen=this.renderToScreen&&this.isLastEnabledPass(a),l.render(this.renderer,this.writeBuffer,this.readBuffer,e,o),l.needsSwap){if(o){const c=this.renderer.getContext(),d=this.renderer.state.buffers.stencil;d.setFunc(c.NOTEQUAL,1,4294967295),this.copyPass.render(this.renderer,this.writeBuffer,this.readBuffer,e),d.setFunc(c.EQUAL,1,4294967295)}this.swapBuffers()}j!==void 0&&(l instanceof j?o=!0:l instanceof Te&&(o=!1))}}this.renderer.setRenderTarget(t)}reset(e){if(e===void 0){const t=this.renderer.getSize(new s.Vector2);this._pixelRatio=this.renderer.getPixelRatio(),this._width=t.width,this._height=t.height,e=this.renderTarget1.clone(),e.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}this.renderTarget1.dispose(),this.renderTarget2.dispose(),this.renderTarget1=e,this.renderTarget2=e.clone(),this.writeBuffer=this.renderTarget1,this.readBuffer=this.renderTarget2}setSize(e,t){this._width=e,this._height=t;const o=this._width*this._pixelRatio,a=this._height*this._pixelRatio;this.renderTarget1.setSize(o,a),this.renderTarget2.setSize(o,a);for(let i=0;i<this.passes.length;i++)this.passes[i].setSize(o,a)}setPixelRatio(e){this._pixelRatio=e,this.setSize(this._width,this._height)}dispose(){this.renderTarget1.dispose(),this.renderTarget2.dispose(),this.copyPass.dispose()}}class ye extends w{constructor(e,t,o=null,a=null,i=null){super(),this.scene=e,this.camera=t,this.overrideMaterial=o,this.clearColor=a,this.clearAlpha=i,this.clear=!0,this.clearDepth=!1,this.needsSwap=!1,this._oldClearColor=new s.Color}render(e,t,o){const a=e.autoClear;e.autoClear=!1;let i,l;this.overrideMaterial!==null&&(l=this.scene.overrideMaterial,this.scene.overrideMaterial=this.overrideMaterial),this.clearColor!==null&&(e.getClearColor(this._oldClearColor),e.setClearColor(this.clearColor,e.getClearAlpha())),this.clearAlpha!==null&&(i=e.getClearAlpha(),e.setClearAlpha(this.clearAlpha)),this.clearDepth==!0&&e.clearDepth(),e.setRenderTarget(this.renderToScreen?null:o),this.clear===!0&&e.clear(e.autoClearColor,e.autoClearDepth,e.autoClearStencil),e.render(this.scene,this.camera),this.clearColor!==null&&e.setClearColor(this._oldClearColor),this.clearAlpha!==null&&e.setClearAlpha(i),this.overrideMaterial!==null&&(this.scene.overrideMaterial=l),e.autoClear=a}}const Y=Symbol("effectComposerThree"),Ce=n.defineComponent({__name:"EffectComposer",props:{enabled:{type:Boolean,default:!0},withoutRenderPass:{type:Boolean}},setup(r,{expose:e}){const t=r,o=n.shallowRef(null);n.provide(Y,o),e({composer:o});const{renderer:a,sizes:i,scene:l,camera:c,render:d}=g.useTresContext(),S=()=>{var m;(m=o.value)==null||m.dispose(),o.value=new Me(a.value)};n.watchEffect(S),n.watchEffect(()=>{var R;const{width:m,height:A}=i;A.value&&m.value&&((R=o.value)==null||R.setSize(m.value,A.value))});const{pixelRatio:h}=F.useDevicePixelRatio();n.watchEffect(()=>{var m;(m=o.value)==null||m.setPixelRatio(h.value)}),t.withoutRenderPass||n.watchEffect(()=>{c.value&&l.value&&o.value&&o.value.addPass(new ye(l.value,c.value))});const{render:v}=g.useLoop();return v(()=>{d.frames.value>0&&o.value&&t.enabled&&o.value.render(),d.frames.value=d.mode.value==="always"?1:Math.max(0,d.frames.value-1)}),n.onUnmounted(()=>{var m;(m=o.value)==null||m.dispose()}),(m,A)=>n.renderSlot(m.$slots,"default")}}),M=(r,e)=>{const t=n.inject(Y),o=n.shallowRef(r()),{sizes:a,invalidate:i}=g.useTresContext();e&&n.watch(e,()=>i());const l=n.watchEffect(()=>{!(t!=null&&t.value)||!a.height.value||!a.width.value||(t.value.addPass(o.value),n.nextTick(()=>l()))});return n.onUnmounted(()=>{var c;(c=t==null?void 0:t.value)==null||c.removePass(o.value),o.value.dispose()}),{pass:o}},Ee={uniforms:{tDiffuse:{value:null},tDisp:{value:null},byp:{value:0},amount:{value:.08},angle:{value:.02},seed:{value:.02},seed_x:{value:.02},seed_y:{value:.02},distortion_x:{value:.5},distortion_y:{value:.6},col_s:{value:.05}},vertexShader:`
|
|
232
|
+
|
|
233
|
+
varying vec2 vUv;
|
|
234
|
+
void main() {
|
|
235
|
+
vUv = uv;
|
|
236
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
237
|
+
}`,fragmentShader:`
|
|
238
|
+
|
|
239
|
+
uniform int byp; //should we apply the glitch ?
|
|
240
|
+
|
|
241
|
+
uniform sampler2D tDiffuse;
|
|
242
|
+
uniform sampler2D tDisp;
|
|
243
|
+
|
|
244
|
+
uniform float amount;
|
|
245
|
+
uniform float angle;
|
|
246
|
+
uniform float seed;
|
|
247
|
+
uniform float seed_x;
|
|
248
|
+
uniform float seed_y;
|
|
249
|
+
uniform float distortion_x;
|
|
250
|
+
uniform float distortion_y;
|
|
251
|
+
uniform float col_s;
|
|
252
|
+
|
|
253
|
+
varying vec2 vUv;
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
float rand(vec2 co){
|
|
257
|
+
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
void main() {
|
|
261
|
+
if(byp<1) {
|
|
262
|
+
vec2 p = vUv;
|
|
263
|
+
float xs = floor(gl_FragCoord.x / 0.5);
|
|
264
|
+
float ys = floor(gl_FragCoord.y / 0.5);
|
|
265
|
+
//based on staffantans glitch shader for unity https://github.com/staffantan/unityglitch
|
|
266
|
+
float disp = texture2D(tDisp, p*seed*seed).r;
|
|
267
|
+
if(p.y<distortion_x+col_s && p.y>distortion_x-col_s*seed) {
|
|
268
|
+
if(seed_x>0.){
|
|
269
|
+
p.y = 1. - (p.y + distortion_y);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
p.y = distortion_y;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if(p.x<distortion_y+col_s && p.x>distortion_y-col_s*seed) {
|
|
276
|
+
if(seed_y>0.){
|
|
277
|
+
p.x=distortion_x;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
p.x = 1. - (p.x + distortion_x);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
p.x+=disp*seed_x*(seed/5.);
|
|
284
|
+
p.y+=disp*seed_y*(seed/5.);
|
|
285
|
+
//base from RGB shift shader
|
|
286
|
+
vec2 offset = amount * vec2( cos(angle), sin(angle));
|
|
287
|
+
vec4 cr = texture2D(tDiffuse, p + offset);
|
|
288
|
+
vec4 cga = texture2D(tDiffuse, p);
|
|
289
|
+
vec4 cb = texture2D(tDiffuse, p - offset);
|
|
290
|
+
gl_FragColor = vec4(cr.r, cga.g, cb.b, cga.a);
|
|
291
|
+
//add noise
|
|
292
|
+
vec4 snow = 200.*amount*vec4(rand(vec2(xs * seed,ys * seed*50.))*0.2);
|
|
293
|
+
gl_FragColor = gl_FragColor+ snow;
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
gl_FragColor=texture2D (tDiffuse, vUv);
|
|
297
|
+
}
|
|
298
|
+
}`};class q extends w{constructor(e=64){super();const t=Ee;this.uniforms=s.UniformsUtils.clone(t.uniforms),this.heightMap=this.generateHeightmap(e),this.uniforms.tDisp.value=this.heightMap,this.material=new s.ShaderMaterial({uniforms:this.uniforms,vertexShader:t.vertexShader,fragmentShader:t.fragmentShader}),this.fsQuad=new T(this.material),this.goWild=!1,this.curF=0,this.generateTrigger()}render(e,t,o){this.uniforms.tDiffuse.value=o.texture,this.uniforms.seed.value=Math.random(),this.uniforms.byp.value=0,this.curF%this.randX==0||this.goWild==!0?(this.uniforms.amount.value=Math.random()/30,this.uniforms.angle.value=s.MathUtils.randFloat(-Math.PI,Math.PI),this.uniforms.seed_x.value=s.MathUtils.randFloat(-1,1),this.uniforms.seed_y.value=s.MathUtils.randFloat(-1,1),this.uniforms.distortion_x.value=s.MathUtils.randFloat(0,1),this.uniforms.distortion_y.value=s.MathUtils.randFloat(0,1),this.curF=0,this.generateTrigger()):this.curF%this.randX<this.randX/5?(this.uniforms.amount.value=Math.random()/90,this.uniforms.angle.value=s.MathUtils.randFloat(-Math.PI,Math.PI),this.uniforms.distortion_x.value=s.MathUtils.randFloat(0,1),this.uniforms.distortion_y.value=s.MathUtils.randFloat(0,1),this.uniforms.seed_x.value=s.MathUtils.randFloat(-.3,.3),this.uniforms.seed_y.value=s.MathUtils.randFloat(-.3,.3)):this.goWild==!1&&(this.uniforms.byp.value=1),this.curF++,this.renderToScreen?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(t),this.clear&&e.clear(),this.fsQuad.render(e))}generateTrigger(){this.randX=s.MathUtils.randInt(120,240)}generateHeightmap(e){const t=new Float32Array(e*e),o=e*e;for(let i=0;i<o;i++){const l=s.MathUtils.randFloat(0,1);t[i]=l}const a=new s.DataTexture(t,e,e,s.RedFormat,s.FloatType);return a.needsUpdate=!0,a}dispose(){this.material.dispose(),this.heightMap.dispose(),this.fsQuad.dispose()}}const De=n.defineComponent({__name:"Glitch",props:{dtSize:{},goWild:{type:Boolean}},setup(r,{expose:e}){const t=r,{pass:o}=M(()=>new q(t.dtSize),t);e({pass:o});const{onBeforeRender:a}=g.useLoop();return a(({invalidate:i})=>i()),b([[()=>t.goWild,"goWild"]],o,()=>new q),()=>{}}}),D={name:"HalftoneShader",uniforms:{tDiffuse:{value:null},shape:{value:1},radius:{value:4},rotateR:{value:Math.PI/12*1},rotateG:{value:Math.PI/12*2},rotateB:{value:Math.PI/12*3},scatter:{value:0},width:{value:1},height:{value:1},blending:{value:1},blendingMode:{value:1},greyscale:{value:!1},disable:{value:!1}},vertexShader:`
|
|
299
|
+
|
|
300
|
+
varying vec2 vUV;
|
|
301
|
+
|
|
302
|
+
void main() {
|
|
303
|
+
|
|
304
|
+
vUV = uv;
|
|
305
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
306
|
+
|
|
307
|
+
}`,fragmentShader:`
|
|
308
|
+
|
|
309
|
+
#define SQRT2_MINUS_ONE 0.41421356
|
|
310
|
+
#define SQRT2_HALF_MINUS_ONE 0.20710678
|
|
311
|
+
#define PI2 6.28318531
|
|
312
|
+
#define SHAPE_DOT 1
|
|
313
|
+
#define SHAPE_ELLIPSE 2
|
|
314
|
+
#define SHAPE_LINE 3
|
|
315
|
+
#define SHAPE_SQUARE 4
|
|
316
|
+
#define BLENDING_LINEAR 1
|
|
317
|
+
#define BLENDING_MULTIPLY 2
|
|
318
|
+
#define BLENDING_ADD 3
|
|
319
|
+
#define BLENDING_LIGHTER 4
|
|
320
|
+
#define BLENDING_DARKER 5
|
|
321
|
+
uniform sampler2D tDiffuse;
|
|
322
|
+
uniform float radius;
|
|
323
|
+
uniform float rotateR;
|
|
324
|
+
uniform float rotateG;
|
|
325
|
+
uniform float rotateB;
|
|
326
|
+
uniform float scatter;
|
|
327
|
+
uniform float width;
|
|
328
|
+
uniform float height;
|
|
329
|
+
uniform int shape;
|
|
330
|
+
uniform bool disable;
|
|
331
|
+
uniform float blending;
|
|
332
|
+
uniform int blendingMode;
|
|
333
|
+
varying vec2 vUV;
|
|
334
|
+
uniform bool greyscale;
|
|
335
|
+
const int samples = 8;
|
|
336
|
+
|
|
337
|
+
float blend( float a, float b, float t ) {
|
|
338
|
+
|
|
339
|
+
// linear blend
|
|
340
|
+
return a * ( 1.0 - t ) + b * t;
|
|
341
|
+
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
float hypot( float x, float y ) {
|
|
345
|
+
|
|
346
|
+
// vector magnitude
|
|
347
|
+
return sqrt( x * x + y * y );
|
|
348
|
+
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
float rand( vec2 seed ){
|
|
352
|
+
|
|
353
|
+
// get pseudo-random number
|
|
354
|
+
return fract( sin( dot( seed.xy, vec2( 12.9898, 78.233 ) ) ) * 43758.5453 );
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
float distanceToDotRadius( float channel, vec2 coord, vec2 normal, vec2 p, float angle, float rad_max ) {
|
|
359
|
+
|
|
360
|
+
// apply shape-specific transforms
|
|
361
|
+
float dist = hypot( coord.x - p.x, coord.y - p.y );
|
|
362
|
+
float rad = channel;
|
|
363
|
+
|
|
364
|
+
if ( shape == SHAPE_DOT ) {
|
|
365
|
+
|
|
366
|
+
rad = pow( abs( rad ), 1.125 ) * rad_max;
|
|
367
|
+
|
|
368
|
+
} else if ( shape == SHAPE_ELLIPSE ) {
|
|
369
|
+
|
|
370
|
+
rad = pow( abs( rad ), 1.125 ) * rad_max;
|
|
371
|
+
|
|
372
|
+
if ( dist != 0.0 ) {
|
|
373
|
+
float dot_p = abs( ( p.x - coord.x ) / dist * normal.x + ( p.y - coord.y ) / dist * normal.y );
|
|
374
|
+
dist = ( dist * ( 1.0 - SQRT2_HALF_MINUS_ONE ) ) + dot_p * dist * SQRT2_MINUS_ONE;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
} else if ( shape == SHAPE_LINE ) {
|
|
378
|
+
|
|
379
|
+
rad = pow( abs( rad ), 1.5) * rad_max;
|
|
380
|
+
float dot_p = ( p.x - coord.x ) * normal.x + ( p.y - coord.y ) * normal.y;
|
|
381
|
+
dist = hypot( normal.x * dot_p, normal.y * dot_p );
|
|
382
|
+
|
|
383
|
+
} else if ( shape == SHAPE_SQUARE ) {
|
|
384
|
+
|
|
385
|
+
float theta = atan( p.y - coord.y, p.x - coord.x ) - angle;
|
|
386
|
+
float sin_t = abs( sin( theta ) );
|
|
387
|
+
float cos_t = abs( cos( theta ) );
|
|
388
|
+
rad = pow( abs( rad ), 1.4 );
|
|
389
|
+
rad = rad_max * ( rad + ( ( sin_t > cos_t ) ? rad - sin_t * rad : rad - cos_t * rad ) );
|
|
390
|
+
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return rad - dist;
|
|
394
|
+
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
struct Cell {
|
|
398
|
+
|
|
399
|
+
// grid sample positions
|
|
400
|
+
vec2 normal;
|
|
401
|
+
vec2 p1;
|
|
402
|
+
vec2 p2;
|
|
403
|
+
vec2 p3;
|
|
404
|
+
vec2 p4;
|
|
405
|
+
float samp2;
|
|
406
|
+
float samp1;
|
|
407
|
+
float samp3;
|
|
408
|
+
float samp4;
|
|
409
|
+
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
vec4 getSample( vec2 point ) {
|
|
413
|
+
|
|
414
|
+
// multi-sampled point
|
|
415
|
+
vec4 tex = texture2D( tDiffuse, vec2( point.x / width, point.y / height ) );
|
|
416
|
+
float base = rand( vec2( floor( point.x ), floor( point.y ) ) ) * PI2;
|
|
417
|
+
float step = PI2 / float( samples );
|
|
418
|
+
float dist = radius * 0.66;
|
|
419
|
+
|
|
420
|
+
for ( int i = 0; i < samples; ++i ) {
|
|
421
|
+
|
|
422
|
+
float r = base + step * float( i );
|
|
423
|
+
vec2 coord = point + vec2( cos( r ) * dist, sin( r ) * dist );
|
|
424
|
+
tex += texture2D( tDiffuse, vec2( coord.x / width, coord.y / height ) );
|
|
425
|
+
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
tex /= float( samples ) + 1.0;
|
|
429
|
+
return tex;
|
|
430
|
+
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
float getDotColour( Cell c, vec2 p, int channel, float angle, float aa ) {
|
|
434
|
+
|
|
435
|
+
// get colour for given point
|
|
436
|
+
float dist_c_1, dist_c_2, dist_c_3, dist_c_4, res;
|
|
437
|
+
|
|
438
|
+
if ( channel == 0 ) {
|
|
439
|
+
|
|
440
|
+
c.samp1 = getSample( c.p1 ).r;
|
|
441
|
+
c.samp2 = getSample( c.p2 ).r;
|
|
442
|
+
c.samp3 = getSample( c.p3 ).r;
|
|
443
|
+
c.samp4 = getSample( c.p4 ).r;
|
|
444
|
+
|
|
445
|
+
} else if (channel == 1) {
|
|
446
|
+
|
|
447
|
+
c.samp1 = getSample( c.p1 ).g;
|
|
448
|
+
c.samp2 = getSample( c.p2 ).g;
|
|
449
|
+
c.samp3 = getSample( c.p3 ).g;
|
|
450
|
+
c.samp4 = getSample( c.p4 ).g;
|
|
451
|
+
|
|
452
|
+
} else {
|
|
453
|
+
|
|
454
|
+
c.samp1 = getSample( c.p1 ).b;
|
|
455
|
+
c.samp3 = getSample( c.p3 ).b;
|
|
456
|
+
c.samp2 = getSample( c.p2 ).b;
|
|
457
|
+
c.samp4 = getSample( c.p4 ).b;
|
|
458
|
+
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
dist_c_1 = distanceToDotRadius( c.samp1, c.p1, c.normal, p, angle, radius );
|
|
462
|
+
dist_c_2 = distanceToDotRadius( c.samp2, c.p2, c.normal, p, angle, radius );
|
|
463
|
+
dist_c_3 = distanceToDotRadius( c.samp3, c.p3, c.normal, p, angle, radius );
|
|
464
|
+
dist_c_4 = distanceToDotRadius( c.samp4, c.p4, c.normal, p, angle, radius );
|
|
465
|
+
res = ( dist_c_1 > 0.0 ) ? clamp( dist_c_1 / aa, 0.0, 1.0 ) : 0.0;
|
|
466
|
+
res += ( dist_c_2 > 0.0 ) ? clamp( dist_c_2 / aa, 0.0, 1.0 ) : 0.0;
|
|
467
|
+
res += ( dist_c_3 > 0.0 ) ? clamp( dist_c_3 / aa, 0.0, 1.0 ) : 0.0;
|
|
468
|
+
res += ( dist_c_4 > 0.0 ) ? clamp( dist_c_4 / aa, 0.0, 1.0 ) : 0.0;
|
|
469
|
+
res = clamp( res, 0.0, 1.0 );
|
|
470
|
+
|
|
471
|
+
return res;
|
|
472
|
+
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
Cell getReferenceCell( vec2 p, vec2 origin, float grid_angle, float step ) {
|
|
476
|
+
|
|
477
|
+
// get containing cell
|
|
478
|
+
Cell c;
|
|
479
|
+
|
|
480
|
+
// calc grid
|
|
481
|
+
vec2 n = vec2( cos( grid_angle ), sin( grid_angle ) );
|
|
482
|
+
float threshold = step * 0.5;
|
|
483
|
+
float dot_normal = n.x * ( p.x - origin.x ) + n.y * ( p.y - origin.y );
|
|
484
|
+
float dot_line = -n.y * ( p.x - origin.x ) + n.x * ( p.y - origin.y );
|
|
485
|
+
vec2 offset = vec2( n.x * dot_normal, n.y * dot_normal );
|
|
486
|
+
float offset_normal = mod( hypot( offset.x, offset.y ), step );
|
|
487
|
+
float normal_dir = ( dot_normal < 0.0 ) ? 1.0 : -1.0;
|
|
488
|
+
float normal_scale = ( ( offset_normal < threshold ) ? -offset_normal : step - offset_normal ) * normal_dir;
|
|
489
|
+
float offset_line = mod( hypot( ( p.x - offset.x ) - origin.x, ( p.y - offset.y ) - origin.y ), step );
|
|
490
|
+
float line_dir = ( dot_line < 0.0 ) ? 1.0 : -1.0;
|
|
491
|
+
float line_scale = ( ( offset_line < threshold ) ? -offset_line : step - offset_line ) * line_dir;
|
|
492
|
+
|
|
493
|
+
// get closest corner
|
|
494
|
+
c.normal = n;
|
|
495
|
+
c.p1.x = p.x - n.x * normal_scale + n.y * line_scale;
|
|
496
|
+
c.p1.y = p.y - n.y * normal_scale - n.x * line_scale;
|
|
497
|
+
|
|
498
|
+
// scatter
|
|
499
|
+
if ( scatter != 0.0 ) {
|
|
500
|
+
|
|
501
|
+
float off_mag = scatter * threshold * 0.5;
|
|
502
|
+
float off_angle = rand( vec2( floor( c.p1.x ), floor( c.p1.y ) ) ) * PI2;
|
|
503
|
+
c.p1.x += cos( off_angle ) * off_mag;
|
|
504
|
+
c.p1.y += sin( off_angle ) * off_mag;
|
|
505
|
+
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// find corners
|
|
509
|
+
float normal_step = normal_dir * ( ( offset_normal < threshold ) ? step : -step );
|
|
510
|
+
float line_step = line_dir * ( ( offset_line < threshold ) ? step : -step );
|
|
511
|
+
c.p2.x = c.p1.x - n.x * normal_step;
|
|
512
|
+
c.p2.y = c.p1.y - n.y * normal_step;
|
|
513
|
+
c.p3.x = c.p1.x + n.y * line_step;
|
|
514
|
+
c.p3.y = c.p1.y - n.x * line_step;
|
|
515
|
+
c.p4.x = c.p1.x - n.x * normal_step + n.y * line_step;
|
|
516
|
+
c.p4.y = c.p1.y - n.y * normal_step - n.x * line_step;
|
|
517
|
+
|
|
518
|
+
return c;
|
|
519
|
+
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
float blendColour( float a, float b, float t ) {
|
|
523
|
+
|
|
524
|
+
// blend colours
|
|
525
|
+
if ( blendingMode == BLENDING_LINEAR ) {
|
|
526
|
+
return blend( a, b, 1.0 - t );
|
|
527
|
+
} else if ( blendingMode == BLENDING_ADD ) {
|
|
528
|
+
return blend( a, min( 1.0, a + b ), t );
|
|
529
|
+
} else if ( blendingMode == BLENDING_MULTIPLY ) {
|
|
530
|
+
return blend( a, max( 0.0, a * b ), t );
|
|
531
|
+
} else if ( blendingMode == BLENDING_LIGHTER ) {
|
|
532
|
+
return blend( a, max( a, b ), t );
|
|
533
|
+
} else if ( blendingMode == BLENDING_DARKER ) {
|
|
534
|
+
return blend( a, min( a, b ), t );
|
|
535
|
+
} else {
|
|
536
|
+
return blend( a, b, 1.0 - t );
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
void main() {
|
|
542
|
+
|
|
543
|
+
if ( ! disable ) {
|
|
544
|
+
|
|
545
|
+
// setup
|
|
546
|
+
vec2 p = vec2( vUV.x * width, vUV.y * height );
|
|
547
|
+
vec2 origin = vec2( 0, 0 );
|
|
548
|
+
float aa = ( radius < 2.5 ) ? radius * 0.5 : 1.25;
|
|
549
|
+
|
|
550
|
+
// get channel samples
|
|
551
|
+
Cell cell_r = getReferenceCell( p, origin, rotateR, radius );
|
|
552
|
+
Cell cell_g = getReferenceCell( p, origin, rotateG, radius );
|
|
553
|
+
Cell cell_b = getReferenceCell( p, origin, rotateB, radius );
|
|
554
|
+
float r = getDotColour( cell_r, p, 0, rotateR, aa );
|
|
555
|
+
float g = getDotColour( cell_g, p, 1, rotateG, aa );
|
|
556
|
+
float b = getDotColour( cell_b, p, 2, rotateB, aa );
|
|
557
|
+
|
|
558
|
+
// blend with original
|
|
559
|
+
vec4 colour = texture2D( tDiffuse, vUV );
|
|
560
|
+
r = blendColour( r, colour.r, blending );
|
|
561
|
+
g = blendColour( g, colour.g, blending );
|
|
562
|
+
b = blendColour( b, colour.b, blending );
|
|
563
|
+
|
|
564
|
+
if ( greyscale ) {
|
|
565
|
+
r = g = b = (r + b + g) / 3.0;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
gl_FragColor = vec4( r, g, b, 1.0 );
|
|
569
|
+
|
|
570
|
+
} else {
|
|
571
|
+
|
|
572
|
+
gl_FragColor = texture2D( tDiffuse, vUV );
|
|
573
|
+
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
}`};class Pe extends w{constructor(e,t,o){super(),this.uniforms=s.UniformsUtils.clone(D.uniforms),this.material=new s.ShaderMaterial({uniforms:this.uniforms,fragmentShader:D.fragmentShader,vertexShader:D.vertexShader}),this.uniforms.width.value=e,this.uniforms.height.value=t;for(const a in o)o.hasOwnProperty(a)&&this.uniforms.hasOwnProperty(a)&&(this.uniforms[a].value=o[a]);this.fsQuad=new T(this.material)}render(e,t,o){this.material.uniforms.tDiffuse.value=o.texture,this.renderToScreen?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(t),this.clear&&e.clear(),this.fsQuad.render(e))}setSize(e,t){this.uniforms.width.value=e,this.uniforms.height.value=t}dispose(){this.material.dispose(),this.fsQuad.dispose()}}const Le=n.defineComponent({__name:"Halftone",props:{shape:{},radius:{},rotateR:{},rotateG:{},rotateB:{},scatter:{},blending:{},greyscale:{type:Boolean},blendingMode:{}},setup(r,{expose:e}){const t=r,{sizes:o}=g.useTresContext(),a=n.computed(()=>Object.fromEntries(Object.entries(t).filter(([l,c])=>c!==void 0))),{pass:i}=M(()=>new Pe(o.width.value,o.height.value,a.value),t);return e({pass:i}),n.watchEffect(()=>{i.value.setSize(o.width.value,o.height.value)}),n.watchEffect(()=>{Object.entries(t).forEach(([l,c])=>{l in i.value.uniforms&&(i.value.uniforms[l].value=c??D.uniforms[l].value)})}),()=>{}}});class k extends w{constructor(e,t,o,a={}){super(),this.pixelSize=e,this.resolution=new s.Vector2,this.renderResolution=new s.Vector2,this.pixelatedMaterial=this.createPixelatedMaterial(),this.normalMaterial=new s.MeshNormalMaterial,this.fsQuad=new T(this.pixelatedMaterial),this.scene=t,this.camera=o,this.normalEdgeStrength=a.normalEdgeStrength||.3,this.depthEdgeStrength=a.depthEdgeStrength||.4,this.beautyRenderTarget=new s.WebGLRenderTarget,this.beautyRenderTarget.texture.minFilter=s.NearestFilter,this.beautyRenderTarget.texture.magFilter=s.NearestFilter,this.beautyRenderTarget.texture.type=s.HalfFloatType,this.beautyRenderTarget.depthTexture=new s.DepthTexture,this.normalRenderTarget=new s.WebGLRenderTarget,this.normalRenderTarget.texture.minFilter=s.NearestFilter,this.normalRenderTarget.texture.magFilter=s.NearestFilter,this.normalRenderTarget.texture.type=s.HalfFloatType}dispose(){this.beautyRenderTarget.dispose(),this.normalRenderTarget.dispose(),this.pixelatedMaterial.dispose(),this.normalMaterial.dispose(),this.fsQuad.dispose()}setSize(e,t){this.resolution.set(e,t),this.renderResolution.set(e/this.pixelSize|0,t/this.pixelSize|0);const{x:o,y:a}=this.renderResolution;this.beautyRenderTarget.setSize(o,a),this.normalRenderTarget.setSize(o,a),this.fsQuad.material.uniforms.resolution.value.set(o,a,1/o,1/a)}setPixelSize(e){this.pixelSize=e,this.setSize(this.resolution.x,this.resolution.y)}render(e,t){const o=this.fsQuad.material.uniforms;o.normalEdgeStrength.value=this.normalEdgeStrength,o.depthEdgeStrength.value=this.depthEdgeStrength,e.setRenderTarget(this.beautyRenderTarget),e.render(this.scene,this.camera);const a=this.scene.overrideMaterial;e.setRenderTarget(this.normalRenderTarget),this.scene.overrideMaterial=this.normalMaterial,e.render(this.scene,this.camera),this.scene.overrideMaterial=a,o.tDiffuse.value=this.beautyRenderTarget.texture,o.tDepth.value=this.beautyRenderTarget.depthTexture,o.tNormal.value=this.normalRenderTarget.texture,this.renderToScreen?e.setRenderTarget(null):(e.setRenderTarget(t),this.clear&&e.clear()),this.fsQuad.render(e)}createPixelatedMaterial(){return new s.ShaderMaterial({uniforms:{tDiffuse:{value:null},tDepth:{value:null},tNormal:{value:null},resolution:{value:new s.Vector4(this.renderResolution.x,this.renderResolution.y,1/this.renderResolution.x,1/this.renderResolution.y)},normalEdgeStrength:{value:0},depthEdgeStrength:{value:0}},vertexShader:`
|
|
577
|
+
varying vec2 vUv;
|
|
578
|
+
|
|
579
|
+
void main() {
|
|
580
|
+
|
|
581
|
+
vUv = uv;
|
|
582
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
583
|
+
|
|
584
|
+
}
|
|
585
|
+
`,fragmentShader:`
|
|
586
|
+
uniform sampler2D tDiffuse;
|
|
587
|
+
uniform sampler2D tDepth;
|
|
588
|
+
uniform sampler2D tNormal;
|
|
589
|
+
uniform vec4 resolution;
|
|
590
|
+
uniform float normalEdgeStrength;
|
|
591
|
+
uniform float depthEdgeStrength;
|
|
592
|
+
varying vec2 vUv;
|
|
593
|
+
|
|
594
|
+
float getDepth(int x, int y) {
|
|
595
|
+
|
|
596
|
+
return texture2D( tDepth, vUv + vec2(x, y) * resolution.zw ).r;
|
|
597
|
+
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
vec3 getNormal(int x, int y) {
|
|
601
|
+
|
|
602
|
+
return texture2D( tNormal, vUv + vec2(x, y) * resolution.zw ).rgb * 2.0 - 1.0;
|
|
603
|
+
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
float depthEdgeIndicator(float depth, vec3 normal) {
|
|
607
|
+
|
|
608
|
+
float diff = 0.0;
|
|
609
|
+
diff += clamp(getDepth(1, 0) - depth, 0.0, 1.0);
|
|
610
|
+
diff += clamp(getDepth(-1, 0) - depth, 0.0, 1.0);
|
|
611
|
+
diff += clamp(getDepth(0, 1) - depth, 0.0, 1.0);
|
|
612
|
+
diff += clamp(getDepth(0, -1) - depth, 0.0, 1.0);
|
|
613
|
+
return floor(smoothstep(0.01, 0.02, diff) * 2.) / 2.;
|
|
614
|
+
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
float neighborNormalEdgeIndicator(int x, int y, float depth, vec3 normal) {
|
|
618
|
+
|
|
619
|
+
float depthDiff = getDepth(x, y) - depth;
|
|
620
|
+
vec3 neighborNormal = getNormal(x, y);
|
|
621
|
+
|
|
622
|
+
// Edge pixels should yield to faces who's normals are closer to the bias normal.
|
|
623
|
+
vec3 normalEdgeBias = vec3(1., 1., 1.); // This should probably be a parameter.
|
|
624
|
+
float normalDiff = dot(normal - neighborNormal, normalEdgeBias);
|
|
625
|
+
float normalIndicator = clamp(smoothstep(-.01, .01, normalDiff), 0.0, 1.0);
|
|
626
|
+
|
|
627
|
+
// Only the shallower pixel should detect the normal edge.
|
|
628
|
+
float depthIndicator = clamp(sign(depthDiff * .25 + .0025), 0.0, 1.0);
|
|
629
|
+
|
|
630
|
+
return (1.0 - dot(normal, neighborNormal)) * depthIndicator * normalIndicator;
|
|
631
|
+
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
float normalEdgeIndicator(float depth, vec3 normal) {
|
|
635
|
+
|
|
636
|
+
float indicator = 0.0;
|
|
637
|
+
|
|
638
|
+
indicator += neighborNormalEdgeIndicator(0, -1, depth, normal);
|
|
639
|
+
indicator += neighborNormalEdgeIndicator(0, 1, depth, normal);
|
|
640
|
+
indicator += neighborNormalEdgeIndicator(-1, 0, depth, normal);
|
|
641
|
+
indicator += neighborNormalEdgeIndicator(1, 0, depth, normal);
|
|
642
|
+
|
|
643
|
+
return step(0.1, indicator);
|
|
644
|
+
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
void main() {
|
|
648
|
+
|
|
649
|
+
vec4 texel = texture2D( tDiffuse, vUv );
|
|
650
|
+
|
|
651
|
+
float depth = 0.0;
|
|
652
|
+
vec3 normal = vec3(0.0);
|
|
653
|
+
|
|
654
|
+
if (depthEdgeStrength > 0.0 || normalEdgeStrength > 0.0) {
|
|
655
|
+
|
|
656
|
+
depth = getDepth(0, 0);
|
|
657
|
+
normal = getNormal(0, 0);
|
|
658
|
+
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
float dei = 0.0;
|
|
662
|
+
if (depthEdgeStrength > 0.0)
|
|
663
|
+
dei = depthEdgeIndicator(depth, normal);
|
|
664
|
+
|
|
665
|
+
float nei = 0.0;
|
|
666
|
+
if (normalEdgeStrength > 0.0)
|
|
667
|
+
nei = normalEdgeIndicator(depth, normal);
|
|
668
|
+
|
|
669
|
+
float Strength = dei > 0.0 ? (1.0 - depthEdgeStrength * dei) : (1.0 + normalEdgeStrength * nei);
|
|
670
|
+
|
|
671
|
+
gl_FragColor = texel * Strength;
|
|
672
|
+
|
|
673
|
+
}
|
|
674
|
+
`})}}const Re=n.defineComponent({__name:"Pixelation",props:{pixelSize:{},depthEdgeStrength:{},normalEdgeStrength:{}},setup(r,{expose:e}){const t=r,{scene:o,camera:a}=g.useTresContext(),{pass:i}=M(()=>new k(t.pixelSize,o.value,a.value),t);return e({pass:i}),n.watchEffect(()=>{i.value.setPixelSize(t.pixelSize)}),b([[()=>t.depthEdgeStrength,"depthEdgeStrength"],[()=>t.normalEdgeStrength,"normalEdgeStrength"]],i,()=>new k(1,o.value,a.value)),()=>{}}}),Oe={name:"OutputShader",uniforms:{tDiffuse:{value:null},toneMappingExposure:{value:1}},vertexShader:`
|
|
675
|
+
precision highp float;
|
|
676
|
+
|
|
677
|
+
uniform mat4 modelViewMatrix;
|
|
678
|
+
uniform mat4 projectionMatrix;
|
|
679
|
+
|
|
680
|
+
attribute vec3 position;
|
|
681
|
+
attribute vec2 uv;
|
|
682
|
+
|
|
683
|
+
varying vec2 vUv;
|
|
684
|
+
|
|
685
|
+
void main() {
|
|
686
|
+
|
|
687
|
+
vUv = uv;
|
|
688
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
689
|
+
|
|
690
|
+
}`,fragmentShader:`
|
|
691
|
+
|
|
692
|
+
precision highp float;
|
|
693
|
+
|
|
694
|
+
uniform sampler2D tDiffuse;
|
|
695
|
+
|
|
696
|
+
#include <tonemapping_pars_fragment>
|
|
697
|
+
#include <colorspace_pars_fragment>
|
|
698
|
+
|
|
699
|
+
varying vec2 vUv;
|
|
700
|
+
|
|
701
|
+
void main() {
|
|
702
|
+
|
|
703
|
+
gl_FragColor = texture2D( tDiffuse, vUv );
|
|
704
|
+
|
|
705
|
+
// tone mapping
|
|
706
|
+
|
|
707
|
+
#ifdef LINEAR_TONE_MAPPING
|
|
708
|
+
|
|
709
|
+
gl_FragColor.rgb = LinearToneMapping( gl_FragColor.rgb );
|
|
710
|
+
|
|
711
|
+
#elif defined( REINHARD_TONE_MAPPING )
|
|
712
|
+
|
|
713
|
+
gl_FragColor.rgb = ReinhardToneMapping( gl_FragColor.rgb );
|
|
714
|
+
|
|
715
|
+
#elif defined( CINEON_TONE_MAPPING )
|
|
716
|
+
|
|
717
|
+
gl_FragColor.rgb = CineonToneMapping( gl_FragColor.rgb );
|
|
718
|
+
|
|
719
|
+
#elif defined( ACES_FILMIC_TONE_MAPPING )
|
|
720
|
+
|
|
721
|
+
gl_FragColor.rgb = ACESFilmicToneMapping( gl_FragColor.rgb );
|
|
722
|
+
|
|
723
|
+
#elif defined( AGX_TONE_MAPPING )
|
|
724
|
+
|
|
725
|
+
gl_FragColor.rgb = AgXToneMapping( gl_FragColor.rgb );
|
|
726
|
+
|
|
727
|
+
#elif defined( NEUTRAL_TONE_MAPPING )
|
|
728
|
+
|
|
729
|
+
gl_FragColor.rgb = NeutralToneMapping( gl_FragColor.rgb );
|
|
730
|
+
|
|
731
|
+
#endif
|
|
732
|
+
|
|
733
|
+
// color space
|
|
734
|
+
|
|
735
|
+
#ifdef SRGB_TRANSFER
|
|
736
|
+
|
|
737
|
+
gl_FragColor = sRGBTransferOETF( gl_FragColor );
|
|
738
|
+
|
|
739
|
+
#endif
|
|
740
|
+
|
|
741
|
+
}`};class Be extends w{constructor(){super();const e=Oe;this.uniforms=s.UniformsUtils.clone(e.uniforms),this.material=new s.RawShaderMaterial({name:e.name,uniforms:this.uniforms,vertexShader:e.vertexShader,fragmentShader:e.fragmentShader}),this.fsQuad=new T(this.material),this._outputColorSpace=null,this._toneMapping=null}render(e,t,o){this.uniforms.tDiffuse.value=o.texture,this.uniforms.toneMappingExposure.value=e.toneMappingExposure,(this._outputColorSpace!==e.outputColorSpace||this._toneMapping!==e.toneMapping)&&(this._outputColorSpace=e.outputColorSpace,this._toneMapping=e.toneMapping,this.material.defines={},s.ColorManagement.getTransfer(this._outputColorSpace)===s.SRGBTransfer&&(this.material.defines.SRGB_TRANSFER=""),this._toneMapping===s.LinearToneMapping?this.material.defines.LINEAR_TONE_MAPPING="":this._toneMapping===s.ReinhardToneMapping?this.material.defines.REINHARD_TONE_MAPPING="":this._toneMapping===s.CineonToneMapping?this.material.defines.CINEON_TONE_MAPPING="":this._toneMapping===s.ACESFilmicToneMapping?this.material.defines.ACES_FILMIC_TONE_MAPPING="":this._toneMapping===s.AgXToneMapping?this.material.defines.AGX_TONE_MAPPING="":this._toneMapping===s.NeutralToneMapping&&(this.material.defines.NEUTRAL_TONE_MAPPING=""),this.material.needsUpdate=!0),this.renderToScreen===!0?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(t),this.clear&&e.clear(e.autoClearColor,e.autoClearDepth,e.autoClearStencil),this.fsQuad.render(e))}dispose(){this.material.dispose(),this.fsQuad.dispose()}}const Ne=n.defineComponent({__name:"Output",setup(r,{expose:e}){const{pass:t}=M(()=>new Be);return e({pass:t}),()=>{}}}),P={name:"SMAAEdgesShader",defines:{SMAA_THRESHOLD:"0.1"},uniforms:{tDiffuse:{value:null},resolution:{value:new s.Vector2(1/1024,1/512)}},vertexShader:`
|
|
742
|
+
|
|
743
|
+
uniform vec2 resolution;
|
|
744
|
+
|
|
745
|
+
varying vec2 vUv;
|
|
746
|
+
varying vec4 vOffset[ 3 ];
|
|
747
|
+
|
|
748
|
+
void SMAAEdgeDetectionVS( vec2 texcoord ) {
|
|
749
|
+
vOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -1.0, 0.0, 0.0, 1.0 ); // WebGL port note: Changed sign in W component
|
|
750
|
+
vOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( 1.0, 0.0, 0.0, -1.0 ); // WebGL port note: Changed sign in W component
|
|
751
|
+
vOffset[ 2 ] = texcoord.xyxy + resolution.xyxy * vec4( -2.0, 0.0, 0.0, 2.0 ); // WebGL port note: Changed sign in W component
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
void main() {
|
|
755
|
+
|
|
756
|
+
vUv = uv;
|
|
757
|
+
|
|
758
|
+
SMAAEdgeDetectionVS( vUv );
|
|
759
|
+
|
|
760
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
761
|
+
|
|
762
|
+
}`,fragmentShader:`
|
|
763
|
+
|
|
764
|
+
uniform sampler2D tDiffuse;
|
|
765
|
+
|
|
766
|
+
varying vec2 vUv;
|
|
767
|
+
varying vec4 vOffset[ 3 ];
|
|
768
|
+
|
|
769
|
+
vec4 SMAAColorEdgeDetectionPS( vec2 texcoord, vec4 offset[3], sampler2D colorTex ) {
|
|
770
|
+
vec2 threshold = vec2( SMAA_THRESHOLD, SMAA_THRESHOLD );
|
|
771
|
+
|
|
772
|
+
// Calculate color deltas:
|
|
773
|
+
vec4 delta;
|
|
774
|
+
vec3 C = texture2D( colorTex, texcoord ).rgb;
|
|
775
|
+
|
|
776
|
+
vec3 Cleft = texture2D( colorTex, offset[0].xy ).rgb;
|
|
777
|
+
vec3 t = abs( C - Cleft );
|
|
778
|
+
delta.x = max( max( t.r, t.g ), t.b );
|
|
779
|
+
|
|
780
|
+
vec3 Ctop = texture2D( colorTex, offset[0].zw ).rgb;
|
|
781
|
+
t = abs( C - Ctop );
|
|
782
|
+
delta.y = max( max( t.r, t.g ), t.b );
|
|
783
|
+
|
|
784
|
+
// We do the usual threshold:
|
|
785
|
+
vec2 edges = step( threshold, delta.xy );
|
|
786
|
+
|
|
787
|
+
// Then discard if there is no edge:
|
|
788
|
+
if ( dot( edges, vec2( 1.0, 1.0 ) ) == 0.0 )
|
|
789
|
+
discard;
|
|
790
|
+
|
|
791
|
+
// Calculate right and bottom deltas:
|
|
792
|
+
vec3 Cright = texture2D( colorTex, offset[1].xy ).rgb;
|
|
793
|
+
t = abs( C - Cright );
|
|
794
|
+
delta.z = max( max( t.r, t.g ), t.b );
|
|
795
|
+
|
|
796
|
+
vec3 Cbottom = texture2D( colorTex, offset[1].zw ).rgb;
|
|
797
|
+
t = abs( C - Cbottom );
|
|
798
|
+
delta.w = max( max( t.r, t.g ), t.b );
|
|
799
|
+
|
|
800
|
+
// Calculate the maximum delta in the direct neighborhood:
|
|
801
|
+
float maxDelta = max( max( max( delta.x, delta.y ), delta.z ), delta.w );
|
|
802
|
+
|
|
803
|
+
// Calculate left-left and top-top deltas:
|
|
804
|
+
vec3 Cleftleft = texture2D( colorTex, offset[2].xy ).rgb;
|
|
805
|
+
t = abs( C - Cleftleft );
|
|
806
|
+
delta.z = max( max( t.r, t.g ), t.b );
|
|
807
|
+
|
|
808
|
+
vec3 Ctoptop = texture2D( colorTex, offset[2].zw ).rgb;
|
|
809
|
+
t = abs( C - Ctoptop );
|
|
810
|
+
delta.w = max( max( t.r, t.g ), t.b );
|
|
811
|
+
|
|
812
|
+
// Calculate the final maximum delta:
|
|
813
|
+
maxDelta = max( max( maxDelta, delta.z ), delta.w );
|
|
814
|
+
|
|
815
|
+
// Local contrast adaptation in action:
|
|
816
|
+
edges.xy *= step( 0.5 * maxDelta, delta.xy );
|
|
817
|
+
|
|
818
|
+
return vec4( edges, 0.0, 0.0 );
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
void main() {
|
|
822
|
+
|
|
823
|
+
gl_FragColor = SMAAColorEdgeDetectionPS( vUv, vOffset, tDiffuse );
|
|
824
|
+
|
|
825
|
+
}`},L={name:"SMAAWeightsShader",defines:{SMAA_MAX_SEARCH_STEPS:"8",SMAA_AREATEX_MAX_DISTANCE:"16",SMAA_AREATEX_PIXEL_SIZE:"( 1.0 / vec2( 160.0, 560.0 ) )",SMAA_AREATEX_SUBTEX_SIZE:"( 1.0 / 7.0 )"},uniforms:{tDiffuse:{value:null},tArea:{value:null},tSearch:{value:null},resolution:{value:new s.Vector2(1/1024,1/512)}},vertexShader:`
|
|
826
|
+
|
|
827
|
+
uniform vec2 resolution;
|
|
828
|
+
|
|
829
|
+
varying vec2 vUv;
|
|
830
|
+
varying vec4 vOffset[ 3 ];
|
|
831
|
+
varying vec2 vPixcoord;
|
|
832
|
+
|
|
833
|
+
void SMAABlendingWeightCalculationVS( vec2 texcoord ) {
|
|
834
|
+
vPixcoord = texcoord / resolution;
|
|
835
|
+
|
|
836
|
+
// We will use these offsets for the searches later on (see @PSEUDO_GATHER4):
|
|
837
|
+
vOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -0.25, 0.125, 1.25, 0.125 ); // WebGL port note: Changed sign in Y and W components
|
|
838
|
+
vOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( -0.125, 0.25, -0.125, -1.25 ); // WebGL port note: Changed sign in Y and W components
|
|
839
|
+
|
|
840
|
+
// And these for the searches, they indicate the ends of the loops:
|
|
841
|
+
vOffset[ 2 ] = vec4( vOffset[ 0 ].xz, vOffset[ 1 ].yw ) + vec4( -2.0, 2.0, -2.0, 2.0 ) * resolution.xxyy * float( SMAA_MAX_SEARCH_STEPS );
|
|
842
|
+
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
void main() {
|
|
846
|
+
|
|
847
|
+
vUv = uv;
|
|
848
|
+
|
|
849
|
+
SMAABlendingWeightCalculationVS( vUv );
|
|
850
|
+
|
|
851
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
852
|
+
|
|
853
|
+
}`,fragmentShader:`
|
|
854
|
+
|
|
855
|
+
#define SMAASampleLevelZeroOffset( tex, coord, offset ) texture2D( tex, coord + float( offset ) * resolution, 0.0 )
|
|
856
|
+
|
|
857
|
+
uniform sampler2D tDiffuse;
|
|
858
|
+
uniform sampler2D tArea;
|
|
859
|
+
uniform sampler2D tSearch;
|
|
860
|
+
uniform vec2 resolution;
|
|
861
|
+
|
|
862
|
+
varying vec2 vUv;
|
|
863
|
+
varying vec4 vOffset[3];
|
|
864
|
+
varying vec2 vPixcoord;
|
|
865
|
+
|
|
866
|
+
#if __VERSION__ == 100
|
|
867
|
+
vec2 round( vec2 x ) {
|
|
868
|
+
return sign( x ) * floor( abs( x ) + 0.5 );
|
|
869
|
+
}
|
|
870
|
+
#endif
|
|
871
|
+
|
|
872
|
+
float SMAASearchLength( sampler2D searchTex, vec2 e, float bias, float scale ) {
|
|
873
|
+
// Not required if searchTex accesses are set to point:
|
|
874
|
+
// float2 SEARCH_TEX_PIXEL_SIZE = 1.0 / float2(66.0, 33.0);
|
|
875
|
+
// e = float2(bias, 0.0) + 0.5 * SEARCH_TEX_PIXEL_SIZE +
|
|
876
|
+
// e * float2(scale, 1.0) * float2(64.0, 32.0) * SEARCH_TEX_PIXEL_SIZE;
|
|
877
|
+
e.r = bias + e.r * scale;
|
|
878
|
+
return 255.0 * texture2D( searchTex, e, 0.0 ).r;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
float SMAASearchXLeft( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {
|
|
882
|
+
/**
|
|
883
|
+
* @PSEUDO_GATHER4
|
|
884
|
+
* This texcoord has been offset by (-0.25, -0.125) in the vertex shader to
|
|
885
|
+
* sample between edge, thus fetching four edges in a row.
|
|
886
|
+
* Sampling with different offsets in each direction allows to disambiguate
|
|
887
|
+
* which edges are active from the four fetched ones.
|
|
888
|
+
*/
|
|
889
|
+
vec2 e = vec2( 0.0, 1.0 );
|
|
890
|
+
|
|
891
|
+
for ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for
|
|
892
|
+
e = texture2D( edgesTex, texcoord, 0.0 ).rg;
|
|
893
|
+
texcoord -= vec2( 2.0, 0.0 ) * resolution;
|
|
894
|
+
if ( ! ( texcoord.x > end && e.g > 0.8281 && e.r == 0.0 ) ) break;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// We correct the previous (-0.25, -0.125) offset we applied:
|
|
898
|
+
texcoord.x += 0.25 * resolution.x;
|
|
899
|
+
|
|
900
|
+
// The searches are bias by 1, so adjust the coords accordingly:
|
|
901
|
+
texcoord.x += resolution.x;
|
|
902
|
+
|
|
903
|
+
// Disambiguate the length added by the last step:
|
|
904
|
+
texcoord.x += 2.0 * resolution.x; // Undo last step
|
|
905
|
+
texcoord.x -= resolution.x * SMAASearchLength(searchTex, e, 0.0, 0.5);
|
|
906
|
+
|
|
907
|
+
return texcoord.x;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
float SMAASearchXRight( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {
|
|
911
|
+
vec2 e = vec2( 0.0, 1.0 );
|
|
912
|
+
|
|
913
|
+
for ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for
|
|
914
|
+
e = texture2D( edgesTex, texcoord, 0.0 ).rg;
|
|
915
|
+
texcoord += vec2( 2.0, 0.0 ) * resolution;
|
|
916
|
+
if ( ! ( texcoord.x < end && e.g > 0.8281 && e.r == 0.0 ) ) break;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
texcoord.x -= 0.25 * resolution.x;
|
|
920
|
+
texcoord.x -= resolution.x;
|
|
921
|
+
texcoord.x -= 2.0 * resolution.x;
|
|
922
|
+
texcoord.x += resolution.x * SMAASearchLength( searchTex, e, 0.5, 0.5 );
|
|
923
|
+
|
|
924
|
+
return texcoord.x;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
float SMAASearchYUp( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {
|
|
928
|
+
vec2 e = vec2( 1.0, 0.0 );
|
|
929
|
+
|
|
930
|
+
for ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for
|
|
931
|
+
e = texture2D( edgesTex, texcoord, 0.0 ).rg;
|
|
932
|
+
texcoord += vec2( 0.0, 2.0 ) * resolution; // WebGL port note: Changed sign
|
|
933
|
+
if ( ! ( texcoord.y > end && e.r > 0.8281 && e.g == 0.0 ) ) break;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
texcoord.y -= 0.25 * resolution.y; // WebGL port note: Changed sign
|
|
937
|
+
texcoord.y -= resolution.y; // WebGL port note: Changed sign
|
|
938
|
+
texcoord.y -= 2.0 * resolution.y; // WebGL port note: Changed sign
|
|
939
|
+
texcoord.y += resolution.y * SMAASearchLength( searchTex, e.gr, 0.0, 0.5 ); // WebGL port note: Changed sign
|
|
940
|
+
|
|
941
|
+
return texcoord.y;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
float SMAASearchYDown( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {
|
|
945
|
+
vec2 e = vec2( 1.0, 0.0 );
|
|
946
|
+
|
|
947
|
+
for ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for
|
|
948
|
+
e = texture2D( edgesTex, texcoord, 0.0 ).rg;
|
|
949
|
+
texcoord -= vec2( 0.0, 2.0 ) * resolution; // WebGL port note: Changed sign
|
|
950
|
+
if ( ! ( texcoord.y < end && e.r > 0.8281 && e.g == 0.0 ) ) break;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
texcoord.y += 0.25 * resolution.y; // WebGL port note: Changed sign
|
|
954
|
+
texcoord.y += resolution.y; // WebGL port note: Changed sign
|
|
955
|
+
texcoord.y += 2.0 * resolution.y; // WebGL port note: Changed sign
|
|
956
|
+
texcoord.y -= resolution.y * SMAASearchLength( searchTex, e.gr, 0.5, 0.5 ); // WebGL port note: Changed sign
|
|
957
|
+
|
|
958
|
+
return texcoord.y;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
vec2 SMAAArea( sampler2D areaTex, vec2 dist, float e1, float e2, float offset ) {
|
|
962
|
+
// Rounding prevents precision errors of bilinear filtering:
|
|
963
|
+
vec2 texcoord = float( SMAA_AREATEX_MAX_DISTANCE ) * round( 4.0 * vec2( e1, e2 ) ) + dist;
|
|
964
|
+
|
|
965
|
+
// We do a scale and bias for mapping to texel space:
|
|
966
|
+
texcoord = SMAA_AREATEX_PIXEL_SIZE * texcoord + ( 0.5 * SMAA_AREATEX_PIXEL_SIZE );
|
|
967
|
+
|
|
968
|
+
// Move to proper place, according to the subpixel offset:
|
|
969
|
+
texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;
|
|
970
|
+
|
|
971
|
+
return texture2D( areaTex, texcoord, 0.0 ).rg;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
vec4 SMAABlendingWeightCalculationPS( vec2 texcoord, vec2 pixcoord, vec4 offset[ 3 ], sampler2D edgesTex, sampler2D areaTex, sampler2D searchTex, ivec4 subsampleIndices ) {
|
|
975
|
+
vec4 weights = vec4( 0.0, 0.0, 0.0, 0.0 );
|
|
976
|
+
|
|
977
|
+
vec2 e = texture2D( edgesTex, texcoord ).rg;
|
|
978
|
+
|
|
979
|
+
if ( e.g > 0.0 ) { // Edge at north
|
|
980
|
+
vec2 d;
|
|
981
|
+
|
|
982
|
+
// Find the distance to the left:
|
|
983
|
+
vec2 coords;
|
|
984
|
+
coords.x = SMAASearchXLeft( edgesTex, searchTex, offset[ 0 ].xy, offset[ 2 ].x );
|
|
985
|
+
coords.y = offset[ 1 ].y; // offset[1].y = texcoord.y - 0.25 * resolution.y (@CROSSING_OFFSET)
|
|
986
|
+
d.x = coords.x;
|
|
987
|
+
|
|
988
|
+
// Now fetch the left crossing edges, two at a time using bilinear
|
|
989
|
+
// filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to
|
|
990
|
+
// discern what value each edge has:
|
|
991
|
+
float e1 = texture2D( edgesTex, coords, 0.0 ).r;
|
|
992
|
+
|
|
993
|
+
// Find the distance to the right:
|
|
994
|
+
coords.x = SMAASearchXRight( edgesTex, searchTex, offset[ 0 ].zw, offset[ 2 ].y );
|
|
995
|
+
d.y = coords.x;
|
|
996
|
+
|
|
997
|
+
// We want the distances to be in pixel units (doing this here allow to
|
|
998
|
+
// better interleave arithmetic and memory accesses):
|
|
999
|
+
d = d / resolution.x - pixcoord.x;
|
|
1000
|
+
|
|
1001
|
+
// SMAAArea below needs a sqrt, as the areas texture is compressed
|
|
1002
|
+
// quadratically:
|
|
1003
|
+
vec2 sqrt_d = sqrt( abs( d ) );
|
|
1004
|
+
|
|
1005
|
+
// Fetch the right crossing edges:
|
|
1006
|
+
coords.y -= 1.0 * resolution.y; // WebGL port note: Added
|
|
1007
|
+
float e2 = SMAASampleLevelZeroOffset( edgesTex, coords, ivec2( 1, 0 ) ).r;
|
|
1008
|
+
|
|
1009
|
+
// Ok, we know how this pattern looks like, now it is time for getting
|
|
1010
|
+
// the actual area:
|
|
1011
|
+
weights.rg = SMAAArea( areaTex, sqrt_d, e1, e2, float( subsampleIndices.y ) );
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
if ( e.r > 0.0 ) { // Edge at west
|
|
1015
|
+
vec2 d;
|
|
1016
|
+
|
|
1017
|
+
// Find the distance to the top:
|
|
1018
|
+
vec2 coords;
|
|
1019
|
+
|
|
1020
|
+
coords.y = SMAASearchYUp( edgesTex, searchTex, offset[ 1 ].xy, offset[ 2 ].z );
|
|
1021
|
+
coords.x = offset[ 0 ].x; // offset[1].x = texcoord.x - 0.25 * resolution.x;
|
|
1022
|
+
d.x = coords.y;
|
|
1023
|
+
|
|
1024
|
+
// Fetch the top crossing edges:
|
|
1025
|
+
float e1 = texture2D( edgesTex, coords, 0.0 ).g;
|
|
1026
|
+
|
|
1027
|
+
// Find the distance to the bottom:
|
|
1028
|
+
coords.y = SMAASearchYDown( edgesTex, searchTex, offset[ 1 ].zw, offset[ 2 ].w );
|
|
1029
|
+
d.y = coords.y;
|
|
1030
|
+
|
|
1031
|
+
// We want the distances to be in pixel units:
|
|
1032
|
+
d = d / resolution.y - pixcoord.y;
|
|
1033
|
+
|
|
1034
|
+
// SMAAArea below needs a sqrt, as the areas texture is compressed
|
|
1035
|
+
// quadratically:
|
|
1036
|
+
vec2 sqrt_d = sqrt( abs( d ) );
|
|
1037
|
+
|
|
1038
|
+
// Fetch the bottom crossing edges:
|
|
1039
|
+
coords.y -= 1.0 * resolution.y; // WebGL port note: Added
|
|
1040
|
+
float e2 = SMAASampleLevelZeroOffset( edgesTex, coords, ivec2( 0, 1 ) ).g;
|
|
1041
|
+
|
|
1042
|
+
// Get the area for this direction:
|
|
1043
|
+
weights.ba = SMAAArea( areaTex, sqrt_d, e1, e2, float( subsampleIndices.x ) );
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
return weights;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
void main() {
|
|
1050
|
+
|
|
1051
|
+
gl_FragColor = SMAABlendingWeightCalculationPS( vUv, vPixcoord, vOffset, tDiffuse, tArea, tSearch, ivec4( 0.0 ) );
|
|
1052
|
+
|
|
1053
|
+
}`},N={name:"SMAABlendShader",uniforms:{tDiffuse:{value:null},tColor:{value:null},resolution:{value:new s.Vector2(1/1024,1/512)}},vertexShader:`
|
|
1054
|
+
|
|
1055
|
+
uniform vec2 resolution;
|
|
1056
|
+
|
|
1057
|
+
varying vec2 vUv;
|
|
1058
|
+
varying vec4 vOffset[ 2 ];
|
|
1059
|
+
|
|
1060
|
+
void SMAANeighborhoodBlendingVS( vec2 texcoord ) {
|
|
1061
|
+
vOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -1.0, 0.0, 0.0, 1.0 ); // WebGL port note: Changed sign in W component
|
|
1062
|
+
vOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( 1.0, 0.0, 0.0, -1.0 ); // WebGL port note: Changed sign in W component
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
void main() {
|
|
1066
|
+
|
|
1067
|
+
vUv = uv;
|
|
1068
|
+
|
|
1069
|
+
SMAANeighborhoodBlendingVS( vUv );
|
|
1070
|
+
|
|
1071
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
1072
|
+
|
|
1073
|
+
}`,fragmentShader:`
|
|
1074
|
+
|
|
1075
|
+
uniform sampler2D tDiffuse;
|
|
1076
|
+
uniform sampler2D tColor;
|
|
1077
|
+
uniform vec2 resolution;
|
|
1078
|
+
|
|
1079
|
+
varying vec2 vUv;
|
|
1080
|
+
varying vec4 vOffset[ 2 ];
|
|
1081
|
+
|
|
1082
|
+
vec4 SMAANeighborhoodBlendingPS( vec2 texcoord, vec4 offset[ 2 ], sampler2D colorTex, sampler2D blendTex ) {
|
|
1083
|
+
// Fetch the blending weights for current pixel:
|
|
1084
|
+
vec4 a;
|
|
1085
|
+
a.xz = texture2D( blendTex, texcoord ).xz;
|
|
1086
|
+
a.y = texture2D( blendTex, offset[ 1 ].zw ).g;
|
|
1087
|
+
a.w = texture2D( blendTex, offset[ 1 ].xy ).a;
|
|
1088
|
+
|
|
1089
|
+
// Is there any blending weight with a value greater than 0.0?
|
|
1090
|
+
if ( dot(a, vec4( 1.0, 1.0, 1.0, 1.0 )) < 1e-5 ) {
|
|
1091
|
+
return texture2D( colorTex, texcoord, 0.0 );
|
|
1092
|
+
} else {
|
|
1093
|
+
// Up to 4 lines can be crossing a pixel (one through each edge). We
|
|
1094
|
+
// favor blending by choosing the line with the maximum weight for each
|
|
1095
|
+
// direction:
|
|
1096
|
+
vec2 offset;
|
|
1097
|
+
offset.x = a.a > a.b ? a.a : -a.b; // left vs. right
|
|
1098
|
+
offset.y = a.g > a.r ? -a.g : a.r; // top vs. bottom // WebGL port note: Changed signs
|
|
1099
|
+
|
|
1100
|
+
// Then we go in the direction that has the maximum weight:
|
|
1101
|
+
if ( abs( offset.x ) > abs( offset.y )) { // horizontal vs. vertical
|
|
1102
|
+
offset.y = 0.0;
|
|
1103
|
+
} else {
|
|
1104
|
+
offset.x = 0.0;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Fetch the opposite color and lerp by hand:
|
|
1108
|
+
vec4 C = texture2D( colorTex, texcoord, 0.0 );
|
|
1109
|
+
texcoord += sign( offset ) * resolution;
|
|
1110
|
+
vec4 Cop = texture2D( colorTex, texcoord, 0.0 );
|
|
1111
|
+
float s = abs( offset.x ) > abs( offset.y ) ? abs( offset.x ) : abs( offset.y );
|
|
1112
|
+
|
|
1113
|
+
// WebGL port note: Added gamma correction
|
|
1114
|
+
C.xyz = pow(C.xyz, vec3(2.2));
|
|
1115
|
+
Cop.xyz = pow(Cop.xyz, vec3(2.2));
|
|
1116
|
+
vec4 mixed = mix(C, Cop, s);
|
|
1117
|
+
mixed.xyz = pow(mixed.xyz, vec3(1.0 / 2.2));
|
|
1118
|
+
|
|
1119
|
+
return mixed;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
void main() {
|
|
1124
|
+
|
|
1125
|
+
gl_FragColor = SMAANeighborhoodBlendingPS( vUv, vOffset, tColor, tDiffuse );
|
|
1126
|
+
|
|
1127
|
+
}`};class Fe extends w{constructor(e,t){super(),this.edgesRT=new s.WebGLRenderTarget(e,t,{depthBuffer:!1,type:s.HalfFloatType}),this.edgesRT.texture.name="SMAAPass.edges",this.weightsRT=new s.WebGLRenderTarget(e,t,{depthBuffer:!1,type:s.HalfFloatType}),this.weightsRT.texture.name="SMAAPass.weights";const o=this,a=new Image;a.src=this.getAreaTexture(),a.onload=function(){o.areaTexture.needsUpdate=!0},this.areaTexture=new s.Texture,this.areaTexture.name="SMAAPass.area",this.areaTexture.image=a,this.areaTexture.minFilter=s.LinearFilter,this.areaTexture.generateMipmaps=!1,this.areaTexture.flipY=!1;const i=new Image;i.src=this.getSearchTexture(),i.onload=function(){o.searchTexture.needsUpdate=!0},this.searchTexture=new s.Texture,this.searchTexture.name="SMAAPass.search",this.searchTexture.image=i,this.searchTexture.magFilter=s.NearestFilter,this.searchTexture.minFilter=s.NearestFilter,this.searchTexture.generateMipmaps=!1,this.searchTexture.flipY=!1,this.uniformsEdges=s.UniformsUtils.clone(P.uniforms),this.uniformsEdges.resolution.value.set(1/e,1/t),this.materialEdges=new s.ShaderMaterial({defines:Object.assign({},P.defines),uniforms:this.uniformsEdges,vertexShader:P.vertexShader,fragmentShader:P.fragmentShader}),this.uniformsWeights=s.UniformsUtils.clone(L.uniforms),this.uniformsWeights.resolution.value.set(1/e,1/t),this.uniformsWeights.tDiffuse.value=this.edgesRT.texture,this.uniformsWeights.tArea.value=this.areaTexture,this.uniformsWeights.tSearch.value=this.searchTexture,this.materialWeights=new s.ShaderMaterial({defines:Object.assign({},L.defines),uniforms:this.uniformsWeights,vertexShader:L.vertexShader,fragmentShader:L.fragmentShader}),this.uniformsBlend=s.UniformsUtils.clone(N.uniforms),this.uniformsBlend.resolution.value.set(1/e,1/t),this.uniformsBlend.tDiffuse.value=this.weightsRT.texture,this.materialBlend=new s.ShaderMaterial({uniforms:this.uniformsBlend,vertexShader:N.vertexShader,fragmentShader:N.fragmentShader}),this.fsQuad=new T(null)}render(e,t,o){this.uniformsEdges.tDiffuse.value=o.texture,this.fsQuad.material=this.materialEdges,e.setRenderTarget(this.edgesRT),this.clear&&e.clear(),this.fsQuad.render(e),this.fsQuad.material=this.materialWeights,e.setRenderTarget(this.weightsRT),this.clear&&e.clear(),this.fsQuad.render(e),this.uniformsBlend.tColor.value=o.texture,this.fsQuad.material=this.materialBlend,this.renderToScreen?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(t),this.clear&&e.clear(),this.fsQuad.render(e))}setSize(e,t){this.edgesRT.setSize(e,t),this.weightsRT.setSize(e,t),this.materialEdges.uniforms.resolution.value.set(1/e,1/t),this.materialWeights.uniforms.resolution.value.set(1/e,1/t),this.materialBlend.uniforms.resolution.value.set(1/e,1/t)}getAreaTexture(){return"data:image/png;base64,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"}getSearchTexture(){return"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAAAhCAAAAABIXyLAAAAAOElEQVRIx2NgGAWjYBSMglEwEICREYRgFBZBqDCSLA2MGPUIVQETE9iNUAqLR5gIeoQKRgwXjwAAGn4AtaFeYLEAAAAASUVORK5CYII="}dispose(){this.edgesRT.dispose(),this.weightsRT.dispose(),this.areaTexture.dispose(),this.searchTexture.dispose(),this.materialEdges.dispose(),this.materialWeights.dispose(),this.materialBlend.dispose(),this.fsQuad.dispose()}}const ze=n.defineComponent({__name:"SMAA",props:{width:{},height:{}},setup(r,{expose:e}){const t=r,{sizes:o}=g.useTresContext(),{pixelRatio:a}=F.useDevicePixelRatio(),i=n.computed(()=>t.width??o.width.value*a.value),l=n.computed(()=>t.height??o.height.value*a.value),{pass:c}=M(()=>new Fe(i.value,l.value),t);return e({pass:c}),n.watchEffect(()=>{c.value.setSize(i.value,l.value)}),()=>{}}}),Q={name:"LuminosityHighPassShader",shaderID:"luminosityHighPass",uniforms:{tDiffuse:{value:null},luminosityThreshold:{value:1},smoothWidth:{value:1},defaultColor:{value:new s.Color(0)},defaultOpacity:{value:0}},vertexShader:`
|
|
1128
|
+
|
|
1129
|
+
varying vec2 vUv;
|
|
1130
|
+
|
|
1131
|
+
void main() {
|
|
1132
|
+
|
|
1133
|
+
vUv = uv;
|
|
1134
|
+
|
|
1135
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
1136
|
+
|
|
1137
|
+
}`,fragmentShader:`
|
|
1138
|
+
|
|
1139
|
+
uniform sampler2D tDiffuse;
|
|
1140
|
+
uniform vec3 defaultColor;
|
|
1141
|
+
uniform float defaultOpacity;
|
|
1142
|
+
uniform float luminosityThreshold;
|
|
1143
|
+
uniform float smoothWidth;
|
|
1144
|
+
|
|
1145
|
+
varying vec2 vUv;
|
|
1146
|
+
|
|
1147
|
+
void main() {
|
|
1148
|
+
|
|
1149
|
+
vec4 texel = texture2D( tDiffuse, vUv );
|
|
1150
|
+
|
|
1151
|
+
float v = luminance( texel.xyz );
|
|
1152
|
+
|
|
1153
|
+
vec4 outputColor = vec4( defaultColor.rgb, defaultOpacity );
|
|
1154
|
+
|
|
1155
|
+
float alpha = smoothstep( luminosityThreshold, luminosityThreshold + smoothWidth, v );
|
|
1156
|
+
|
|
1157
|
+
gl_FragColor = mix( outputColor, texel, alpha );
|
|
1158
|
+
|
|
1159
|
+
}`};class y extends w{constructor(e,t,o,a){super(),this.strength=t!==void 0?t:1,this.radius=o,this.threshold=a,this.resolution=e!==void 0?new s.Vector2(e.x,e.y):new s.Vector2(256,256),this.clearColor=new s.Color(0,0,0),this.renderTargetsHorizontal=[],this.renderTargetsVertical=[],this.nMips=5;let i=Math.round(this.resolution.x/2),l=Math.round(this.resolution.y/2);this.renderTargetBright=new s.WebGLRenderTarget(i,l,{type:s.HalfFloatType}),this.renderTargetBright.texture.name="UnrealBloomPass.bright",this.renderTargetBright.texture.generateMipmaps=!1;for(let v=0;v<this.nMips;v++){const m=new s.WebGLRenderTarget(i,l,{type:s.HalfFloatType});m.texture.name="UnrealBloomPass.h"+v,m.texture.generateMipmaps=!1,this.renderTargetsHorizontal.push(m);const A=new s.WebGLRenderTarget(i,l,{type:s.HalfFloatType});A.texture.name="UnrealBloomPass.v"+v,A.texture.generateMipmaps=!1,this.renderTargetsVertical.push(A),i=Math.round(i/2),l=Math.round(l/2)}const c=Q;this.highPassUniforms=s.UniformsUtils.clone(c.uniforms),this.highPassUniforms.luminosityThreshold.value=a,this.highPassUniforms.smoothWidth.value=.01,this.materialHighPassFilter=new s.ShaderMaterial({uniforms:this.highPassUniforms,vertexShader:c.vertexShader,fragmentShader:c.fragmentShader}),this.separableBlurMaterials=[];const d=[3,5,7,9,11];i=Math.round(this.resolution.x/2),l=Math.round(this.resolution.y/2);for(let v=0;v<this.nMips;v++)this.separableBlurMaterials.push(this.getSeparableBlurMaterial(d[v])),this.separableBlurMaterials[v].uniforms.invSize.value=new s.Vector2(1/i,1/l),i=Math.round(i/2),l=Math.round(l/2);this.compositeMaterial=this.getCompositeMaterial(this.nMips),this.compositeMaterial.uniforms.blurTexture1.value=this.renderTargetsVertical[0].texture,this.compositeMaterial.uniforms.blurTexture2.value=this.renderTargetsVertical[1].texture,this.compositeMaterial.uniforms.blurTexture3.value=this.renderTargetsVertical[2].texture,this.compositeMaterial.uniforms.blurTexture4.value=this.renderTargetsVertical[3].texture,this.compositeMaterial.uniforms.blurTexture5.value=this.renderTargetsVertical[4].texture,this.compositeMaterial.uniforms.bloomStrength.value=t,this.compositeMaterial.uniforms.bloomRadius.value=.1;const S=[1,.8,.6,.4,.2];this.compositeMaterial.uniforms.bloomFactors.value=S,this.bloomTintColors=[new s.Vector3(1,1,1),new s.Vector3(1,1,1),new s.Vector3(1,1,1),new s.Vector3(1,1,1),new s.Vector3(1,1,1)],this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors;const h=I;this.copyUniforms=s.UniformsUtils.clone(h.uniforms),this.blendMaterial=new s.ShaderMaterial({uniforms:this.copyUniforms,vertexShader:h.vertexShader,fragmentShader:h.fragmentShader,blending:s.AdditiveBlending,depthTest:!1,depthWrite:!1,transparent:!0}),this.enabled=!0,this.needsSwap=!1,this._oldClearColor=new s.Color,this.oldClearAlpha=1,this.basic=new s.MeshBasicMaterial,this.fsQuad=new T(null)}dispose(){for(let e=0;e<this.renderTargetsHorizontal.length;e++)this.renderTargetsHorizontal[e].dispose();for(let e=0;e<this.renderTargetsVertical.length;e++)this.renderTargetsVertical[e].dispose();this.renderTargetBright.dispose();for(let e=0;e<this.separableBlurMaterials.length;e++)this.separableBlurMaterials[e].dispose();this.compositeMaterial.dispose(),this.blendMaterial.dispose(),this.basic.dispose(),this.fsQuad.dispose()}setSize(e,t){let o=Math.round(e/2),a=Math.round(t/2);this.renderTargetBright.setSize(o,a);for(let i=0;i<this.nMips;i++)this.renderTargetsHorizontal[i].setSize(o,a),this.renderTargetsVertical[i].setSize(o,a),this.separableBlurMaterials[i].uniforms.invSize.value=new s.Vector2(1/o,1/a),o=Math.round(o/2),a=Math.round(a/2)}render(e,t,o,a,i){e.getClearColor(this._oldClearColor),this.oldClearAlpha=e.getClearAlpha();const l=e.autoClear;e.autoClear=!1,e.setClearColor(this.clearColor,0),i&&e.state.buffers.stencil.setTest(!1),this.renderToScreen&&(this.fsQuad.material=this.basic,this.basic.map=o.texture,e.setRenderTarget(null),e.clear(),this.fsQuad.render(e)),this.highPassUniforms.tDiffuse.value=o.texture,this.highPassUniforms.luminosityThreshold.value=this.threshold,this.fsQuad.material=this.materialHighPassFilter,e.setRenderTarget(this.renderTargetBright),e.clear(),this.fsQuad.render(e);let c=this.renderTargetBright;for(let d=0;d<this.nMips;d++)this.fsQuad.material=this.separableBlurMaterials[d],this.separableBlurMaterials[d].uniforms.colorTexture.value=c.texture,this.separableBlurMaterials[d].uniforms.direction.value=y.BlurDirectionX,e.setRenderTarget(this.renderTargetsHorizontal[d]),e.clear(),this.fsQuad.render(e),this.separableBlurMaterials[d].uniforms.colorTexture.value=this.renderTargetsHorizontal[d].texture,this.separableBlurMaterials[d].uniforms.direction.value=y.BlurDirectionY,e.setRenderTarget(this.renderTargetsVertical[d]),e.clear(),this.fsQuad.render(e),c=this.renderTargetsVertical[d];this.fsQuad.material=this.compositeMaterial,this.compositeMaterial.uniforms.bloomStrength.value=this.strength,this.compositeMaterial.uniforms.bloomRadius.value=this.radius,this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors,e.setRenderTarget(this.renderTargetsHorizontal[0]),e.clear(),this.fsQuad.render(e),this.fsQuad.material=this.blendMaterial,this.copyUniforms.tDiffuse.value=this.renderTargetsHorizontal[0].texture,i&&e.state.buffers.stencil.setTest(!0),this.renderToScreen?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(o),this.fsQuad.render(e)),e.setClearColor(this._oldClearColor,this.oldClearAlpha),e.autoClear=l}getSeparableBlurMaterial(e){const t=[];for(let o=0;o<e;o++)t.push(.39894*Math.exp(-.5*o*o/(e*e))/e);return new s.ShaderMaterial({defines:{KERNEL_RADIUS:e},uniforms:{colorTexture:{value:null},invSize:{value:new s.Vector2(.5,.5)},direction:{value:new s.Vector2(.5,.5)},gaussianCoefficients:{value:t}},vertexShader:`varying vec2 vUv;
|
|
1160
|
+
void main() {
|
|
1161
|
+
vUv = uv;
|
|
1162
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
1163
|
+
}`,fragmentShader:`#include <common>
|
|
1164
|
+
varying vec2 vUv;
|
|
1165
|
+
uniform sampler2D colorTexture;
|
|
1166
|
+
uniform vec2 invSize;
|
|
1167
|
+
uniform vec2 direction;
|
|
1168
|
+
uniform float gaussianCoefficients[KERNEL_RADIUS];
|
|
1169
|
+
|
|
1170
|
+
void main() {
|
|
1171
|
+
float weightSum = gaussianCoefficients[0];
|
|
1172
|
+
vec3 diffuseSum = texture2D( colorTexture, vUv ).rgb * weightSum;
|
|
1173
|
+
for( int i = 1; i < KERNEL_RADIUS; i ++ ) {
|
|
1174
|
+
float x = float(i);
|
|
1175
|
+
float w = gaussianCoefficients[i];
|
|
1176
|
+
vec2 uvOffset = direction * invSize * x;
|
|
1177
|
+
vec3 sample1 = texture2D( colorTexture, vUv + uvOffset ).rgb;
|
|
1178
|
+
vec3 sample2 = texture2D( colorTexture, vUv - uvOffset ).rgb;
|
|
1179
|
+
diffuseSum += (sample1 + sample2) * w;
|
|
1180
|
+
weightSum += 2.0 * w;
|
|
1181
|
+
}
|
|
1182
|
+
gl_FragColor = vec4(diffuseSum/weightSum, 1.0);
|
|
1183
|
+
}`})}getCompositeMaterial(e){return new s.ShaderMaterial({defines:{NUM_MIPS:e},uniforms:{blurTexture1:{value:null},blurTexture2:{value:null},blurTexture3:{value:null},blurTexture4:{value:null},blurTexture5:{value:null},bloomStrength:{value:1},bloomFactors:{value:null},bloomTintColors:{value:null},bloomRadius:{value:0}},vertexShader:`varying vec2 vUv;
|
|
1184
|
+
void main() {
|
|
1185
|
+
vUv = uv;
|
|
1186
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
1187
|
+
}`,fragmentShader:`varying vec2 vUv;
|
|
1188
|
+
uniform sampler2D blurTexture1;
|
|
1189
|
+
uniform sampler2D blurTexture2;
|
|
1190
|
+
uniform sampler2D blurTexture3;
|
|
1191
|
+
uniform sampler2D blurTexture4;
|
|
1192
|
+
uniform sampler2D blurTexture5;
|
|
1193
|
+
uniform float bloomStrength;
|
|
1194
|
+
uniform float bloomRadius;
|
|
1195
|
+
uniform float bloomFactors[NUM_MIPS];
|
|
1196
|
+
uniform vec3 bloomTintColors[NUM_MIPS];
|
|
1197
|
+
|
|
1198
|
+
float lerpBloomFactor(const in float factor) {
|
|
1199
|
+
float mirrorFactor = 1.2 - factor;
|
|
1200
|
+
return mix(factor, mirrorFactor, bloomRadius);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
void main() {
|
|
1204
|
+
gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) +
|
|
1205
|
+
lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) +
|
|
1206
|
+
lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) +
|
|
1207
|
+
lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) +
|
|
1208
|
+
lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );
|
|
1209
|
+
}`})}}y.BlurDirectionX=new s.Vector2(1,0),y.BlurDirectionY=new s.Vector2(0,1);const Ue=n.defineComponent({__name:"UnrealBloom",props:{radius:{default:0},strength:{default:1},threshold:{default:0}},setup(r,{expose:e}){const t=r,{sizes:o}=g.useTresContext(),{pass:a}=M(()=>new y(new s.Vector2(o.width.value,o.height.value),t.radius,t.strength,t.threshold),t);return e({pass:a}),n.watchEffect(()=>{var i;a.value.radius=t.radius??((i=a.value.getCompositeMaterial().uniforms.bloomRadius)==null?void 0:i.value)??.1}),n.watchEffect(()=>{var i;a.value.strength=t.strength??((i=a.value.getCompositeMaterial().uniforms.bloomStrength)==null?void 0:i.value)??1}),n.watchEffect(()=>{var i;a.value.threshold=t.threshold??((i=Q.uniforms.luminosityThreshold)==null?void 0:i.value)??1}),()=>{}}});u.BarrelBlurPmndrs=se,u.BloomPmndrs=_,u.ChromaticAberrationPmndrs=ne,u.ColorAveragePmndrs=de,u.DepthOfFieldPmndrs=$,u.DotScreenPmndrs=ge,u.EffectComposer=Ce,u.EffectComposerPmndrs=Z,u.Glitch=De,u.GlitchPmndrs=ee,u.Halftone=Le,u.HueSaturationPmndrs=le,u.KuwaharaPmndrs=ue,u.LensDistortionPmndrs=he,u.LinocutPmndrs=xe,u.NoisePmndrs=te,u.OutlinePmndrs=oe,u.Output=Ne,u.Pixelation=Re,u.PixelationPmndrs=ae,u.SMAA=ze,u.ScanlinePmndrs=ce,u.SepiaPmndrs=ve,u.ShockWavePmndrs=me,u.TiltShiftPmndrs=pe,u.ToneMappingPmndrs=re,u.UnrealBloom=Ue,u.VignettePmndrs=ie,u.useEffect=M,u.useEffectPmndrs=p,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
|