From edcc7e20ddd45bdd31419364ee5754e98a42597e Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Tue, 28 Apr 2026 14:00:51 +0200 Subject: [PATCH] Add source size control to screen-space god rays rendering --- src/rendering/screen-space-god-rays.ts | 30 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/rendering/screen-space-god-rays.ts b/src/rendering/screen-space-god-rays.ts index 04f8d6ed..de573205 100644 --- a/src/rendering/screen-space-god-rays.ts +++ b/src/rendering/screen-space-god-rays.ts @@ -30,6 +30,8 @@ const MIN_CELESTIAL_LIGHT_INTENSITY = 1e-4; const MAX_GOD_RAYS_INTENSITY = 3; const MAX_GOD_RAYS_EXPOSURE = 2; const MAX_GOD_RAYS_DENSITY = 1.5; +const MIN_GOD_RAYS_SOURCE_SIZE = 0.25; +const MAX_GOD_RAYS_SOURCE_SIZE = 3; const MIN_GOD_RAYS_SAMPLES = 8; const MAX_GOD_RAYS_SAMPLES = 64; const LIGHT_OFFSCREEN_FADE_START = 0.92; @@ -49,6 +51,7 @@ export interface ResolvedGodRaysParameters { decay: number; exposure: number; density: number; + sourceSize: number; samples: number; } @@ -150,6 +153,11 @@ export function resolveGodRaysParameters( 0, MAX_GOD_RAYS_DENSITY ); + const sourceSize = clampNumber( + finiteOr(settings.sourceSize, 1), + MIN_GOD_RAYS_SOURCE_SIZE, + MAX_GOD_RAYS_SOURCE_SIZE + ); const samples = Math.round( clampNumber( finiteOr(settings.samples, MIN_GOD_RAYS_SAMPLES), @@ -169,6 +177,7 @@ export function resolveGodRaysParameters( decay, exposure, density, + sourceSize, samples }; } @@ -177,24 +186,29 @@ export function shouldApplyGodRays(settings: AdvancedRenderingSettings) { return settings.enabled && resolveGodRaysParameters(settings.godRays).enabled; } -export function resolveGodRaysSourceMask(sourceDistance: number): number { - if (!Number.isFinite(sourceDistance)) { +export function resolveGodRaysSourceMask( + sourceDistance: number, + sourceSize: number = 1 +): number { + if (!Number.isFinite(sourceDistance) || !Number.isFinite(sourceSize)) { return 0; } + const scaledSourceDistance = + sourceDistance / Math.max(sourceSize, MIN_GOD_RAYS_SOURCE_SIZE); const core = 1 - smoothstep( GOD_RAYS_SOURCE_MASK_RADII.coreInner, GOD_RAYS_SOURCE_MASK_RADII.coreOuter, - sourceDistance + scaledSourceDistance ); const halo = 1 - smoothstep( GOD_RAYS_SOURCE_MASK_RADII.haloInner, GOD_RAYS_SOURCE_MASK_RADII.haloOuter, - sourceDistance + scaledSourceDistance ); return clampNumber(core * 1.15 + halo * 0.55, 0, 1); @@ -290,13 +304,14 @@ const sourceMaskFragmentShader = ` uniform vec2 resolution; uniform vec2 lightPosition; uniform float sourceIntensity; +uniform float sourceSize; varying vec2 vUv; void main() { vec2 safeResolution = max(resolution, vec2(1.0)); vec2 aspectScale = vec2(safeResolution.x / safeResolution.y, 1.0); - float sourceDistance = length((vUv - lightPosition) * aspectScale); + float sourceDistance = length((vUv - lightPosition) * aspectScale) / max(sourceSize, ${formatGlslFloat(MIN_GOD_RAYS_SOURCE_SIZE)}); float core = 1.0 - smoothstep(${formatGlslFloat(GOD_RAYS_SOURCE_MASK_RADII.coreInner)}, ${formatGlslFloat(GOD_RAYS_SOURCE_MASK_RADII.coreOuter)}, sourceDistance); float halo = 1.0 - smoothstep(${formatGlslFloat(GOD_RAYS_SOURCE_MASK_RADII.haloInner)}, ${formatGlslFloat(GOD_RAYS_SOURCE_MASK_RADII.haloOuter)}, sourceDistance); float sourceMask = clamp(core * 1.15 + halo * 0.55, 0.0, 1.0); @@ -474,7 +489,8 @@ export class ScreenSpaceGodRaysPass extends Pass { uniforms: { resolution: new Uniform(this.maskResolution), lightPosition: new Uniform(this.lightPosition), - sourceIntensity: new Uniform(0) + sourceIntensity: new Uniform(0), + sourceSize: new Uniform(parameters.sourceSize) }, vertexShader, fragmentShader: sourceMaskFragmentShader, @@ -544,6 +560,8 @@ export class ScreenSpaceGodRaysPass extends Pass { renderer.clear(true, true, false); this.sourceMaskMaterial.uniforms.sourceIntensity.value = sourceIntensity; + this.sourceMaskMaterial.uniforms.sourceSize.value = + this.parameters.sourceSize; this.fullscreenMaterial = this.sourceMaskMaterial; renderer.render(this.scene, this.camera);