@threepipe/webgi-plugins
Version:
WebGi - Realistic Rendering Plugins for ThreePipe.
732 lines • 222 kB
JavaScript
/**
* @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