diff --git a/examples.html b/examples.html index db6b64a..ad7f17b 100644 --- a/examples.html +++ b/examples.html @@ -373,6 +373,7 @@ WebXR GLSL Shaders Debug Coloring + Depth of Field Editor
diff --git a/examples/depth-of-field/index.html b/examples/depth-of-field/index.html new file mode 100644 index 0000000..e7fd745 --- /dev/null +++ b/examples/depth-of-field/index.html @@ -0,0 +1,66 @@ + + + + + + + Spark • Depth of Field + + + + + + + + + diff --git a/index.html b/index.html index 908f5ca..c241b3a 100644 --- a/index.html +++ b/index.html @@ -145,6 +145,7 @@

Examples

  • WebXR
  • GLSL Shaders
  • Debug Coloring
  • +
  • Depth of Field
  • Editor
  • Viewer
  • diff --git a/src/SparkRenderer.ts b/src/SparkRenderer.ts index 7a94baf..8ecc99b 100644 --- a/src/SparkRenderer.ts +++ b/src/SparkRenderer.ts @@ -115,6 +115,10 @@ export type SparkRendererOptions = { // to correctly account for "blurring" when anti-aliasing. Typically 0.3 // (equivalent to approx 0.5 pixel radius) in scenes trained with anti-aliasing. blurAmount?: number; + // Depth-of-field distance to focal plane + focalDistance?: number; + // Full-width angle of aperture opening (in radians), default 0.0 to disable + apertureAngle?: number; // Modulate Gaussian kernel falloff. 0 means "no falloff, flat shading", // while 1 is the normal Gaussian kernel. (default: 1.0) falloff?: number; @@ -140,6 +144,8 @@ export class SparkRenderer extends THREE.Mesh { enable2DGS: boolean; preBlurAmount: number; blurAmount: number; + focalDistance: number; + apertureAngle: number; falloff: number; clipXY: number; @@ -241,6 +247,8 @@ export class SparkRenderer extends THREE.Mesh { this.enable2DGS = options.enable2DGS ?? true; this.preBlurAmount = options.preBlurAmount ?? 0.0; this.blurAmount = options.blurAmount ?? 0.3; + this.focalDistance = options.focalDistance ?? 0.0; + this.apertureAngle = options.apertureAngle ?? 0.0; this.falloff = options.falloff ?? 1.0; this.clipXY = options.clipXY ?? 1.4; @@ -287,6 +295,10 @@ export class SparkRenderer extends THREE.Mesh { preBlurAmount: { value: 0.0 }, // Add to 2D splat covariance diagonal and adjust opacity (anti-aliasing) blurAmount: { value: 0.3 }, + // Depth-of-field distance to focal plane + focalDistance: { value: 0.0 }, + // Full-width angle of aperture opening (in radians) + apertureAngle: { value: 0.0 }, // Modulate Gaussian kernal falloff. 0 means "no falloff, flat shading", // 1 is normal e^-x^2 falloff. falloff: { value: 1.0 }, @@ -424,6 +436,8 @@ export class SparkRenderer extends THREE.Mesh { this.uniforms.enable2DGS.value = this.enable2DGS; this.uniforms.preBlurAmount.value = this.preBlurAmount; this.uniforms.blurAmount.value = this.blurAmount; + this.uniforms.focalDistance.value = this.focalDistance; + this.uniforms.apertureAngle.value = this.apertureAngle; this.uniforms.falloff.value = this.falloff; this.uniforms.clipXY.value = this.clipXY; diff --git a/src/shaders/splatVertex.glsl b/src/shaders/splatVertex.glsl index 00a009b..c9e9893 100644 --- a/src/shaders/splatVertex.glsl +++ b/src/shaders/splatVertex.glsl @@ -22,6 +22,8 @@ uniform bool debugFlag; uniform bool enable2DGS; uniform float blurAmount; uniform float preBlurAmount; +uniform float focalDistance; +uniform float apertureAngle; uniform float clipXY; uniform usampler2DArray packedSplats; @@ -135,10 +137,21 @@ void main() { a += preBlurAmount; d += preBlurAmount; + float fullBlurAmount = blurAmount; + if ((focalDistance > 0.0) && (apertureAngle > 0.0)) { + float focusRadius = MAX_PIXEL_RADIUS; + if (viewCenter.z < 0.0) { + float focusBlur = abs((-viewCenter.z - focalDistance) / viewCenter.z); + float apertureRadius = focal.x * tan(0.5 * apertureAngle); + focusRadius = focusBlur * apertureRadius; + } + fullBlurAmount = clamp(sqr(focusRadius), blurAmount, sqr(MAX_PIXEL_RADIUS)); + } + // Do convolution with a 0.5-pixel Gaussian for anti-aliasing: sqrt(0.3) ~= 0.5 float detOrig = a * d - b * b; - a += blurAmount; - d += blurAmount; + a += fullBlurAmount; + d += fullBlurAmount; float det = a * d - b * b; // Compute anti-aliasing intensity scaling factor