@@ -146,7 +146,7 @@ const filterParamsType = d.struct({
146146 padHMask : d . u32 ,
147147 /** Normalized low-pass radius vs max toroidal √(hw²+hh²); keep r ≤ cutoff. */
148148 lowPassCutoff : d . f32 ,
149- /** Normalized high-pass inner radius; keep r > cutoff (DC at r = 0 is removed when cutoff = 0 ). */
149+ /** Normalized high-pass inner radius; keep ` r > cutoff`. `0` = high-pass **off** (do not attenuate DC or low r ). */
150150 highPassCutoff : d . f32 ,
151151 /** 1 when `Fft2d.skipFinalTranspose`: spectrum is `W×H` row-major with stride `padH` (`r*padH+c`), not `y*padW+x`. */
152152 swapSpectrumAxes : d . u32 ,
@@ -199,7 +199,9 @@ const filterKernel = tgpu.computeFn({
199199 const lowC = filterLayout . $ . params . lowPassCutoff * rMax ;
200200 const highC = filterLayout . $ . params . highPassCutoff * rMax ;
201201 const lowMask = std . select ( d . f32 ( 0 ) , d . f32 ( 1 ) , r <= lowC ) ;
202- const highMask = std . select ( d . f32 ( 0 ) , d . f32 ( 1 ) , r > highC ) ;
202+ const highPassOff = filterLayout . $ . params . highPassCutoff <= d . f32 ( 0 ) ;
203+ const highMaskInner = std . select ( d . f32 ( 0 ) , d . f32 ( 1 ) , r > highC ) ;
204+ const highMask = std . select ( highMaskInner , d . f32 ( 1 ) , highPassOff ) ;
203205 const mask = lowMask * highMask ;
204206 const c = filterLayout . $ . spectrum [ tid ] ;
205207 filterLayout . $ . spectrum [ tid ] = d . vec2f ( c . x * mask , c . y * mask ) ;
@@ -255,16 +257,15 @@ const magKernel = tgpu.computeFn({
255257 magLayout . $ . params . swapSpectrumAxes !== d . u32 ( 0 ) ,
256258 ) ;
257259 const cShift = magLayout . $ . spectrum [ srcTid ] ;
258- const len = std . sqrt ( cShift . x * cShift . x + cShift . y * cShift . y ) ;
259- /** Neutral at `exposure = 0` matches the former default `log(1+|·|) * 0.2` scale. */
260- const logv =
261- std . log ( 1.0 + len ) * 0.2 * std . exp2 ( magLayout . $ . params . exposure ) ;
260+ const lenRaw = std . sqrt ( cShift . x * cShift . x + cShift . y * cShift . y ) ;
261+ /** Log stretch tuned on these magnitudes (`log(1+|·|) * 0.2`). */
262+ const logv = std . log ( 1.0 + lenRaw ) * 0.2 * std . exp2 ( magLayout . $ . params . exposure ) ;
262263 const cv = std . clamp ( logv , 0.0 , 1.0 ) ;
263264 /** `cv` from log-magnitude; L ∈ [0.04, 1]; chroma → 0 at max `cv` so peaks go neutral white. */
264265 const L = 0.04 + cv * ( 1.0 - 0.04 ) ;
265266 const chroma = cv * ( 1.0 - cv ) * 0.32 ;
266267 /** Oklab a,b = chroma × unit phase — same as chroma·(cos θ, sin θ) with θ = atan2(im, re), without trig. */
267- const invLen = 1.0 / std . max ( len , 1e-20 ) ;
268+ const invLen = 1.0 / std . max ( lenRaw , 1e-20 ) ;
268269 const lab = d . vec3f ( L , chroma * invLen * cShift . x , chroma * invLen * cShift . y ) ;
269270 const rgb = oklabToLinearRgb ( oklabGamutClip . adaptiveL05 ( lab ) ) ;
270271 std . textureStore ( magLayout . $ . outTex , d . vec2u ( xLin , yLin ) , d . vec4f ( rgb , 1 ) ) ;
@@ -275,7 +276,7 @@ const spatialParamsType = d.struct({
275276 padH : d . u32 ,
276277 padWLog2 : d . u32 ,
277278 padWMask : d . u32 ,
278- /** `1 / (padW * padH)` — unnormalized inverse scaling . */
279+ /** Linear gain on real part after inverse FFT (`1` = full amplitude in buffer) . */
279280 invSize : d . f32 ,
280281 /** Same EV as spectrum: linear sample is multiplied by `exp2(exposure)` before clamp. */
281282 exposure : d . f32 ,
@@ -490,7 +491,7 @@ let applyInverseFft = false;
490491let exposureEv = 0 ;
491492/** Normalized low-pass radius vs max toroidal radius (1 = no attenuation). */
492493let lowPassCutoffNorm = 1 ;
493- /** Normalized high-pass inner radius (0 = no AC attenuation from this term ). */
494+ /** Normalized high-pass inner radius (`0` = high-pass off; spectrum passes through to low-pass only ). */
494495let highPassCutoffNorm = 0 ;
495496/** Separable Hann window on camera ROI before FFT (reduces periodic-boundary cross in spectrum). */
496497let applyEdgeWindow = false ;
@@ -757,7 +758,7 @@ function processVideoFrame(_: number, metadata: VideoFrameCallbackMetadata) {
757758 padH,
758759 padWLog2,
759760 padWMask : padW - 1 ,
760- invSize : 1 / ( padW * padH ) ,
761+ invSize : 1 ,
761762 exposure : exposureEv ,
762763 } ) ;
763764 }
@@ -868,8 +869,8 @@ export const controls = defineControls({
868869 } ,
869870 exposure : {
870871 initial : exposureEv ,
871- min : - 4 ,
872- max : 4 ,
872+ min : - 8 ,
873+ max : 8 ,
873874 step : 0.05 ,
874875 onSliderChange : ( value ) => {
875876 exposureEv = value ;
0 commit comments