UNPKG

@threepipe/webgi-plugins

Version:

WebGi - Realistic Rendering Plugins for ThreePipe.

732 lines 222 kB
/** * @license * @threepipe/webgi-plugins v0.5.3 * Copyright 2022-2025 repalash <palash@shaders.app> (https://repalash.com) * SEE LICENSE IN LICENSE */ var _a, _b; import { ShaderChunk, PipelinePassPlugin, GBufferPlugin, ProgressivePlugin, generateUiConfig, uiToggle, uiConfig, ExtendedShaderPass, Vector2, Matrix4, CopyShader, getOrCall, serialize, uniform, uiVector, matDefineBool, UnsignedByteType, shaderReplaceString, LinearSRGBColorSpace, GBufferRenderPass, Color, ShaderMaterial, NoBlending, Matrix3, DoubleSide, uiImage, uiFolderContainer, uiConfigMaterialExtension, updateBit, Vector4, HalfFloatType, AdditiveBlending, uiSlider, onChange, onChange2, Vector3, PickingPlugin, now, FrameFadePlugin, shaderUtils, ExtendedShaderMaterial, RGBAFormat, NearestFilter, bindToValue, AViewerPluginSync, updateMaterialDefines, glsl, BaseGroundPlugin, matDefine, SSAAPlugin, getTexelDecoding, AScreenPassExtensionPlugin, animateTarget, RenderPass, uiColor, makeSamplerUi, SRGBColorSpace, Mesh2, Plane, PerspectiveCamera, MathUtils, DirectionalLight2, copyObject3DUserData, Serialization, ThreeSerialization, ShadowMaterial, SimpleEventDispatcher, BasicShadowMap, ShaderMaterial2, NoColorSpace, Layers, LinearFilter, LinearMipmapLinearFilter, PCFShadowMap, PCFSoftShadowMap, VSMShadowMap, uiDropdown, uiInput, uiButton } from "threepipe"; const VelocityBufferUnpack = "#if defined(HAS_VELOCITY_BUFFER)\nuniform sampler2D tVelocity;vec2 getVelocity(const in vec2 uv){vec2 screenSpaceVelocity=texture2D(tVelocity,uv).xy*2.0-1.0;return sign(screenSpaceVelocity)*pow(abs(screenSpaceVelocity),vec2(4.));}\n#endif\n"; const ssVelocityVert = "#ifdef USE_ALPHAMAP\n#define USE_UV\n#endif\n#include <uv_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvarying vec3 vWorldPosition;varying vec3 vWorldPositionPrevious;uniform mat4 modelMatrixPrevious;void main(){\n#include <uv_vertex>\n#include <skinbase_vertex>\n#include <begin_vertex>\n#include <morphtarget_vertex>\n#include <skinning_vertex>\n#include <displacementmap_vertex>\nvec4 mvPosition=vec4(transformed,1.0);\n#ifdef USE_INSTANCING\nmvPosition=instanceMatrix*mvPosition;\n#endif\nvWorldPosition=(modelMatrix*mvPosition).xyz;vWorldPositionPrevious=(modelMatrixPrevious*mvPosition).xyz;mvPosition=modelViewMatrix*mvPosition;gl_Position=projectionMatrix*mvPosition;\n#include <logdepthbuf_vertex>\n#include <clipping_planes_vertex>\n}"; const ssVelocityFrag = "varying vec3 vWorldPosition;varying vec3 vWorldPositionPrevious;uniform mat4 currentProjectionViewMatrix;uniform mat4 lastProjectionViewMatrix;vec2 computeScreenSpaceVelocity2(){vec4 currentPositionClip=currentProjectionViewMatrix*vec4(vWorldPosition,1.0);vec4 prevPositionClip=lastProjectionViewMatrix*vec4(vWorldPositionPrevious,1.0);vec2 currentPositionNDC=currentPositionClip.xy/currentPositionClip.w;vec2 prevPositionNDC=prevPositionClip.xy/prevPositionClip.w;if(prevPositionNDC.x>=1.0||prevPositionNDC.x<=-1.0||prevPositionNDC.x>=1.0||prevPositionNDC.y<=-1.0){return vec2(0.0);}return 0.5*(currentPositionNDC-prevPositionNDC);}void main(){vec2 velocity=clamp(computeScreenSpaceVelocity2(),-1.0,1.0);velocity=sign(velocity)*pow(abs(velocity),vec2(1./4.));velocity=velocity*0.5+0.5;gl_FragColor=vec4(velocity.x,velocity.y,1.,1.);}"; const computeScreenSpaceVelocity = "uniform mat4 lastProjectionViewMatrix;uniform mat4 currentProjectionViewMatrix;vec2 computeScreenSpaceVelocity(const in vec3 worldPosition){vec4 currentPositionClip=currentProjectionViewMatrix*vec4(worldPosition,1.0);vec4 prevPositionClip=lastProjectionViewMatrix*vec4(worldPosition,1.0);vec2 currentPositionNDC=currentPositionClip.xy/currentPositionClip.w;vec2 prevPositionNDC=prevPositionClip.xy/prevPositionClip.w;if(prevPositionNDC.x>=1.0||prevPositionNDC.x<=-1.0||prevPositionNDC.x>=1.0||prevPositionNDC.y<=-1.0){return vec2(0.0);}return 0.5*(currentPositionNDC-prevPositionNDC);}"; const getWorldPositionFromViewZ = "uniform mat4 inverseViewMatrix;vec3 getWorldPositionFromViewZ(const in vec2 uv,const in float viewDepth){vec2 uv_=2.*uv-1.;float xe=-(uv_.x+projection[2][0])*viewDepth/projection[0][0];float ye=-(uv_.y+projection[2][1])*viewDepth/projection[1][1];return(inverseViewMatrix*vec4(xe,ye,viewDepth,1.)).xyz;}"; const temporalaa = "#include <common>\n#include <gbuffer_unpack>\n#ifdef HAS_VELOCITY_BUFFER\n#pragma <velocity_unpack>\n#else\n#define HAS_VELOCITY_BUFFER 0\n#endif\n#include <cameraHelpers>\nvarying vec2 vUv;uniform vec2 previousRTSize;uniform vec2 jitterSample;uniform vec2 feedBack;uniform bool firstFrame;vec3 find_closest_fragment_3x3(const in vec2 uv){const vec3 offset=vec3(-1.0,1.0,0.0);vec2 texelSize=1.0/previousRTSize;vec3 dtr=vec3(1,1,getDepth(uv+offset.yy*texelSize));vec3 dtc=vec3(0,1,getDepth(uv+offset.zy*texelSize));vec3 dtl=vec3(-1,1,getDepth(uv+offset.xy*texelSize));vec3 dml=vec3(-1,0,getDepth(uv+offset.xz*texelSize));vec3 dmc=vec3(0,0,getDepth(uv));vec3 dmr=vec3(1,0,getDepth(uv+offset.yz*texelSize));vec3 dbl=vec3(-1,-1,getDepth(uv+offset.xx*texelSize));vec3 dbc=vec3(0,-1,getDepth(uv+offset.zx*texelSize));vec3 dbr=vec3(1,-1,getDepth(uv+offset.yx*texelSize));vec3 dmin=dtl;if(dmin.z>dtc.z)dmin=dtc;if(dmin.z>dtr.z)dmin=dtr;if(dmin.z>dml.z)dmin=dml;if(dmin.z>dmc.z)dmin=dmc;if(dmin.z>dmr.z)dmin=dmr;if(dmin.z>dbl.z)dmin=dbl;if(dmin.z>dbc.z)dmin=dbc;if(dmin.z>dbr.z)dmin=dbr;return vec3(uv+texelSize.xy*dmin.xy,dmin.z);}vec3 find_closest_fragment_5tap(const in vec2 uv){vec2 texelSize=1.0/previousRTSize;vec2 offset=vec2(1.0,-1.0);vec3 dtl=vec3(-1,1,getDepth(uv+offset.yx*texelSize));vec3 dtr=vec3(1,1,getDepth(uv+offset.xx*texelSize));vec3 dmc=vec3(0,0,getDepth(uv));vec3 dbl=vec3(-1,-1,getDepth(uv+offset.yy*texelSize));vec3 dbr=vec3(1,-1,getDepth(uv+offset.xy*texelSize));vec3 dmin=dtl;if(dmin.z>dtr.z)dmin=dtr;if(dmin.z>dmc.z)dmin=dmc;if(dmin.z>dbl.z)dmin=dbl;if(dmin.z>dbr.z)dmin=dbr;return vec3(uv+dmin.xy*texelSize,dmin.z);}vec4 clip_aabb(const in vec4 aabb_min,const in vec4 aabb_max,vec4 p){const float FLT_EPS=1e-8;vec4 p_clip=0.5*(aabb_max+aabb_min);vec4 e_clip=0.5*(aabb_max-aabb_min)+FLT_EPS;vec4 v_clip=p-p_clip;vec4 v_unit=abs(v_clip/e_clip);float ma_unit=max(v_unit.x,max(v_unit.y,v_unit.z));if(ma_unit>1.0)return p_clip+v_clip/ma_unit;else return p;}\n#if HAS_VELOCITY_BUFFER == 0 || defined(DEBUG_VELOCITY)\n#include <computeScreenSpaceVelocity>\n#include <getWorldPositionFromViewZ>\n#endif\nvec4 currentRTTexelToLinear1(vec4 a){if(isinf(a.x)||isinf(a.y)||isinf(a.z)||isinf(a.w)){return vec4(1.);}return currentRTTexelToLinear(a);}vec4 computeTAA(const in vec2 uv,const in vec2 screenSpaceVelocity,const in float feedbackScale){vec2 uvUnJitter=uv;vec4 currentColor=currentRTTexelToLinear(texture2D(currentRT,uvUnJitter));vec4 previousColor=previousRTTexelToLinear(texture2D(previousRT,uv-screenSpaceVelocity));const vec3 offset=vec3(1.,-1.,0.);vec2 texelSize=1./previousRTSize;float texelSpeed=length(screenSpaceVelocity);vec4 tl=currentRTTexelToLinear1(texture2D(currentRT,uvUnJitter+offset.yx*texelSize));vec4 tc=currentRTTexelToLinear1(texture2D(currentRT,uvUnJitter+offset.zx*texelSize));vec4 tr=currentRTTexelToLinear1(texture2D(currentRT,uvUnJitter+offset.xx*texelSize));vec4 ml=currentRTTexelToLinear1(texture2D(currentRT,uvUnJitter+offset.yz*texelSize));vec4 mc=currentColor;vec4 mr=currentRTTexelToLinear1(texture2D(currentRT,uvUnJitter+offset.xz*texelSize));vec4 bl=currentRTTexelToLinear1(texture2D(currentRT,uvUnJitter+offset.yy*texelSize));vec4 bc=currentRTTexelToLinear1(texture2D(currentRT,uvUnJitter+offset.zy*texelSize));vec4 br=currentRTTexelToLinear1(texture2D(currentRT,uvUnJitter+offset.xy*texelSize));vec4 corners=2.0*(tr+bl+br+tl)-2.0*mc;mc+=(mc-(corners*0.166667))*2.718282*0.3;mc=max(vec4(0.0),mc);vec4 min5=min(tc,min(ml,min(mc,min(mr,bc))));vec4 max5=max(tc,max(ml,max(mc,max(mr,bc))));vec4 cmin=min(min5,min(tl,min(tr,min(bl,br))));vec4 cmax=max(min5,max(tl,max(tr,max(bl,br))));;cmin=0.5*(cmin+min5);cmax=0.5*(cmax+max5);previousColor=clip_aabb(cmin,cmax,previousColor);float lum0=luminance(currentColor.rgb);float lum1=luminance(previousColor.rgb);float unbiased_diff=abs(lum0-lum1)/max(lum0,max(lum1,0.2));float unbiased_weight=1.0-unbiased_diff;float unbiased_weight_sqr=unbiased_weight*unbiased_weight;float k_feedback=mix(feedBack.x,feedBack.y,unbiased_weight_sqr);return mix(currentColor,previousColor,clamp(k_feedback*feedbackScale,0.,1.));}void main(){\n#if HAS_VELOCITY_BUFFER == 0\n#if QUALITY == 1\nvec3 c_frag=find_closest_fragment_3x3(vUv);\n#else\nvec3 c_frag=find_closest_fragment_5tap(vUv);\n#endif\n#else\nvec3 c_frag=vec3(vUv,0.);\n#endif\nbool bg=firstFrame;\n#if BACKGROUND_TAA\nfloat d=c_frag.z;float edgef=min(1.,max(0.,1.-(d*100.-99.)));\n#else\nbg=bg||c_frag.z>0.999;\n#endif\nif(bg){gl_FragColor=currentRTTexelToLinear1(texture2D(currentRT,vUv));}else{\n#if HAS_VELOCITY_BUFFER == 0\nfloat sampleViewZ=mix(-cameraNearFar.x,-cameraNearFar.y,c_frag.z);vec3 worldPosition=getWorldPositionFromViewZ(c_frag.xy,sampleViewZ);vec2 screenSpaceVelocity=computeScreenSpaceVelocity(worldPosition);\n#else\nvec2 screenSpaceVelocity=getVelocity(c_frag.xy);\n#endif\n#if BACKGROUND_TAA\ngl_FragColor=computeTAA(vUv,screenSpaceVelocity*edgef,edgef);\n#else\ngl_FragColor=computeTAA(vUv,screenSpaceVelocity,1.);\n#endif\n}\n#include <colorspace_fragment>\n#ifdef DEBUG_VELOCITY\nfloat sampleViewZ=mix(-cameraNearFar.x,-cameraNearFar.y,c_frag.z);vec3 worldPosition=getWorldPositionFromViewZ(c_frag.xy,sampleViewZ);vec2 screenSpaceVelocity=computeScreenSpaceVelocity(worldPosition);gl_FragColor=vec4(10.*length(screenSpaceVelocity),0.,0.,1.);\n#endif\n}"; const ssreflection = "uniform float currentFrameCount;\n#ifndef D_frameCount\n#define D_frameCount\nuniform float frameCount;\n#endif\nuniform float objectRadius;uniform float radius;uniform float tolerance;uniform float ssrRoughnessFactor;uniform bool autoRadius;\n#ifndef D_sceneBoundingRadius\n#define D_sceneBoundingRadius\nuniform float sceneBoundingRadius;\n#endif\n#if SSREFL_ENABLED == 2\nuniform float ssrSplitX;\n#endif\n#ifdef HAS_VELOCITY_BUFFER\n#pragma <velocity_unpack>\n#else\n#define HAS_VELOCITY_BUFFER 0\n#endif\n#if HAS_VELOCITY_BUFFER == 0\n#include <computeScreenSpaceVelocity>\n#include <getWorldPositionFromViewZ>\n#endif\nvec3 ComputeReflectionL(vec3 N,vec2 E,vec3 V,float rough){float rough4=rough*rough*rough*rough;float phi=2.0*PI*E.x;float cos_theta=pow(max(E.y,0.000001),rough4/(2.0-rough4));float sin_theta=sqrt(max(0.,1.0-cos_theta*cos_theta));vec3 half_vec=vec3(sin_theta*cos(phi),sin_theta*sin(phi),cos_theta);vec3 tangentX=normalize(cross(abs(N.z)<0.999 ? vec3(0.0,0.0,1.0): vec3(1.0,0.0,0.0),N));vec3 tangentY=cross(N,tangentX);half_vec=half_vec.x*tangentX+half_vec.y*tangentY+half_vec.z*N;vec3 ray_dir=(2.0*dot(V,half_vec))*half_vec-V;return ray_dir;}vec2 GetRandomE(float seed){vec2 rand_e;rand_e.x=interleavedGradientNoise(gl_FragCoord.xy,frameCount*34.+seed);rand_e.y=fract(rand_e.x*38.65435);rand_e.y=mix(rand_e.y,1.0,0.7);return rand_e;}vec4 calculateSSR(in float seed,in vec3 screenPos,in vec3 normal,in float radiusFactor,in float roughness){vec3 viewPos=screenToView3(screenPos.xy,screenPos.z);normal=normalize(normal);vec2 E=GetRandomE(seed);vec3 L=ComputeReflectionL(normal,E,-normalize(viewPos),roughness*ssrRoughnessFactor);L=normalize(L);float cameraDist=length(cameraPositionWorld);float rayLen=objectRadius*sceneBoundingRadius;rayLen=autoRadius ?min(max(mix(max(0.0,(cameraDist+rayLen)+viewPos.z),max(0.0,-viewPos.z-max(0.0,cameraDist-rayLen)),L.z*0.5+0.5),rayLen*0.1),rayLen*5.):rayLen;rayLen*=radiusFactor;float r=interleavedGradientNoise(gl_FragCoord.xy,frameCount+seed);rayLen=max(rayLen,0.001);int steps=SSR_STEP_COUNT/(currentFrameCount<float(SSR_LOW_QUALITY_FRAMES)? 2 : 1);vec3 state=vec3(0.,(r+0.5)/float(steps),2.);viewPos+=normal*max(-0.0001*viewPos.z,0.001);vec3 screenHitP=traceRay(viewPos,L*rayLen,tolerance*rayLen,state,steps);if(state.z<0.99){if(currentFrameCount<1.){\n#if HAS_VELOCITY_BUFFER == 0\nvec3 worldPosition=getWorldPositionFromViewZ(screenHitP.xy,screenHitP.z);vec2 screenSpaceVelocity=computeScreenSpaceVelocity(worldPosition);\n#else\nvec2 screenSpaceVelocity=getVelocity(screenHitP.xy);\n#endif\nscreenHitP.xy-=screenSpaceVelocity;}vec3 hitColor=(tLastFrameTexelToLinear(texture2D(tLastFrame,screenHitP.xy))).rgb;float ssrWeight=1.;return vec4(hitColor*ssrWeight,1.);}return vec4(0.);}"; const ssrtao = "uniform float currentFrameCount;uniform float intensity;uniform float objectRadius;uniform float rayCount;uniform float power;uniform float bias;uniform float falloff;uniform float tolerance;uniform bool autoRadius;uniform vec2 screenSize;\n#ifndef D_sceneBoundingRadius\n#define D_sceneBoundingRadius\nuniform float sceneBoundingRadius;\n#endif\n#ifdef HAS_VELOCITY_BUFFER\n#pragma <velocity_unpack>\n#else\n#define HAS_VELOCITY_BUFFER 0\n#endif\n#if HAS_VELOCITY_BUFFER == 0\n#include <computeScreenSpaceVelocity>\n#include <getWorldPositionFromViewZ>\n#endif\nvec3 ComputeUniformL(vec3 N,vec2 E){vec3 L;L.xy=E;L.z=interleavedGradientNoise(gl_FragCoord.xy,currentFrameCount*5.);L=L*2.-1.;return L;}vec2 GetRandomE(float seed){vec2 rand_e;rand_e.x=random3(vec3(gl_FragCoord.xy,currentFrameCount+seed));rand_e.y=random3(vec3(gl_FragCoord.yx,rand_e.x+(currentFrameCount)*7.));return rand_e;}float saturate2(float v,float mx){return max(0.,min(mx,v));}vec4 calculateGI(in float seed,in vec3 screenPos,in vec3 normal,in float radiusFactor){vec3 viewPos=screenToView3(screenPos.xy,screenPos.z);normal=normalize(normal);vec2 E=GetRandomE(seed);vec3 L=ComputeUniformL(normal,E);L=normalize(L);L*=sign(dot(L,normal));float cameraDist=length(cameraPositionWorld);float rayLen=objectRadius*sceneBoundingRadius;rayLen=autoRadius ?min(max(mix(max(0.0,(cameraDist+rayLen)+viewPos.z),max(0.0,-viewPos.z-max(0.0,cameraDist-rayLen)),L.z*0.5+0.5),rayLen*0.1),rayLen*5.):rayLen;rayLen*=radiusFactor;float r=interleavedGradientNoise(gl_FragCoord.xy,currentFrameCount*14.+seed)+0.05;rayLen=max(rayLen,0.001);vec3 state=vec3(1.,(r+0.5)/float(RTAO_STEP_COUNT),2.);viewPos+=normal*max(-0.01*viewPos.z,0.001);vec3 screenHitP=traceRay(viewPos,L*rayLen,tolerance*rayLen,state,RTAO_STEP_COUNT);vec3 viewHitP=screenToView3(screenHitP.xy,screenHitP.z);vec3 LRes=viewHitP-viewPos;if(state.z>1.)LRes=vec3(9999999.);float dist=length(LRes)*falloff;float EPS=0.01;float zBias=(viewPos.z)*bias;float ao=(max(dot(normal,L)+zBias,0.))/(dist*dist+EPS);\n#if defined(SSGI_ENABLED) && SSGI_ENABLED > 0\nif(currentFrameCount<1.){\n#if HAS_VELOCITY_BUFFER == 0\nvec3 worldPosition=getWorldPositionFromViewZ(screenHitP.xy,screenHitP.z);vec2 screenSpaceVelocity=computeScreenSpaceVelocity(worldPosition);\n#else\nvec2 screenSpaceVelocity=getVelocity(screenHitP.xy);\n#endif\nscreenHitP.xy-=screenSpaceVelocity;}vec3 hitColor=tLastFrameTexelToLinear(texture2D(tLastFrame,screenHitP.xy)).rgb;vec3 hitNormal=getViewNormal(screenHitP.xy);float giWeight=1.;giWeight=saturate2(giWeight/(dist+EPS),1.);giWeight*=saturate2((dot(normal,L)),1.0);giWeight*=saturate2((dot(hitNormal,-L)),1.0);return vec4(hitColor*giWeight,ao);\n#endif\nreturn vec4(0,0,0,ao);}float normpdf(in float x,in float sigma){return exp(-0.5*x*x/(sigma*sigma));}vec4 getLastThis(sampler2D tex,float depth,vec3 normal){vec2 direction=vec2(1,1);vec4 color=clamp(tLastThisTexelToLinear(texture2D(tex,vUv.xy)),0.,5.);return color;}void main(){float depth;vec3 normal;getDepthNormal(vUv,depth,normal);if(depth>0.99){discard;gl_FragColor=getLastThis(tLastThis,depth,normal);return;}float viewZ=depthToViewZ(depth);vec3 screenPos=vec3(vUv.x,vUv.y,viewZ);vec4 gi=vec4(0.);gi+=calculateGI(8.,screenPos,normal,1.);if(rayCount>1.5)gi=max(gi,calculateGI(2.,screenPos,normal,0.4));if(rayCount>2.5)gi=max(gi,calculateGI(3.,screenPos,normal,1.5));if(rayCount>3.5)gi=max(gi,calculateGI(1.,screenPos,normal,0.6));if(rayCount>4.5)gi=max(gi,calculateGI(3.,screenPos,normal,1.));gi.a=min(1.,gi.a);gi.a=max(0.,gi.a);gi.rgb=min(vec3(3.),gi.rgb);gi.rgb=max(vec3(0.),gi.rgb);if(currentFrameCount<3.){gl_FragColor=gi;return;}gl_FragColor=(texture2D(tLastThis,vUv));gl_FragColor=((gi+(gl_FragColor)*currentFrameCount)/(currentFrameCount+1.));}"; const shadersUtils2 = { computeScreenSpaceVelocity, getWorldPositionFromViewZ, temporalAA: temporalaa, ssReflection: ssreflection, calculateGI: ssrtao, ["__inited"]: false }; function getShaders() { if (!shadersUtils2.__inited) { shadersUtils2.__inited = true; Object.assign(ShaderChunk, shadersUtils2); } return shadersUtils2; } var __defProp$f = Object.defineProperty; var __getOwnPropDesc$9 = Object.getOwnPropertyDescriptor; var __decorateClass$f = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$9(target, key) : target; for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--) if (decorator = decorators[i2]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp$f(target, key, result); return result; }; const passId$4 = "taa"; const _TemporalAAPlugin = class _TemporalAAPlugin extends PipelinePassPlugin { // readonly materialExtension: MaterialExtension = uiConfigMaterialExtension(this._getUiConfig.bind(this), TemporalAAPlugin.PluginType) constructor(enabled = true) { super(); this.passId = passId$4; this._stableNoise = true; this._gbufferUnpackExtension = void 0; this._gbufferUnpackExtensionChanged = () => { if (!this._pass || !this._viewer) throw new Error("TemporalAAPlugin: pass/viewer not created yet"); const newExtension = this._viewer.renderManager.gbufferUnpackExtension; if (this._gbufferUnpackExtension === newExtension) return; if (this._gbufferUnpackExtension) this._pass.material.unregisterMaterialExtensions([this._gbufferUnpackExtension]); this._gbufferUnpackExtension = newExtension; if (this._gbufferUnpackExtension) this._pass.material.registerMaterialExtensions([this._gbufferUnpackExtension]); else this._viewer.console.warn("TemporalAAPlugin: GBuffer unpack extension removed"); }; this.dependencies = [GBufferPlugin, ProgressivePlugin]; this.uiConfig = { type: "folder", label: "TemporalAA Plugin", onChange: this.setDirty.bind(this), children: [ ...generateUiConfig(this) || [] ] }; this.enabled = enabled; this.setDirty = this.setDirty.bind(this); } get stableNoise() { return this._viewer?.renderManager.stableNoise ?? this._stableNoise; } set stableNoise(v) { if (this._viewer) this._viewer.renderManager.stableNoise = v; this._stableNoise = v; } _createPass() { if (!this._viewer) throw new Error("TemporalAAPlugin: viewer not set"); if (!this._viewer.renderManager.gbufferTarget || !this._viewer.renderManager.gbufferUnpackExtension) throw new Error("TemporalAAPlugin: GBuffer target not created. GBufferPlugin is required."); const applyOnBackground = !!this._viewer.renderManager.msaa; const t2 = new TemporalAAPluginPass(this.passId, () => this._viewer?.getPlugin(ProgressivePlugin)?.target, applyOnBackground); return t2; } // todo use gbufferUnpackExtension from render manager to support depth buffer plugin as well. onAdded(viewer) { super.onAdded(viewer); this._gbufferUnpackExtensionChanged(); viewer.renderManager.addEventListener("gbufferUnpackExtensionChanged", this._gbufferUnpackExtensionChanged); viewer.renderManager.addEventListener("resize", this._pass.onSizeUpdate); } onRemove(viewer) { viewer.renderManager.removeEventListener("gbufferUnpackExtensionChanged", this._gbufferUnpackExtensionChanged); viewer.renderManager.removeEventListener("resize", this._pass.onSizeUpdate); super.onRemove(viewer); } _beforeRender(scene, camera, renderManager) { if (!super._beforeRender(scene, camera, renderManager)) return false; const pass = this.pass; const v = this._viewer; if (!pass || !v) return false; const frame = renderManager.frameCount; pass.taaEnabled = frame <= 1 && scene.renderCamera === scene.mainCamera; if (!pass.taaEnabled) return false; const cam = camera; if (!cam) return false; cam.updateMatrixWorld(true); cam.updateShaderProperties(pass.material); pass.updateCameraProperties(cam); pass.target = v.getPlugin(ProgressivePlugin).target; return true; } // region to be done or removed // static AddTemporalAAData(material: IMaterial, params?: IMaterialUserData['TemporalAA'], setDirty = true): IMaterialUserData['TemporalAA']|null { // const ud = material?.userData // if (!ud) return null // if (!ud[TemporalAAPlugin.PluginType]) { // ud[TemporalAAPlugin.PluginType] = {} // } // const data = ud[TemporalAAPlugin.PluginType]! // data.enable = true // params && Object.assign(data, params) // if (setDirty && material.setDirty) material.setDirty() // return data // } /** * This uiConfig is added to each material by extension * @param material * @private */ // private _getUiConfig(material: IMaterial) { // const config: UiObjectConfig = { // type: 'folder', // label: 'TemporalAA', // children: [ // { // type: 'checkbox', // label: 'Enabled', // get value() { // return material.userData[TemporalAAPlugin.PluginType]?.enable ?? true // }, // set value(v) { // let data = material.userData[TemporalAAPlugin.PluginType] // if (v === data?.enable) return // if (!data) data = TemporalAAPlugin.AddTemporalAAData(material, undefined, false)! // data.enable = v // material.setDirty() // config.uiRefresh?.(true, 'postFrame') // }, // onChange: this.setDirty, // }, // ], // } // return config // } // endregion }; _TemporalAAPlugin.PluginType = "TAA"; _TemporalAAPlugin.OldPluginType = "TemporalAAPlugin"; let TemporalAAPlugin = _TemporalAAPlugin; __decorateClass$f([ uiToggle("Stable Noise (Total frame count)") ], TemporalAAPlugin.prototype, "stableNoise", 1); __decorateClass$f([ uiConfig(void 0, { unwrapContents: true }) ], TemporalAAPlugin.prototype, "_pass", 2); class TemporalAAPluginPass extends ExtendedShaderPass { constructor(pid, target, applyOnBackground = false) { super({ vertexShader: CopyShader.vertexShader, fragmentShader: getShaders().temporalAA, uniforms: { currentRT: { value: null }, previousRT: { value: null }, previousRTSize: { value: new Vector2() }, cameraNearFar: { value: new Vector2() }, lastProjectionViewMatrix: { value: new Matrix4() }, currentProjectionViewMatrix: { value: new Matrix4() }, projection: { value: new Matrix4() }, inverseViewMatrix: { value: new Matrix4() }, jitterSample: { value: new Vector2() }, firstFrame: { value: true } }, defines: { ["QUALITY"]: 1, ["UNJITTER"]: 0, ["BACKGROUND_TAA"]: applyOnBackground ? 1 : 0 } }, "currentRT", "previousRT"); this.before = ["progressive"]; this.after = []; this.required = ["render", "progressive"]; this.taaEnabled = true; this.feedBack = new Vector2(0.88, 0.97); this.debugVelocity = false; this.uiConfig = { type: "folder", label: "Temporal AA Pass", onChange: this.setDirty, children: [ { type: "checkbox", label: "Enabled", property: [this, "enabled"], onChange: () => this.onSizeUpdate() }, ...generateUiConfig(this)?.filter((c) => c && c.label !== "Enabled") || [] ] }; this.passId = pid; this.onSizeUpdate = this.onSizeUpdate.bind(this); this.target = target; this.clear = false; this.needsSwap = true; } render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) { if (!this.taaEnabled || !this.enabled) { this.needsSwap = false; return; } this.needsSwap = true; this.uniforms.previousRT.value = getOrCall(this.target)?.texture ?? null; super.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive); this.uniforms.lastProjectionViewMatrix.value.copy(this.uniforms.currentProjectionViewMatrix.value); this.uniforms.firstFrame.value = false; } updateCameraProperties(camera) { if (!camera) return; this.uniforms.currentProjectionViewMatrix.value.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); this.uniforms.inverseViewMatrix.value.copy(camera.matrixWorld); } onSizeUpdate() { this.uniforms.firstFrame.value = true; this.setDirty(); } setSize(width, height) { super.setSize(width, height); this.onSizeUpdate(); } } __decorateClass$f([ serialize(), uniform(), uiVector("Feedback", void 0, 1e-4) ], TemporalAAPluginPass.prototype, "feedBack", 2); __decorateClass$f([ uiToggle(), matDefineBool("DEBUG_VELOCITY", void 0, false, void 0, true) ], TemporalAAPluginPass.prototype, "debugVelocity", 2); var __defProp$e = Object.defineProperty; var __getOwnPropDesc$8 = Object.getOwnPropertyDescriptor; var __decorateClass$e = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$8(target, key) : target; for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--) if (decorator = decorators[i2]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp$e(target, key, result); return result; }; let VelocityBufferPlugin = class extends PipelinePassPlugin { constructor(bufferType = UnsignedByteType, enabled = true, _attachToTaa = true) { super(); this.passId = "velocityBuffer"; this.material = new SSVelocityMaterial(); this.unpackExtension = { shaderExtender: (shader) => { if (this.isDisabled()) return; shader.fragmentShader = shaderReplaceString( shader.fragmentShader, "#pragma <velocity_unpack>", "\n" + VelocityBufferUnpack + "\n" ); }, computeCacheKey: () => this.isDisabled() ? "" : "vb", extraUniforms: { tVelocity: () => ({ value: !this.isDisabled() ? this.target?.texture : null }) }, extraDefines: { ["HAS_VELOCITY_BUFFER"]: () => !this.isDisabled() && this.target?.texture ? 1 : void 0 }, priority: 100, isCompatible: () => true }; this.enabled = enabled; this.bufferType = bufferType; this._attachToTaa = _attachToTaa; } // cannot be changed after creation (for now) _createTarget(recreate = true) { if (!this._viewer) return; if (recreate) this._disposeTarget(); if (!this.target) this.target = this._viewer.renderManager.createTarget( { depthBuffer: true, // samples: v.renderManager.composerTarget.samples || 0, samples: 0, type: this.bufferType, // magFilter: NearestFilter, // minFilter: NearestFilter, generateMipmaps: false, colorSpace: LinearSRGBColorSpace } ); this.texture = this.target.texture; this.texture.name = "velocityBuffer"; if (this._pass) this._pass.target = this.target; } _disposeTarget() { if (!this._viewer) return; if (this.target) { this._viewer.renderManager.disposeTarget(this.target); this.target = void 0; } this.texture = void 0; } _createPass() { this._createTarget(true); if (!this.target) throw new Error("VelocityBufferPlugin: target not created"); this.material.userData.isGBufferMaterial = true; const v = this._viewer; const pass = new class extends GBufferRenderPass { constructor() { super(...arguments); this._firstCall = true; } render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) { if (v.renderManager.frameCount > 0) return; if (!this.enabled || !this.camera) return; const mat = this.overrideMaterial; mat.uniforms.currentProjectionViewMatrix.value.copy(this.camera.projectionMatrix).multiply(this.camera.matrixWorldInverse); if (this._firstCall) { mat.uniforms.lastProjectionViewMatrix.value.copy(mat.uniforms.currentProjectionViewMatrix.value); this._firstCall = false; } super.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive); mat.uniforms.lastProjectionViewMatrix.value.copy(mat.uniforms.currentProjectionViewMatrix.value); } }(this.passId, this.target, this.material, new Color(0.5, 0.5, 0.5), 1); const preprocessMaterial = pass.preprocessMaterial; pass.preprocessMaterial = (m) => preprocessMaterial(m, m.userData[VelocityBufferPlugin.PluginType]?.disabled); pass.before = ["render"]; pass.after = []; pass.required = ["render"]; return pass; } onAdded(viewer) { super.onAdded(viewer); viewer.forPlugin(TemporalAAPlugin, (taa) => { this._attachToTaa && taa.pass?.material.registerMaterialExtensions([this.unpackExtension]); }, (taa) => { taa.pass?.material?.unregisterMaterialExtensions([this.unpackExtension]); }); } onRemove(viewer) { this._disposeTarget(); return super.onRemove(viewer); } setDirty() { super.setDirty(); this.unpackExtension.setDirty?.(); } _beforeRender(scene, camera, renderManager) { if (!super._beforeRender(scene, camera, renderManager)) return false; const pass = this.pass; if (!pass) return false; if (renderManager.frameCount > 0) return false; pass.scene = scene; pass.camera = camera; camera.updateShaderProperties(pass.overrideMaterial); return true; } }; VelocityBufferPlugin.PluginType = "VelocityBuffer"; VelocityBufferPlugin.OldPluginType = "VelocityBufferPlugin"; __decorateClass$e([ uiImage("Velocity Buffer", { readOnly: true }) ], VelocityBufferPlugin.prototype, "texture", 2); VelocityBufferPlugin = __decorateClass$e([ uiFolderContainer("Velocity Buffer Plugin (for TAA)") ], VelocityBufferPlugin); class SSVelocityMaterial extends ShaderMaterial { constructor() { super({ vertexShader: ssVelocityVert, fragmentShader: ssVelocityFrag, uniforms: { cameraNearFar: { value: new Vector2(0.1, 1e3) }, alphaMap: { value: null }, alphaTest: { value: null }, alphaMapTransform: { value: /* @__PURE__ */ new Matrix3() }, currentProjectionViewMatrix: { value: new Matrix4() }, lastProjectionViewMatrix: { value: new Matrix4() } }, blending: NoBlending // todo? }); this.extraUniformsToUpload = { modelMatrixPrevious: { value: new Matrix4().identity() } }; this._previousWorldMatrices = {}; } // this gets called for each object. onBeforeRender(_r, _s, _c, _geometry, object) { const prevMatrix = this._previousWorldMatrices[object.uuid]; this.extraUniformsToUpload.modelMatrixPrevious.value.copy(prevMatrix ?? object.matrixWorld); if (prevMatrix) { prevMatrix.copy(object.matrixWorld); } else { this._previousWorldMatrices[object.uuid] = object.matrixWorld.clone(); } let mat = object.material; if (Array.isArray(mat)) { mat = mat[0]; } this.uniforms.alphaMap.value = mat?.alphaMap ?? null; this.uniforms.alphaTest.value = !mat || !mat.alphaTest || mat.alphaTest < 1e-7 ? 1e-3 : mat.alphaTest; let x = this.uniforms.alphaMap.value ? 1 : void 0; if (x !== this.defines.USE_ALPHAMAP) { if (x === void 0) delete this.defines.USE_ALPHAMAP; else this.defines.USE_ALPHAMAP = x; this.needsUpdate = true; } x = mat?.userData.ALPHA_I_RGBA_PACKING ? 1 : void 0; if (x !== this.defines.ALPHA_I_RGBA_PACKING) { if (x === void 0) delete this.defines.ALPHA_I_RGBA_PACKING; else this.defines.ALPHA_I_RGBA_PACKING = x; this.needsUpdate = true; } this.side = mat?.side ?? DoubleSide; } } const hdrBloom = "#include <packing>\nuniform float intensity;uniform float opacity;uniform vec2 tDiffuseSize;varying vec2 vUv;uniform float weight;\n#if PASS_STEP == 0\nuniform vec4 prefilter;vec4 Prefilter(vec4 c){\n#ifdef HAS_GBUFFER\n#if !BACKGROUND_BLOOM\nif(getDepth(vUv)>0.999){return vec4(0.0);}\n#endif\n#endif\nfloat brightness=max(c.r,max(c.g,c.b));float soft=brightness+prefilter.x*(prefilter.y-1.);soft=clamp(soft,0.,prefilter.z);soft=soft*soft*prefilter.w;float contribution=max(soft,brightness-prefilter.x);contribution/=max(brightness,0.001);return vec4(c.rgb*contribution,c.a);}\n#endif\nvec4 Sample(vec2 uv){return min(vec4(MAX_INTENSITY,MAX_INTENSITY,MAX_INTENSITY,1.),tDiffuseTexelToLinear(texture2D(tDiffuse,uv)));}vec4 SampleBox(vec2 uv,float delta){vec4 o=vec2(-delta,delta).xxyy/tDiffuseSize.xyxy;vec4 s=Sample(uv+o.xy)+Sample(uv+o.zy)+Sample(uv+o.xw)+Sample(uv+o.zw);return s*0.25;}int getBloomBit(in int number){\n#ifdef WebGL2Context\nreturn(number/4)% 2;\n#else\nreturn int(mod(floor(float(number)/4.),2.));\n#endif\n}void main(){\n#if PASS_STEP == 0\n#ifdef GBUFFER_HAS_FLAGS\nint doBloom=getBloomBit(getGBufferFlags(vUv).a);\n#else\nint doBloom=1;\n#endif\ngl_FragColor=float(doBloom)*weight*Prefilter(SampleBox(vUv,1.));gl_FragColor.a=1.;\n#elif PASS_STEP == 1\ngl_FragColor=weight*(SampleBox(vUv,1.));gl_FragColor.a=1.;\n#elif PASS_STEP == 2\ngl_FragColor=(SampleBox(vUv,0.5));gl_FragColor.a=1.;\n#elif PASS_STEP == 3\nvec4 texel=tSourceTexelToLinear(texture2D(tSource,vUv));vec4 bloom=intensity*SampleBox(vUv,0.5).rgba;float brightness=max(bloom.r,max(bloom.g,bloom.b));texel.rgb+=bloom.rgb;texel.a=min(1.,texel.a+brightness);gl_FragColor=texel;\n#elif PASS_STEP == 4\nvec4 texel=vec4(0.);texel.rgb+=intensity*SampleBox(vUv,0.5).rgb;texel.a=1.;gl_FragColor=texel;\n#endif\n#include <colorspace_fragment>\n}"; var __defProp$d = Object.defineProperty; var __getOwnPropDesc$7 = Object.getOwnPropertyDescriptor; var __decorateClass$d = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$7(target, key) : target; for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--) if (decorator = decorators[i2]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp$d(target, key, result); return result; }; const passId$3 = "bloom"; const _BloomPlugin = (_a = class extends PipelinePassPlugin { constructor() { super(...arguments); this.passId = passId$3; this.materialExtension = uiConfigMaterialExtension(this._getUiConfig.bind(this), _a.PluginType); this.dependencies = [GBufferPlugin]; this._onPluginAdd = (e2) => { if (e2.plugin?.constructor?.PluginType !== GBufferPlugin.PluginType) return; const gbuffer = e2.plugin; gbuffer.registerGBufferUpdater(this.constructor.PluginType, this.updateGBufferFlags.bind(this)); this._pass?.material.registerMaterialExtensions([gbuffer.unpackExtension]); this._viewer?.removeEventListener("addPlugin", this._onPluginAdd); }; this.uiConfig = { type: "folder", label: "Bloom Plugin", onChange: this.setDirty.bind(this), children: [ ...generateUiConfig(this) || [] ] }; } _createPass() { const pass = new BloomPluginPass(this.passId, Math.min(8, this._viewer?.renderManager.maxHDRIntensity || 8)); return pass; } onAdded(viewer) { super.onAdded(viewer); const gbuffer = viewer.getPlugin(GBufferPlugin); if (gbuffer) { gbuffer.registerGBufferUpdater(this.constructor.PluginType, this.updateGBufferFlags.bind(this)); this._pass.material.registerMaterialExtensions([gbuffer.unpackExtension]); } else viewer.addEventListener("addPlugin", this._onPluginAdd); viewer.materialManager.registerMaterialExtension(this.materialExtension); } onRemove(viewer) { viewer.removeEventListener("addPlugin", this._onPluginAdd); const gbuffer = viewer.getPlugin(GBufferPlugin); gbuffer?.unregisterGBufferUpdater(this.constructor.PluginType); gbuffer && this._pass?.material.unregisterMaterialExtensions([gbuffer.unpackExtension]); viewer.materialManager.unregisterMaterialExtension(this.materialExtension); super.onRemove(viewer); } updateGBufferFlags(data, c) { if (!c.material || !c.material.userData) return; const disabled = c.material.userData[_a.PluginType]?.enable === false || c.material.userData.pluginsDisabled; const x = disabled ? 0 : 1; data.w = updateBit(data.w, 2, x); } static AddBloomData(material, params, setDirty = true) { const ud = material?.userData; if (!ud) return null; if (!ud[_a.PluginType]) { ud[_a.PluginType] = {}; } const data = ud[_a.PluginType]; data.enable = true; params && Object.assign(data, params); if (setDirty && material.setDirty) material.setDirty(); return data; } /** * This uiConfig is added to each material by extension * @param material * @private */ _getUiConfig(material) { const config = { type: "folder", label: "Bloom", children: [ { type: "checkbox", label: "Enabled", get value() { return material.userData[_a.PluginType]?.enable ?? true; }, set value(v) { let data = material.userData[_a.PluginType]; if (v === data?.enable) return; if (!data) data = _a.AddBloomData(material, void 0, false); data.enable = v; material.setDirty(); config.uiRefresh?.(true, "postFrame"); }, onChange: this.setDirty } ] }; return config; } }, _a.PluginType = "Bloom", _a.OldPluginType = "BloomPlugin", _a); __decorateClass$d([ uiConfig(void 0, { unwrapContents: true }) ], _BloomPlugin.prototype, "_pass", 2); let BloomPlugin = _BloomPlugin; let BloomPluginPass = class extends ExtendedShaderPass { constructor(pid, maxIntensity = 16) { super({ vertexShader: CopyShader.vertexShader, defines: { ["PASS_STEP"]: 1, ["MAX_INTENSITY"]: Math.min(maxIntensity, 16) }, uniforms: { tSource: { value: null }, tDiffuse: { value: null }, // intensity: {value: 0.2}, opacity: { value: 1 }, // prefilter: {value: new Vector4(1, 0.5, 0, 0)}, tDiffuseSize: { value: new Vector2() }, weight: { value: 1 } // tNormalDepth: {value: null}, // tGBufferFlags: {value: null}, }, fragmentShader: hdrBloom }, "tDiffuse", "tSource"); this.uiConfig = void 0; this.before = ["screen"]; this.after = ["render", "progressive"]; this.required = ["render"]; this.prefilter = new Vector4(2, 0.5, 0, 0); this.threshold = 2; this.softThreshold = 0.5; this.intensity = 0.2; this.backgroundBloom = false; this.bloomIterations = 4; this._currentIterations = 0; this.radius = 0.6; this.power = 1; this.bloomDebug = false; this._weights = []; this.passId = pid; this._updateWeights = this._updateWeights.bind(this); this._thresholdsUpdated = this._thresholdsUpdated.bind(this); this._updateWeights(); this._thresholdsUpdated(); this.clear = true; } _thresholdsUpdated() { this.prefilter.x = this.threshold; this.prefilter.y = this.softThreshold; this.prefilter.z = 2 * this.prefilter.x * this.prefilter.y; this.prefilter.w = this.uniforms?.prefilter ? 0.125 / (this.uniforms.prefilter.value.z + 1e-5) : 0; } render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) { const renderManager = renderer.renderManager; this.material.defines.PASS_STEP = 0; this.clear = true; this.needsSwap = false; const source = readBuffer; if (!source) { console.warn("BloomPluginPass: No source to read from"); return; } this.needsSwap = true; let sizeMultiplier = 0.5; let width = source.width * sizeMultiplier; let height = source.height * sizeMultiplier; const textures = []; let currentDestination = renderManager.getTempTarget({ sizeMultiplier: 1, type: HalfFloatType }); textures.push(currentDestination); let currentSource = source; this.material.needsUpdate = true; this.material.uniforms.weight.value = this._weights[0]; super.render(renderer, currentDestination, currentSource, deltaTime, maskActive); currentSource = currentDestination; const ci = this._currentIterations; let i2 = 1; const iter = Math.max(2, this.bloomIterations); for (; i2 < iter; i2++) { width /= 2; height /= 2; sizeMultiplier /= 2; if (height < 2 || width < 2) { break; } currentDestination = renderManager.getTempTarget({ sizeMultiplier, type: HalfFloatType }); textures.push(currentDestination); this.material.defines.PASS_STEP = 1; let modifiedWeight = this._weights[i2]; { modifiedWeight = this._weights[i2 - 1] !== 0 ? this._weights[i2] / this._weights[i2 - 1] : this._weights[i2]; } this.material.uniforms.weight.value = modifiedWeight; this.material.needsUpdate = true; super.render(renderer, currentDestination, currentSource, deltaTime, maskActive); currentSource = currentDestination; this._currentIterations = i2 + 1; } if (ci !== this._currentIterations) this._updateWeights(false); this.clear = false; const oldAutoClear = renderer.autoClear; renderer.autoClear = false; for (i2 -= 2; i2 >= 0; i2--) { currentDestination = textures[i2]; textures[i2] = void 0; this.material.defines.PASS_STEP = 2; this.material.transparent = true; this.material.blending = AdditiveBlending; this.material.needsUpdate = true; renderer.autoClear = false; super.render(renderer, currentDestination, currentSource, deltaTime, maskActive); this.material.blending = NoBlending; renderManager.releaseTempTarget(currentSource); currentSource = currentDestination; } this.clear = true; renderer.autoClear = oldAutoClear; renderer.autoClear = true; if (this.bloomDebug) { this.material.defines.PASS_STEP = 4; this.material.needsUpdate = true; super.render(renderer, writeBuffer, currentSource, deltaTime, maskActive); } else { this.uniforms.tSource.value = source.texture; this.material.defines.PASS_STEP = 3; this.material.needsUpdate = true; super.render(renderer, writeBuffer, currentSource, deltaTime, maskActive); this.uniforms.tSource.value = null; } renderManager.releaseTempTarget(currentSource); } _updateWeights(setDirty = true) { if (!this._weights) return; const radius = Math.max(Math.min(this.radius, 1), 0); const iter = Math.max(2, this._currentIterations || this.bloomIterations); const delta = 1 / (iter - 1); for (let i2 = 0; i2 < iter; i2++) { let f = i2 * delta + 0.1; let oneMinusF = 1.2 - f; f = Math.pow(f, this.power); oneMinusF = Math.pow(oneMinusF, this.power); this._weights[i2] = oneMinusF * (1 - radius) + f * radius; } if (setDirty !== false) this.setDirty(); } }; __decorateClass$d([ uniform() ], BloomPluginPass.prototype, "prefilter", 2); __decorateClass$d([ uiSlider("Threshold", [0, 2]), onChange(BloomPluginPass.prototype._thresholdsUpdated), serialize() ], BloomPluginPass.prototype, "threshold", 2); __decorateClass$d([ uiSlider("Soft Threshold", [0, 1]), onChange(BloomPluginPass.prototype._thresholdsUpdated), serialize() ], BloomPluginPass.prototype, "softThreshold", 2); __decorateClass$d([ uiSlider("Intensity", [0, 3]), serialize(), uniform() ], BloomPluginPass.prototype, "intensity", 2); __decorateClass$d([ uiToggle("Background Bloom"), serialize(), matDefineBool("BACKGROUND_BLOOM") ], BloomPluginPass.prototype, "backgroundBloom", 2); __decorateClass$d([ uiSlider("Iterations", [2, 7], 1), onChange2(BloomPluginPass.prototype._updateWeights), serialize() ], BloomPluginPass.prototype, "bloomIterations", 2); __decorateClass$d([ uiSlider("Radius", [0, 1], 0.01), onChange2(BloomPluginPass.prototype._updateWeights), serialize() ], BloomPluginPass.prototype, "radius", 2); __decorateClass$d([ uiSlider("Power", [0.2, 10], 0.01), onChange2(BloomPluginPass.prototype._updateWeights), serialize() ], BloomPluginPass.prototype, "power", 2); __decorateClass$d([ uiToggle("Debug") ], BloomPluginPass.prototype, "bloomDebug", 2); BloomPluginPass = __decorateClass$d([ uiFolderContainer("Bloom Pass") ], BloomPluginPass); const dofCombine = "#include <common>\n#include <packing>\nvarying vec2 vUv;uniform vec2 cocTextureSize;uniform vec2 nearFarBlurScale;uniform vec2 cameraNearFar;uniform vec2 focalDepthRange;uniform vec2 crossCenter;uniform float crossRadius;uniform float crossAlpha;uniform vec3 crossColor;float smoothBoundary(float d,float smooothFactor){smooothFactor*=0.5;float value=smoothstep(-smooothFactor,smooothFactor,d);return value;}float circle(vec2 p,float r){return min((length(p)-r),-(length(p)-r-0.01));}float computeCoc(){float depth=getDepth(vUv);if(depth>1.0-0.01)return max(nearFarBlurScale.x,nearFarBlurScale.y);depth=mix(cameraNearFar.x,cameraNearFar.y,depth);float coc=(depth-focalDepthRange.x)/focalDepthRange.y;coc=clamp(coc,-1.,1.);return(coc>0.0 ? coc*nearFarBlurScale.y : coc*nearFarBlurScale.x);}void main(){vec4 blur=blurTextureTexelToLinear(texture2D(blurTexture,vUv));float scale=0.5;blur+=blurTextureTexelToLinear(texture2D(blurTexture,vUv+scale*vec2(1.0,1.0)/cocTextureSize));blur+=blurTextureTexelToLinear(texture2D(blurTexture,vUv+scale*vec2(-1.0,1.0)/cocTextureSize));blur+=blurTextureTexelToLinear(texture2D(blurTexture,vUv+scale*vec2(-1.0,-1.0)/cocTextureSize));blur+=blurTextureTexelToLinear(texture2D(blurTexture,vUv+scale*vec2(1.0,-1.0)/cocTextureSize));blur/=5.0;vec2 uvNearest=(floor(vUv*cocTextureSize)+0.5)/cocTextureSize;float coc=abs(min(2.*cocTextureTexelToLinear(texture2D(cocTexture,uvNearest)).a-1.,computeCoc()));float cocLower=0.005;float cocHigher=0.3;vec4 outColor=vec4(mix(colorTextureTexelToLinear(texture2D(colorTexture,vUv)).rgb,blur.rgb,smoothstep(cocLower,cocHigher,coc)),1.0);vec2 d=vUv-crossCenter;if(length(d)>crossRadius+0.05){float dist=circle(d,crossRadius);gl_FragColor=outColor;}else{d.x*=cocTextureSize.x/cocTextureSize.y;float dist=circle(d,crossRadius);dist=smoothBoundary(dist,2.*fwidth(dist));vec4 color=outColor;vec3 dofCircleColor=mix(crossColor,color.rgb,1.-crossAlpha);gl_FragColor=vec4(mix(color.rgb,dofCircleColor,dist),color.a);}\n#include <colorspace_fragment>\n}"; const dofPoissonBox = "#include <randomHelpers>\n#include <common>\nvarying vec2 vUv;uniform vec2 colorTextureSize;uniform float blurRadius;\n#ifndef D_frameCount\n#define D_frameCount\nuniform float frameCount;\n#endif\nvec4 CircularBlur(){vec4 color=colorTextureTexelToLinear(texture2D(colorTexture,vUv));\n#ifdef DOF_MODE\nfloat blurDist=blurRadius*(2.*color.a-1.);\n#else\nfloat blurDist=blurRadius*color.a;\n#endif\nfloat rnd=PI2*random3(vec3(vUv,frameCount*0.1));float costheta=cos(rnd);float sintheta=sin(rnd);vec4 rotationMatrix=vec4(costheta,-sintheta,sintheta,costheta);vec3 colorSum=vec3(0.0);float weightSum=0.001;vec2 ofs;vec4 sampleColor;setPds();\n#pragma unroll_loop_start\nfor(int i=0;i<16;i++){ofs=poisson_disk_samples[UNROLLED_LOOP_INDEX];ofs=vec2(dot(ofs,rotationMatrix.xy),dot(ofs,rotationMatrix.zw));sampleColor=colorTextureTexelToLinear(texture2D(colorTexture,vUv+blurDist*ofs/colorTextureSize.xy));\n#ifdef DOF_MODE\nsampleColor.a=abs(sampleColor.a*2.0-1.0);sampleColor.a*=sampleColor.a*sampleColor.a;\n#endif\ncolorSum+=sampleColor.rgb*sampleColor.a;weightSum+=sampleColor.a;}\n#pragma unroll_loop_end\ncolorSum/=weightSum;return vec4(min(vec3(72.),max(vec3(0.),colorSum)),1.0);}void main(){gl_FragColor=CircularBlur();\n#include <colorspace_fragment>\n}"; const poissonDiskSamples$1 = "vec2 poisson_disk_samples[16];void setPds(){poisson_disk_samples[0]=vec2(-0.399691779231,0.728591545584);poisson_disk_samples[1]=vec2(-0.48622557676,-0.84016533712);poisson_disk_samples[2]=vec2(0.770309468987,-0.24906070432);poisson_disk_samples[3]=vec2(0.556596796154,0.820359876432);poisson_disk_samples[4]=vec2(-0.933902004071,0.0600539051593);poisson_disk_samples[5]=vec2(0.330144964342,0.207477293384);poisson_disk_samples[6]=vec2(0.289013230975,-0.686749271417);poisson_disk_samples[7]=vec2(-0.0832470893559,-0.187351643125);poisson_disk_samples[8]=vec2(-0.296314525615,0.254474834305);poisson_disk_samples[9]=vec2(-0.850977666059,0.484642744689);poisson_disk_samples[10]=vec2(0.829287915319,0.2345063545);poisson_disk_samples[11]=vec2(-0.773042143899,-0.543741521254);poisson_disk_samples[12]=vec2(0.0561133030864,0.928419742597);poisson_disk_samples[13]=vec2(-0.205799249508,-0.562072714492);poisson_disk_samples[14]=vec2(-0.526991665882,-0.193690188118);poisson_disk_samples[15]=vec2(-0.051789270667,-0.935374050821);}"; const dofComputeCoC = "#include <common>\n#include <packing>\nvarying vec2 vUv;uniform vec2 nearFarBlurScale;uniform vec2 cameraNearFar;uniform vec2 focalDepthRange;float computeCoc(){float depth=getDepth(vUv);if(depth==1.0)return max(nearFarBlurScale.x,nearFarBlurScale.y);depth=mix(cameraNearFar.x,cameraNearFar.y,depth);float coc=(depth-focalDepthRange.x)/focalDepthRange.y;coc=clamp(coc,-1.,1.);return(coc>0.0 ? coc*nearFarBlurScale.y : coc*nearFarBlurScale.x);}void main(){gl_FragColor=vec4(colorTextureTexelToLinear(texture2D(colorTexture,vUv)).rgb,0.5*computeCoc()+0.5);\n#include <colorspace_fragment>\n}"; const d