From b08f4c22eb54235e5cdb95108b5c084990f8af7e Mon Sep 17 00:00:00 2001 From: Noeri Huisman <8823461+mrxz@users.noreply.github.com> Date: Mon, 1 Jun 2026 18:30:01 +0200 Subject: [PATCH 1/2] Infer encodeLinear from the current render target --- src/SparkRenderer.ts | 57 +++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/src/SparkRenderer.ts b/src/SparkRenderer.ts index 63a1e204..f3f3fecb 100644 --- a/src/SparkRenderer.ts +++ b/src/SparkRenderer.ts @@ -40,11 +40,6 @@ export interface SparkRendererOptions { * @default true */ premultipliedAlpha?: boolean; - /** - * Whether to encode Gsplat with linear RGB (for environment mapping) - * @default false - */ - encodeLinear?: boolean; /** * Pass in a THREE.Clock to synchronize time-based effects across different * systems. Alternatively, you can set the property time directly. @@ -353,7 +348,6 @@ export class SparkRenderer extends THREE.Mesh { falloff: number; clipXY: number; focalAdjustment: number; - encodeLinear: boolean; sortRadial: boolean; minSortIntervalMs: number; @@ -525,7 +519,6 @@ export class SparkRenderer extends THREE.Mesh { this.falloff = options.falloff ?? 1.0; this.clipXY = options.clipXY ?? 1.4; this.focalAdjustment = options.focalAdjustment ?? 1.0; - this.encodeLinear = options.encodeLinear ?? false; this.sortRadial = options.sortRadial ?? true; this.minSortIntervalMs = options.minSortIntervalMs ?? 0; @@ -612,7 +605,6 @@ export class SparkRenderer extends THREE.Mesh { targetOptions, ); } - this.encodeLinear = options.encodeLinear ?? true; } } @@ -741,21 +733,30 @@ export class SparkRenderer extends THREE.Mesh { const isNewFrame = frame !== spark.lastFrame; spark.lastFrame = frame; - if (spark.target) { - spark.renderSize.set(spark.target.width, spark.target.height); - } else { - const renderSize = renderer.getDrawingBufferSize(spark.renderSize); - if (renderer.xr.isPresenting) { - if (renderSize.x === 1 && renderSize.y === 1) { - // WebXR mode on Apple Vision Pro returns 1x1 when presenting. - // Use a different means to figure out the render size. - const baseLayer = renderer.xr.getSession()?.renderState.baseLayer; - if (baseLayer) { - renderSize.x = baseLayer.framebufferWidth; - renderSize.y = baseLayer.framebufferHeight; - } + // Determine render target + const currentRenderTarget = renderer.getRenderTarget(); + const isXRRenderTarget = checkIsXRRenderTarget(currentRenderTarget); + if (currentRenderTarget) { + spark.renderSize.set( + currentRenderTarget.width, + currentRenderTarget.height, + ); + + // WebXR mode on Apple Vision Pro returns 1x1 when presenting. + // Use a different means to figure out the render size. + if ( + isXRRenderTarget && + spark.renderSize.x === 1 && + spark.renderSize.y === 1 + ) { + const baseLayer = renderer.xr.getSession()?.renderState.baseLayer; + if (baseLayer) { + spark.renderSize.x = baseLayer.framebufferWidth; + spark.renderSize.y = baseLayer.framebufferHeight; } } + } else { + renderer.getDrawingBufferSize(spark.renderSize); } this.uniforms.renderSize.value.copy(spark.renderSize); @@ -797,7 +798,15 @@ export class SparkRenderer extends THREE.Mesh { this.uniforms.falloff.value = spark.falloff; this.uniforms.clipXY.value = spark.clipXY; this.uniforms.focalAdjustment.value = spark.focalAdjustment; - this.uniforms.encodeLinear.value = spark.encodeLinear; + + const outputColorSpace = + currentRenderTarget === null + ? renderer.outputColorSpace + : isXRRenderTarget + ? currentRenderTarget.texture.colorSpace + : THREE.ColorManagement.workingColorSpace; + this.uniforms.encodeLinear.value = + outputColorSpace !== THREE.SRGBColorSpace; this.uniforms.ordering.value = spark.orderingTexture ?? SparkRenderer.emptyOrdering; @@ -2107,3 +2116,7 @@ export class SparkRenderer extends THREE.Mesh { } } } + +function checkIsXRRenderTarget(renderTarget: THREE.RenderTarget | null) { + return (renderTarget as unknown as Record)?.isXRRenderTarget; +} From e5429f141516ed2475c47ffcb4dd3df3c06feb7d Mon Sep 17 00:00:00 2001 From: Noeri Huisman <8823461+mrxz@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:31:12 +0200 Subject: [PATCH 2/2] Remove mention of encodeLinear from the docs --- docs/docs/spark-renderer.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/docs/spark-renderer.md b/docs/docs/spark-renderer.md index c3cc0ad7..2273b50c 100644 --- a/docs/docs/spark-renderer.md +++ b/docs/docs/spark-renderer.md @@ -32,7 +32,6 @@ const spark = new SparkRenderer({ | **Parameter** | Description | | ----------------- | ----------- | | **premultipliedAlpha** | Whether to use premultiplied alpha when accumulating splat RGB. (default: `true`) -| **encodeLinear** | Whether to encode Gsplat with linear RGB (for example for rendering environment maps). (default: `false`) | **clock** | Pass in a `THREE.Clock` to synchronize time-based effects across different systems. Alternatively, you can set the `SparkRenderer` properties `time` and `deltaTime` directly. (default: `new THREE.Clock`) | **autoUpdate** | Controls whether to check and automatically update splat collection each frame render. (default: `true`) | **preUpdate** | Controls whether to update the splats before or after rendering. For WebXR this is set to `false` in order to complete rendering as soon as possible. (default: `true` if not WebXR)