@hology/core 0.0.249 → 0.0.251

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/effects/vfx/gpu-sprite-runtime.js +1 -1
  2. package/dist/effects/vfx/gpu-vfx-world-service.js +1 -1
  3. package/dist/gameplay/actors/actor.js +1 -1
  4. package/dist/gameplay/actors/camera/third-person-camera-component.js +1 -1
  5. package/dist/gameplay/ai/dynamic-tiled-navmesh.js +1 -1
  6. package/dist/gameplay/initiate.d.ts +4 -0
  7. package/dist/gameplay/initiate.js +1 -1
  8. package/dist/gameplay/services/render.d.ts +11 -3
  9. package/dist/gameplay/services/render.js +1 -1
  10. package/dist/rendering/native-dlss-upscaler.d.ts +104 -0
  11. package/dist/rendering/native-dlss-upscaler.js +4 -0
  12. package/dist/rendering/node-material-webgpu-resolver.d.ts +2 -1
  13. package/dist/rendering/node-material-webgpu-resolver.js +1 -1
  14. package/dist/rendering/post-process-effect.d.ts +1 -1
  15. package/dist/rendering/post-process-effect.js +1 -1
  16. package/dist/rendering/rendering-backend.d.ts +9 -0
  17. package/dist/rendering/rendering-backend.js +4 -0
  18. package/dist/rendering/upscaling-pass.d.ts +9 -1
  19. package/dist/rendering/upscaling-pass.js +1 -1
  20. package/dist/rendering/webgl-backend.d.ts +32 -0
  21. package/dist/rendering/webgl-backend.js +4 -0
  22. package/dist/rendering/webgpu-experimental-backend.d.ts +19 -2
  23. package/dist/rendering/webgpu-experimental-backend.js +1 -1
  24. package/dist/rendering/webgpu-runtime-bridge.d.ts +22 -0
  25. package/dist/rendering/webgpu-runtime-bridge.js +4 -0
  26. package/dist/rendering.d.ts +45 -16
  27. package/dist/rendering.js +1 -1
  28. package/dist/scene/asset-resource-loader.d.ts +5 -0
  29. package/dist/scene/asset-resource-loader.js +1 -1
  30. package/dist/scene/materializer.js +1 -1
  31. package/dist/scene/materials/water.js +1 -1
  32. package/dist/scene/runtime-bundled-backend-service.d.ts +7 -0
  33. package/dist/scene/runtime-bundled-backend-service.js +1 -1
  34. package/dist/scene/storage/packed-json.js +1 -1
  35. package/dist/secondary-motion/runtime.d.ts +1 -1
  36. package/dist/secondary-motion/runtime.js +1 -1
  37. package/dist/test/actor-attachment.test.d.ts +2 -0
  38. package/dist/test/actor-attachment.test.js +4 -0
  39. package/dist/test/gpu-sprite-compiler.test.js +1 -1
  40. package/dist/test/native-dlss-upscaler.test.d.ts +2 -0
  41. package/dist/test/native-dlss-upscaler.test.js +4 -0
  42. package/dist/test/node-material-webgpu-resolver.test.js +1 -1
  43. package/dist/test/webgpu-experimental-backend.test.js +1 -1
  44. package/dist/utils/uuid.js +1 -1
  45. package/package.json +1 -1
  46. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,4 @@
1
- import{FullScreenQuad as e,Pass as t}from"three/examples/jsm/Addons.js";import{NodeShaderMaterial as s}from"../shader-nodes/index.js";import{depthUniformName as r,farUniformName as i,nearUniformName as o,resolutionUniformName as n,sceneNormalUniformName as a}from"../shader-nodes/depth.js";import{aoMapUniformName as f,sceneMapUniformName as l}from"../shader-nodes/scene-sample.js";import{elapsedTimeUniformName as u}from"../shader-nodes/time.js";export const postProcessEffectStages=["beforeFog","beforeDepthOfField","beforeColorAdjustment","beforeOutline","beforeAntiAliasing","beforeLut","beforeOutput"];export const defaultPostProcessEffectStage="beforeOutput";export function applyPostProcessEffectUniformState(e,t){null!=e.uniforms[n]&&e.uniforms[n].value.copy(t.resolution),null!=e.uniforms[r]&&(e.uniforms[r].value=t.depthTexture),null!=e.uniforms[a]&&(e.uniforms[a].value=t.normalTexture),null!=e.uniforms[o]&&null!=t.cameraNear&&(e.uniforms[o].value=t.cameraNear),null!=e.uniforms[i]&&null!=t.cameraFar&&(e.uniforms[i].value=t.cameraFar),null!=e.uniforms[u]&&(e.uniforms[u].value=t.simulationTime),null!=e.uniforms[f]&&(e.uniforms[f].value=t.aoTexture),e instanceof s&&null!=e.uniforms[f]&&(t.aoEnabled?(null==e.defines.USE_SSAO_MAP&&(e.needsUpdate=!0),e.defines.USE_SSAO_MAP=""):null!=e.defines.USE_SSAO_MAP&&(delete e.defines.USE_SSAO_MAP,e.needsUpdate=!0))}export function sanitizePostProcessEffectStage(e){return e??"beforeOutput"}export function sanitizePostProcessEffectPriority(e){return null!=e&&Number.isFinite(e)?e:0}export class PostProcessEffectRegistration{constructor(e,t){this.owner=e,this.entry=t,this.disposed=!1}get material(){return this.entry.material}get enabled(){return this.entry.enabled}set enabled(e){this.entry.enabled!==e&&(this.entry.enabled=e,this.entry.pass.enabled=e,this.owner.refreshPostProcessEffectPassOrder())}get priority(){return this.entry.priority}set priority(e){const t=sanitizePostProcessEffectPriority(e);this.entry.priority!==t&&(this.entry.priority=t,this.owner.refreshPostProcessEffectPassOrder())}get stage(){return this.entry.stage}set stage(e){const t=sanitizePostProcessEffectStage(e);this.entry.stage!==t&&(this.entry.stage=t,this.owner.refreshPostProcessEffectPassOrder())}dispose(){this.disposed||(this.disposed=!0,this.owner.removePostProcessEffectEntry(this.entry))}}export class PostProcessEffectPass extends t{constructor(t){super(),this.material=t,this.material.depthWrite=!1,this.material.depthTest=!1,this.material.toneMapped=!1,this.fsQuad=new e(this.material),this.needsSwap=!0,this.clear=!1}updateUniformState(e){applyPostProcessEffectUniformState(this.material,e)}setMaterial(e){this.fsQuad.material=e,this.material=e}render(e,t,s,r,i){if(null!=this.material.uniforms[l]&&(this.material.uniforms[l].value=s.texture),this.renderToScreen)return e.setRenderTarget(null),this.clear&&e.clear(),void this.fsQuad.render(e);e.setRenderTarget(t),this.clear&&e.clear(),this.fsQuad.render(e)}dispose(){this.fsQuad.dispose()}}/*
1
+ import{FullScreenQuad as e,Pass as t}from"three/examples/jsm/Addons.js";import{NodeShaderMaterial as s}from"../shader-nodes/index.js";import{depthUniformName as r,farUniformName as i,nearUniformName as o,resolutionUniformName as n,sceneNormalUniformName as a}from"../shader-nodes/depth.js";import{aoMapUniformName as f,sceneMapUniformName as l}from"../shader-nodes/scene-sample.js";import{elapsedTimeUniformName as u}from"../shader-nodes/time.js";export const postProcessEffectStages=["beforeFog","beforeDepthOfField","beforeColorAdjustment","beforeOutline","beforeAntiAliasing","beforeLut","beforeOutput"];export const defaultPostProcessEffectStage="beforeOutput";export function applyPostProcessEffectUniformState(e,t){null!=e.uniforms[n]&&e.uniforms[n].value.copy(t.resolution),null!=e.uniforms[r]&&(e.uniforms[r].value=t.depthTexture),null!=e.uniforms[a]&&(e.uniforms[a].value=t.normalTexture),null!=e.uniforms[o]&&null!=t.cameraNear&&(e.uniforms[o].value=t.cameraNear),null!=e.uniforms[i]&&null!=t.cameraFar&&(e.uniforms[i].value=t.cameraFar),null!=e.uniforms[u]&&(e.uniforms[u].value=t.simulationTime),null!=e.uniforms[f]&&(e.uniforms[f].value=t.aoTexture),e instanceof s&&null!=e.uniforms[f]&&(t.aoEnabled?(null==e.defines.USE_SSAO_MAP&&(e.needsUpdate=!0),e.defines.USE_SSAO_MAP=""):null!=e.defines.USE_SSAO_MAP&&(delete e.defines.USE_SSAO_MAP,e.needsUpdate=!0))}export function sanitizePostProcessEffectStage(e){return e??"beforeOutput"}export function sanitizePostProcessEffectPriority(e){return null!=e&&Number.isFinite(e)?e:0}export class PostProcessEffectRegistration{constructor(e,t){this.owner=e,this.entry=t,this.disposed=!1}get material(){return this.entry.material}get enabled(){return this.entry.enabled}set enabled(e){this.entry.enabled!==e&&(this.entry.enabled=e,null!=this.entry.pass&&(this.entry.pass.enabled=e),this.owner.refreshPostProcessEffectPassOrder())}get priority(){return this.entry.priority}set priority(e){const t=sanitizePostProcessEffectPriority(e);this.entry.priority!==t&&(this.entry.priority=t,this.owner.refreshPostProcessEffectPassOrder())}get stage(){return this.entry.stage}set stage(e){const t=sanitizePostProcessEffectStage(e);this.entry.stage!==t&&(this.entry.stage=t,this.owner.refreshPostProcessEffectPassOrder())}dispose(){this.disposed||(this.disposed=!0,this.owner.removePostProcessEffectEntry(this.entry))}}export class PostProcessEffectPass extends t{constructor(t){super(),this.material=t,this.material.depthWrite=!1,this.material.depthTest=!1,this.material.toneMapped=!1,this.fsQuad=new e(this.material),this.needsSwap=!0,this.clear=!1}updateUniformState(e){applyPostProcessEffectUniformState(this.material,e)}setMaterial(e){this.fsQuad.material=e,this.material=e}render(e,t,s,r,i){if(null!=this.material.uniforms[l]&&(this.material.uniforms[l].value=s.texture),this.renderToScreen)return e.setRenderTarget(null),this.clear&&e.clear(),void this.fsQuad.render(e);e.setRenderTarget(t),this.clear&&e.clear(),this.fsQuad.render(e)}dispose(){this.fsQuad.dispose()}}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -0,0 +1,9 @@
1
+ import type { Texture } from 'three';
2
+ /** Backend-neutral operations used by RenderingView and resource materializers. */
3
+ export interface RenderingBackendDriver {
4
+ readonly kind: 'webgl' | 'webgpu';
5
+ readonly canvas: HTMLCanvasElement;
6
+ initTexture(texture: Texture): void;
7
+ getEnvironmentTexture(texture: Texture): Texture;
8
+ }
9
+ //# sourceMappingURL=rendering-backend.d.ts.map
@@ -0,0 +1,4 @@
1
+ export{};/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -1,6 +1,11 @@
1
1
  import * as THREE from 'three';
2
2
  import { Pass } from 'three/examples/jsm/postprocessing/Pass.js';
3
- export type UpscalingMethod = 'linear' | 'spatial' | 'catmull-rom' | 'temporal';
3
+ export type UpscalingMethod = 'linear' | 'spatial' | 'catmull-rom' | 'temporal' | 'dlss';
4
+ export type DlssQualityMode = 'quality' | 'balanced' | 'performance' | 'ultra-performance';
5
+ export type DlssUpscalingOptions = {
6
+ /** Streamline DLSS performance/quality mode. Defaults to `quality`. */
7
+ mode?: DlssQualityMode;
8
+ };
4
9
  export type TemporalUpscalingOptions = {
5
10
  /**
6
11
  * How strongly history contributes to the current frame. Defaults to 0.88.
@@ -15,6 +20,8 @@ export type UpscalingOptions = {
15
20
  enabled?: boolean;
16
21
  /**
17
22
  * `temporal` jitters the projection and accumulates history using depth reprojection.
23
+ * `dlss` requests native DLSS Super Resolution and falls back to temporal
24
+ * upscaling when the host does not expose a compatible implementation.
18
25
  * `spatial` and `catmull-rom` are single-frame upscalers with sharpening.
19
26
  * `linear` only decouples render and presentation resolutions.
20
27
  */
@@ -24,6 +31,7 @@ export type UpscalingOptions = {
24
31
  */
25
32
  sharpness?: number;
26
33
  temporal?: TemporalUpscalingOptions;
34
+ dlss?: DlssUpscalingOptions;
27
35
  };
28
36
  export type TemporalUpscalingFrameState = {
29
37
  depthTexture: THREE.Texture | null;
@@ -1,4 +1,4 @@
1
- import*as e from"three";import{Pass as t,FullScreenQuad as r}from"three/examples/jsm/postprocessing/Pass.js";export function getUpscalingMethod(e){return e?.method??"spatial"}export function getTemporalUpscalingJitter(e,t,r=1){return t.set((n(e%1024+1,2)-.5)*r,(n(e%1024+1,3)-.5)*r),t}export class UpscaleOutputPass extends t{constructor(t={}){super(),this.options=t,this.uniforms={tDiffuse:{value:null},tDepth:{value:null},tHistory:{value:null},toneMappingExposure:{value:1},inputSize:{value:new e.Vector2(1,1)},sharpness:{value:.2},temporalFeedback:{value:.88},historyValid:{value:0},currentJitterUv:{value:new e.Vector2},currentViewProjectionInverse:{value:new e.Matrix4},previousViewProjection:{value:new e.Matrix4}},this.drawingBufferSize=new e.Vector2,this.historyRead=null,this.historyWrite=null,this.historyValid=!1,this.frameState=null,this._outputColorSpace=null,this._toneMapping=null,this._method=null,this._usesCatmullRom=null,this._usesTemporal=null,this.material=new e.RawShaderMaterial({name:"UpscaleOutputPass",uniforms:this.uniforms,vertexShader:o,fragmentShader:a}),this.fsQuad=new r(this.material)}setFrameState(e){this.frameState=e}resetHistory(){this.historyValid=!1}render(t,r,n){t.getDrawingBufferSize(this.drawingBufferSize);const o=getUpscalingMethod(this.options),a=n.width<this.drawingBufferSize.x-.5||n.height<this.drawingBufferSize.y-.5,s="temporal"===o&&null!=this.frameState&&null!=this.frameState.depthTexture,l=a&&(s||"spatial"===o||"catmull-rom"===o);if(this.uniforms.tDiffuse.value=n.texture,this.uniforms.tDepth.value=this.frameState?.depthTexture??null,this.uniforms.toneMappingExposure.value=t.toneMappingExposure,this.uniforms.inputSize.value.set(n.width,n.height),this.uniforms.sharpness.value=e.MathUtils.clamp(i(this.options.sharpness,.2),0,1),this.uniforms.temporalFeedback.value=e.MathUtils.clamp(i(this.options.temporal?.feedback,.88),0,.97),s?(this.ensureHistoryTargets(this.drawingBufferSize.x,this.drawingBufferSize.y),this.uniforms.tHistory.value=this.historyRead?.texture??null,this.uniforms.historyValid.value=this.historyValid?1:0,this.uniforms.currentJitterUv.value.copy(this.frameState.currentJitterUv),this.uniforms.currentViewProjectionInverse.value.copy(this.frameState.currentViewProjectionInverse),this.uniforms.previousViewProjection.value.copy(this.frameState.previousViewProjection)):(this.uniforms.tHistory.value=null,this.uniforms.historyValid.value=0,this.uniforms.currentJitterUv.value.set(0,0)),this.updateDefines(t,o,l,s),!0===this.renderToScreen?(t.setRenderTarget(null),this.fsQuad.render(t)):(t.setRenderTarget(r),this.clear&&t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil),this.fsQuad.render(t)),s&&null!=this.historyWrite){t.setRenderTarget(this.historyWrite),this.fsQuad.render(t);const e=this.historyRead;this.historyRead=this.historyWrite,this.historyWrite=e,this.historyValid=!0}else s||(this.historyValid=!1)}dispose(){this.material.dispose(),this.fsQuad.dispose(),this.disposeHistoryTargets()}updateDefines(t,r,i,n){this._outputColorSpace===t.outputColorSpace&&this._toneMapping===t.toneMapping&&this._method===r&&this._usesCatmullRom===i&&this._usesTemporal===n||(this._outputColorSpace=t.outputColorSpace,this._toneMapping=t.toneMapping,this._method=r,this._usesCatmullRom=i,this._usesTemporal=n,this.material.defines={},i&&(this.material.defines.CATMULL_ROM_UPSCALE=""),n&&(this.material.defines.TEMPORAL_UPSCALE=""),e.ColorManagement.getTransfer(t.outputColorSpace)===e.SRGBTransfer&&(this.material.defines.SRGB_TRANSFER=""),t.toneMapping===e.LinearToneMapping?this.material.defines.LINEAR_TONE_MAPPING="":t.toneMapping===e.ReinhardToneMapping?this.material.defines.REINHARD_TONE_MAPPING="":t.toneMapping===e.CineonToneMapping?this.material.defines.CINEON_TONE_MAPPING="":t.toneMapping===e.ACESFilmicToneMapping?this.material.defines.ACES_FILMIC_TONE_MAPPING="":t.toneMapping===e.AgXToneMapping?this.material.defines.AGX_TONE_MAPPING="":t.toneMapping===e.NeutralToneMapping&&(this.material.defines.NEUTRAL_TONE_MAPPING=""),this.material.needsUpdate=!0)}ensureHistoryTargets(e,t){const r=Math.max(1,Math.floor(e)),i=Math.max(1,Math.floor(t));null!=this.historyRead&&null!=this.historyWrite&&this.historyRead.width===r&&this.historyRead.height===i||(this.disposeHistoryTargets(),this.historyRead=this.createHistoryTarget(r,i,"UpscaleOutputPass.historyRead"),this.historyWrite=this.createHistoryTarget(r,i,"UpscaleOutputPass.historyWrite"),this.historyValid=!1)}createHistoryTarget(t,r,i){const n=new e.WebGLRenderTarget(t,r,{type:e.HalfFloatType,minFilter:e.LinearFilter,magFilter:e.LinearFilter,format:e.RGBAFormat,depthBuffer:!1,stencilBuffer:!1});return n.texture.name=i,n.texture.generateMipmaps=!1,n}disposeHistoryTargets(){this.historyRead?.dispose(),this.historyWrite?.dispose(),this.historyRead=null,this.historyWrite=null,this.historyValid=!1}}function i(e,t){return null!=e&&Number.isFinite(e)?e:t}function n(e,t){let r=0,i=1/t;for(;e>0;)r+=i*(e%t),e=Math.floor(e/t),i/=t;return r}const o="\n precision highp float;\n\n uniform mat4 modelViewMatrix;\n uniform mat4 projectionMatrix;\n\n attribute vec3 position;\n attribute vec2 uv;\n\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n",a="\n precision highp float;\n\n uniform sampler2D tDiffuse;\n uniform sampler2D tDepth;\n uniform sampler2D tHistory;\n uniform vec2 inputSize;\n uniform float sharpness;\n uniform float temporalFeedback;\n uniform float historyValid;\n uniform vec2 currentJitterUv;\n uniform mat4 currentViewProjectionInverse;\n uniform mat4 previousViewProjection;\n\n #include <common>\n #include <tonemapping_pars_fragment>\n #include <colorspace_pars_fragment>\n #include <dithering_pars_fragment>\n\n varying vec2 vUv;\n\n vec4 applyOutputTransform(vec4 color) {\n #ifdef LINEAR_TONE_MAPPING\n color.rgb = LinearToneMapping(color.rgb);\n #elif defined(REINHARD_TONE_MAPPING)\n color.rgb = ReinhardToneMapping(color.rgb);\n #elif defined(CINEON_TONE_MAPPING)\n color.rgb = CineonToneMapping(color.rgb);\n #elif defined(ACES_FILMIC_TONE_MAPPING)\n color.rgb = ACESFilmicToneMapping(color.rgb);\n #elif defined(AGX_TONE_MAPPING)\n color.rgb = AgXToneMapping(color.rgb);\n #elif defined(NEUTRAL_TONE_MAPPING)\n color.rgb = NeutralToneMapping(color.rgb);\n #endif\n\n #ifdef SRGB_TRANSFER\n color = sRGBTransferOETF(color);\n #endif\n\n return color;\n }\n\n vec4 readOutputColor(vec2 uv) {\n return applyOutputTransform(texture2D(tDiffuse, clamp(uv, vec2(0.0), vec2(1.0))));\n }\n\n float cubicWeight(float value) {\n value = abs(value);\n float value2 = value * value;\n float value3 = value2 * value;\n if (value <= 1.0) {\n return 1.5 * value3 - 2.5 * value2 + 1.0;\n }\n if (value < 2.0) {\n return -0.5 * value3 + 2.5 * value2 - 4.0 * value + 2.0;\n }\n return 0.0;\n }\n\n vec4 sampleCatmullRom(vec2 uv) {\n vec2 texelSize = 1.0 / inputSize;\n vec2 pixel = uv * inputSize - 0.5;\n vec2 basePixel = floor(pixel);\n vec2 fraction = pixel - basePixel;\n vec4 color = vec4(0.0);\n float weightSum = 0.0;\n\n for (int y = -1; y <= 2; y++) {\n float wy = cubicWeight(float(y) - fraction.y);\n for (int x = -1; x <= 2; x++) {\n float wx = cubicWeight(float(x) - fraction.x);\n float weight = wx * wy;\n vec2 sampleUv = (basePixel + vec2(float(x), float(y)) + 0.5) * texelSize;\n color += readOutputColor(sampleUv) * weight;\n weightSum += weight;\n }\n }\n\n return color / max(weightSum, 0.00001);\n }\n\n void getNeighborhoodBounds(vec2 uv, out vec3 minColor, out vec3 maxColor, out vec3 blurColor) {\n vec2 texelSize = 1.0 / inputSize;\n vec3 center = readOutputColor(uv).rgb;\n vec3 north = readOutputColor(uv + vec2(0.0, texelSize.y)).rgb;\n vec3 south = readOutputColor(uv - vec2(0.0, texelSize.y)).rgb;\n vec3 east = readOutputColor(uv + vec2(texelSize.x, 0.0)).rgb;\n vec3 west = readOutputColor(uv - vec2(texelSize.x, 0.0)).rgb;\n minColor = min(center, min(min(north, south), min(east, west)));\n maxColor = max(center, max(max(north, south), max(east, west)));\n blurColor = (north + south + east + west) * 0.25;\n }\n\n vec3 applyContrastLimitedSharpen(vec2 uv, vec3 color) {\n vec3 minColor;\n vec3 maxColor;\n vec3 blurColor;\n getNeighborhoodBounds(uv, minColor, maxColor, blurColor);\n return clamp(color + (color - blurColor) * sharpness, minColor, maxColor);\n }\n\n vec2 reprojectHistoryUv(vec2 uv, float depth) {\n vec4 clip = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);\n vec4 world = currentViewProjectionInverse * clip;\n world /= max(abs(world.w), 0.00001);\n vec4 previousClip = previousViewProjection * world;\n vec3 previousNdc = previousClip.xyz / max(abs(previousClip.w), 0.00001);\n return previousNdc.xy * 0.5 + 0.5;\n }\n\n vec4 applyTemporal(vec2 currentUv, vec4 currentColor) {\n if (historyValid < 0.5) {\n return currentColor;\n }\n\n float depth = texture2D(tDepth, clamp(currentUv, vec2(0.0), vec2(1.0))).x;\n if (depth <= 0.0 || depth >= 1.0) {\n return currentColor;\n }\n\n vec2 historyUv = reprojectHistoryUv(currentUv, depth);\n if (\n historyUv.x < 0.0 || historyUv.x > 1.0 ||\n historyUv.y < 0.0 || historyUv.y > 1.0\n ) {\n return currentColor;\n }\n\n vec3 minColor;\n vec3 maxColor;\n vec3 blurColor;\n getNeighborhoodBounds(currentUv, minColor, maxColor, blurColor);\n vec4 historyColor = texture2D(tHistory, historyUv);\n historyColor.rgb = clamp(historyColor.rgb, minColor, maxColor);\n return mix(currentColor, historyColor, temporalFeedback);\n }\n\n void main() {\n vec2 currentUv = vUv;\n #ifdef TEMPORAL_UPSCALE\n currentUv -= currentJitterUv;\n #endif\n\n #ifdef CATMULL_ROM_UPSCALE\n gl_FragColor = sampleCatmullRom(currentUv);\n gl_FragColor.rgb = applyContrastLimitedSharpen(currentUv, gl_FragColor.rgb);\n #else\n gl_FragColor = readOutputColor(currentUv);\n #endif\n\n #ifdef TEMPORAL_UPSCALE\n gl_FragColor = applyTemporal(currentUv, gl_FragColor);\n #endif\n\n #include <dithering_fragment>\n }\n";/*
1
+ import*as e from"three";import{Pass as t,FullScreenQuad as r}from"three/examples/jsm/postprocessing/Pass.js";export function getUpscalingMethod(e){return e?.method??"spatial"}export function getTemporalUpscalingJitter(e,t,r=1){return t.set((n(e%1024+1,2)-.5)*r,(n(e%1024+1,3)-.5)*r),t}export class UpscaleOutputPass extends t{constructor(t={}){super(),this.options=t,this.uniforms={tDiffuse:{value:null},tDepth:{value:null},tHistory:{value:null},toneMappingExposure:{value:1},inputSize:{value:new e.Vector2(1,1)},sharpness:{value:.2},temporalFeedback:{value:.88},historyValid:{value:0},currentJitterUv:{value:new e.Vector2},currentViewProjectionInverse:{value:new e.Matrix4},previousViewProjection:{value:new e.Matrix4}},this.drawingBufferSize=new e.Vector2,this.historyRead=null,this.historyWrite=null,this.historyValid=!1,this.frameState=null,this._outputColorSpace=null,this._toneMapping=null,this._method=null,this._usesCatmullRom=null,this._usesTemporal=null,this.material=new e.RawShaderMaterial({name:"UpscaleOutputPass",uniforms:this.uniforms,vertexShader:o,fragmentShader:a}),this.fsQuad=new r(this.material)}setFrameState(e){this.frameState=e}resetHistory(){this.historyValid=!1}render(t,r,n){t.getDrawingBufferSize(this.drawingBufferSize);const o=getUpscalingMethod(this.options),a=n.width<this.drawingBufferSize.x-.5||n.height<this.drawingBufferSize.y-.5,s=("temporal"===o||"dlss"===o)&&null!=this.frameState&&null!=this.frameState.depthTexture,l=a&&(s||"spatial"===o||"catmull-rom"===o);if(this.uniforms.tDiffuse.value=n.texture,this.uniforms.tDepth.value=this.frameState?.depthTexture??null,this.uniforms.toneMappingExposure.value=t.toneMappingExposure,this.uniforms.inputSize.value.set(n.width,n.height),this.uniforms.sharpness.value=e.MathUtils.clamp(i(this.options.sharpness,.2),0,1),this.uniforms.temporalFeedback.value=e.MathUtils.clamp(i(this.options.temporal?.feedback,.88),0,.97),s?(this.ensureHistoryTargets(this.drawingBufferSize.x,this.drawingBufferSize.y),this.uniforms.tHistory.value=this.historyRead?.texture??null,this.uniforms.historyValid.value=this.historyValid?1:0,this.uniforms.currentJitterUv.value.copy(this.frameState.currentJitterUv),this.uniforms.currentViewProjectionInverse.value.copy(this.frameState.currentViewProjectionInverse),this.uniforms.previousViewProjection.value.copy(this.frameState.previousViewProjection)):(this.uniforms.tHistory.value=null,this.uniforms.historyValid.value=0,this.uniforms.currentJitterUv.value.set(0,0)),this.updateDefines(t,o,l,s),!0===this.renderToScreen?(t.setRenderTarget(null),this.fsQuad.render(t)):(t.setRenderTarget(r),this.clear&&t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil),this.fsQuad.render(t)),s&&null!=this.historyWrite){t.setRenderTarget(this.historyWrite),this.fsQuad.render(t);const e=this.historyRead;this.historyRead=this.historyWrite,this.historyWrite=e,this.historyValid=!0}else s||(this.historyValid=!1)}dispose(){this.material.dispose(),this.fsQuad.dispose(),this.disposeHistoryTargets()}updateDefines(t,r,i,n){this._outputColorSpace===t.outputColorSpace&&this._toneMapping===t.toneMapping&&this._method===r&&this._usesCatmullRom===i&&this._usesTemporal===n||(this._outputColorSpace=t.outputColorSpace,this._toneMapping=t.toneMapping,this._method=r,this._usesCatmullRom=i,this._usesTemporal=n,this.material.defines={},i&&(this.material.defines.CATMULL_ROM_UPSCALE=""),n&&(this.material.defines.TEMPORAL_UPSCALE=""),e.ColorManagement.getTransfer(t.outputColorSpace)===e.SRGBTransfer&&(this.material.defines.SRGB_TRANSFER=""),t.toneMapping===e.LinearToneMapping?this.material.defines.LINEAR_TONE_MAPPING="":t.toneMapping===e.ReinhardToneMapping?this.material.defines.REINHARD_TONE_MAPPING="":t.toneMapping===e.CineonToneMapping?this.material.defines.CINEON_TONE_MAPPING="":t.toneMapping===e.ACESFilmicToneMapping?this.material.defines.ACES_FILMIC_TONE_MAPPING="":t.toneMapping===e.AgXToneMapping?this.material.defines.AGX_TONE_MAPPING="":t.toneMapping===e.NeutralToneMapping&&(this.material.defines.NEUTRAL_TONE_MAPPING=""),this.material.needsUpdate=!0)}ensureHistoryTargets(e,t){const r=Math.max(1,Math.floor(e)),i=Math.max(1,Math.floor(t));null!=this.historyRead&&null!=this.historyWrite&&this.historyRead.width===r&&this.historyRead.height===i||(this.disposeHistoryTargets(),this.historyRead=this.createHistoryTarget(r,i,"UpscaleOutputPass.historyRead"),this.historyWrite=this.createHistoryTarget(r,i,"UpscaleOutputPass.historyWrite"),this.historyValid=!1)}createHistoryTarget(t,r,i){const n=new e.WebGLRenderTarget(t,r,{type:e.HalfFloatType,minFilter:e.LinearFilter,magFilter:e.LinearFilter,format:e.RGBAFormat,depthBuffer:!1,stencilBuffer:!1});return n.texture.name=i,n.texture.generateMipmaps=!1,n}disposeHistoryTargets(){this.historyRead?.dispose(),this.historyWrite?.dispose(),this.historyRead=null,this.historyWrite=null,this.historyValid=!1}}function i(e,t){return null!=e&&Number.isFinite(e)?e:t}function n(e,t){let r=0,i=1/t;for(;e>0;)r+=i*(e%t),e=Math.floor(e/t),i/=t;return r}const o="\n precision highp float;\n\n uniform mat4 modelViewMatrix;\n uniform mat4 projectionMatrix;\n\n attribute vec3 position;\n attribute vec2 uv;\n\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n",a="\n precision highp float;\n\n uniform sampler2D tDiffuse;\n uniform sampler2D tDepth;\n uniform sampler2D tHistory;\n uniform vec2 inputSize;\n uniform float sharpness;\n uniform float temporalFeedback;\n uniform float historyValid;\n uniform vec2 currentJitterUv;\n uniform mat4 currentViewProjectionInverse;\n uniform mat4 previousViewProjection;\n\n #include <common>\n #include <tonemapping_pars_fragment>\n #include <colorspace_pars_fragment>\n #include <dithering_pars_fragment>\n\n varying vec2 vUv;\n\n vec4 applyOutputTransform(vec4 color) {\n #ifdef LINEAR_TONE_MAPPING\n color.rgb = LinearToneMapping(color.rgb);\n #elif defined(REINHARD_TONE_MAPPING)\n color.rgb = ReinhardToneMapping(color.rgb);\n #elif defined(CINEON_TONE_MAPPING)\n color.rgb = CineonToneMapping(color.rgb);\n #elif defined(ACES_FILMIC_TONE_MAPPING)\n color.rgb = ACESFilmicToneMapping(color.rgb);\n #elif defined(AGX_TONE_MAPPING)\n color.rgb = AgXToneMapping(color.rgb);\n #elif defined(NEUTRAL_TONE_MAPPING)\n color.rgb = NeutralToneMapping(color.rgb);\n #endif\n\n #ifdef SRGB_TRANSFER\n color = sRGBTransferOETF(color);\n #endif\n\n return color;\n }\n\n vec4 readOutputColor(vec2 uv) {\n return applyOutputTransform(texture2D(tDiffuse, clamp(uv, vec2(0.0), vec2(1.0))));\n }\n\n float cubicWeight(float value) {\n value = abs(value);\n float value2 = value * value;\n float value3 = value2 * value;\n if (value <= 1.0) {\n return 1.5 * value3 - 2.5 * value2 + 1.0;\n }\n if (value < 2.0) {\n return -0.5 * value3 + 2.5 * value2 - 4.0 * value + 2.0;\n }\n return 0.0;\n }\n\n vec4 sampleCatmullRom(vec2 uv) {\n vec2 texelSize = 1.0 / inputSize;\n vec2 pixel = uv * inputSize - 0.5;\n vec2 basePixel = floor(pixel);\n vec2 fraction = pixel - basePixel;\n vec4 color = vec4(0.0);\n float weightSum = 0.0;\n\n for (int y = -1; y <= 2; y++) {\n float wy = cubicWeight(float(y) - fraction.y);\n for (int x = -1; x <= 2; x++) {\n float wx = cubicWeight(float(x) - fraction.x);\n float weight = wx * wy;\n vec2 sampleUv = (basePixel + vec2(float(x), float(y)) + 0.5) * texelSize;\n color += readOutputColor(sampleUv) * weight;\n weightSum += weight;\n }\n }\n\n return color / max(weightSum, 0.00001);\n }\n\n void getNeighborhoodBounds(vec2 uv, out vec3 minColor, out vec3 maxColor, out vec3 blurColor) {\n vec2 texelSize = 1.0 / inputSize;\n vec3 center = readOutputColor(uv).rgb;\n vec3 north = readOutputColor(uv + vec2(0.0, texelSize.y)).rgb;\n vec3 south = readOutputColor(uv - vec2(0.0, texelSize.y)).rgb;\n vec3 east = readOutputColor(uv + vec2(texelSize.x, 0.0)).rgb;\n vec3 west = readOutputColor(uv - vec2(texelSize.x, 0.0)).rgb;\n minColor = min(center, min(min(north, south), min(east, west)));\n maxColor = max(center, max(max(north, south), max(east, west)));\n blurColor = (north + south + east + west) * 0.25;\n }\n\n vec3 applyContrastLimitedSharpen(vec2 uv, vec3 color) {\n vec3 minColor;\n vec3 maxColor;\n vec3 blurColor;\n getNeighborhoodBounds(uv, minColor, maxColor, blurColor);\n return clamp(color + (color - blurColor) * sharpness, minColor, maxColor);\n }\n\n vec2 reprojectHistoryUv(vec2 uv, float depth) {\n vec4 clip = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);\n vec4 world = currentViewProjectionInverse * clip;\n world /= max(abs(world.w), 0.00001);\n vec4 previousClip = previousViewProjection * world;\n vec3 previousNdc = previousClip.xyz / max(abs(previousClip.w), 0.00001);\n return previousNdc.xy * 0.5 + 0.5;\n }\n\n vec4 applyTemporal(vec2 currentUv, vec4 currentColor) {\n if (historyValid < 0.5) {\n return currentColor;\n }\n\n float depth = texture2D(tDepth, clamp(currentUv, vec2(0.0), vec2(1.0))).x;\n if (depth <= 0.0 || depth >= 1.0) {\n return currentColor;\n }\n\n vec2 historyUv = reprojectHistoryUv(currentUv, depth);\n if (\n historyUv.x < 0.0 || historyUv.x > 1.0 ||\n historyUv.y < 0.0 || historyUv.y > 1.0\n ) {\n return currentColor;\n }\n\n vec3 minColor;\n vec3 maxColor;\n vec3 blurColor;\n getNeighborhoodBounds(currentUv, minColor, maxColor, blurColor);\n vec4 historyColor = texture2D(tHistory, historyUv);\n historyColor.rgb = clamp(historyColor.rgb, minColor, maxColor);\n return mix(currentColor, historyColor, temporalFeedback);\n }\n\n void main() {\n vec2 currentUv = vUv;\n #ifdef TEMPORAL_UPSCALE\n currentUv -= currentJitterUv;\n #endif\n\n #ifdef CATMULL_ROM_UPSCALE\n gl_FragColor = sampleCatmullRom(currentUv);\n gl_FragColor.rgb = applyContrastLimitedSharpen(currentUv, gl_FragColor.rgb);\n #else\n gl_FragColor = readOutputColor(currentUv);\n #endif\n\n #ifdef TEMPORAL_UPSCALE\n gl_FragColor = applyTemporal(currentUv, gl_FragColor);\n #endif\n\n #include <dithering_fragment>\n }\n";/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -0,0 +1,32 @@
1
+ import * as THREE from 'three';
2
+ import type { RenderingBackendDriver } from './rendering-backend.js';
3
+ import { OutlineEffect } from './outline-effect.js';
4
+ export interface WebGlBackendOptions {
5
+ readonly container: HTMLElement;
6
+ readonly pixelRatio: number;
7
+ readonly enableXR: boolean;
8
+ readonly shadows: {
9
+ readonly enabled: boolean;
10
+ readonly autoUpdate: boolean;
11
+ };
12
+ }
13
+ /**
14
+ * Owns renderer-specific resource preparation for the legacy WebGL pipeline.
15
+ * RenderingView deliberately delegates through this adapter so resource-loading
16
+ * code never has to infer which concrete renderer happens to be active.
17
+ */
18
+ export declare class WebGlBackend implements RenderingBackendDriver {
19
+ readonly renderer: THREE.WebGLRenderer;
20
+ readonly outlineEffect: OutlineEffect;
21
+ readonly kind: "webgl";
22
+ readonly canvas: HTMLCanvasElement;
23
+ private pmremGenerator;
24
+ private readonly pmremResults;
25
+ private readonly ownedPmremResults;
26
+ private constructor();
27
+ static initialize(options: WebGlBackendOptions): WebGlBackend;
28
+ initTexture(texture: THREE.Texture): void;
29
+ getEnvironmentTexture(texture: THREE.Texture): THREE.Texture;
30
+ dispose(): void;
31
+ }
32
+ //# sourceMappingURL=webgl-backend.d.ts.map
@@ -0,0 +1,4 @@
1
+ import*as e from"three";import{VRButton as t}from"three-stdlib";import{RectAreaLightUniformsLib as r}from"three/examples/jsm/lights/RectAreaLightUniformsLib.js";import{OutlineEffect as n}from"./outline-effect.js";export class WebGlBackend{constructor(e,t){this.renderer=e,this.outlineEffect=t,this.kind="webgl",this.pmremGenerator=null,this.pmremResults=new WeakMap,this.ownedPmremResults=new Set,this.canvas=e.domElement}static initialize(i){r.init();const a=window,o=a.renderer??new e.WebGLRenderer({antialias:!1,powerPreference:"high-performance"});return a.renderer=o,o.setPixelRatio(i.pixelRatio),o.setSize(i.container.clientWidth,i.container.clientHeight),o.xr.enabled=i.enableXR,i.enableXR&&document.body.appendChild(t.createButton(o)),o.shadowMap.enabled=i.shadows.enabled,o.shadowMap.type=e.PCFSoftShadowMap,o.shadowMap.autoUpdate=i.shadows.autoUpdate,o.outputColorSpace=e.SRGBColorSpace,o.toneMapping=e.NoToneMapping,o.toneMappingExposure=1,o.gammaFactor=1.4,o.debug.checkShaderErrors=!1,new WebGlBackend(o,new n(o,{defaultThickness:.005,defaultColor:[0,0,0],defaultAlpha:1,defaultKeepAlive:!0}))}initTexture(e){this.renderer.initTexture(e)}getEnvironmentTexture(t){if(t.mapping===e.CubeUVReflectionMapping)return t;let r=this.pmremResults.get(t);return null==r&&(null==this.pmremGenerator&&(this.pmremGenerator=new e.PMREMGenerator(this.renderer),this.pmremGenerator.compileEquirectangularShader()),r=this.pmremGenerator.fromEquirectangular(t),this.pmremResults.set(t,r),this.ownedPmremResults.add(r)),r.texture}dispose(){this.pmremGenerator?.dispose(),this.pmremGenerator=null;for(const e of this.ownedPmremResults)e.dispose();this.ownedPmremResults.clear()}}/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -1,7 +1,9 @@
1
1
  import * as THREE from 'three';
2
2
  import { NodeMaterialWebGpuResolver } from './node-material-webgpu-resolver.js';
3
3
  import type { WorldEnvironmentState } from './environment.js';
4
+ import type { RenderingBackendDriver } from './rendering-backend.js';
4
5
  import type { PostProcessEffectStage } from './post-process-effect.js';
6
+ import type { DlssQualityMode } from './upscaling-pass.js';
5
7
  import type { BloomOptions, ColorGradingOptions, DepthOfFieldOptions, FXAAOptions, FrameGraphBuilder, GTAOOptions, GTAOQuality, OutlineOptions, OutlineInstanceSelection, MotionBlurOptions, MotionBlurOverride, MotionBlurOverrideHandle, SSROptions, RendererFrameProfile, SMAAOptions, TemporalAAOptions, VolumetricFogOptions, VolumetricFogQuality } from '@hology/webgpu-renderer';
6
8
  export type { RendererFrameProfile, GTAOOptions, GTAOQuality, MotionBlurOptions, MotionBlurOverride, MotionBlurOverrideHandle, VolumetricFogOptions, VolumetricFogQuality } from '@hology/webgpu-renderer';
7
9
  type SupportedCamera = THREE.PerspectiveCamera | THREE.OrthographicCamera;
@@ -12,6 +14,11 @@ export type ExperimentalWebGpuRenderGraphExtension = ((graph: FrameGraphBuilder,
12
14
  stage?: 'beforeScene' | 'afterScene';
13
15
  };
14
16
  export interface ExperimentalWebGpuPostProcessingOptions {
17
+ /** Request native DLSS-SR when supported by the host. Falls back to TAA. */
18
+ readonly nativeUpscaling?: false | {
19
+ readonly method: 'dlss';
20
+ readonly mode?: DlssQualityMode;
21
+ };
15
22
  readonly bloom?: false | BloomOptions;
16
23
  /**
17
24
  * Selects one mutually exclusive antialiasing method. When present, all
@@ -73,7 +80,7 @@ export interface WebGpuSceneCapabilitySummary {
73
80
  materialsReplaced: number;
74
81
  unsupportedCamera: number;
75
82
  }
76
- export declare class ExperimentalWebGpuBackend {
83
+ export declare class ExperimentalWebGpuBackend implements RenderingBackendDriver {
77
84
  private readonly renderer;
78
85
  private readonly fallbackMaterial;
79
86
  private readonly nodeMaterialResolver;
@@ -93,6 +100,8 @@ export declare class ExperimentalWebGpuBackend {
93
100
  private readonly renderGraphExtensions;
94
101
  private readonly antiAliasingState;
95
102
  private readonly directionalShadowState;
103
+ private readonly nativeDlss;
104
+ readonly kind: "webgpu";
96
105
  readonly canvas: HTMLCanvasElement;
97
106
  private renderScale;
98
107
  private pmremGenerator;
@@ -100,7 +109,14 @@ export declare class ExperimentalWebGpuBackend {
100
109
  private readonly ownedPmremResults;
101
110
  private readonly warnedUnsupportedPostProcessStages;
102
111
  private constructor();
103
- static create(postProcessing?: ExperimentalWebGpuPostProcessingOptions): Promise<ExperimentalWebGpuBackend>;
112
+ static probeAvailability(): Promise<{
113
+ available: true;
114
+ adapter: GPUAdapter;
115
+ } | {
116
+ available: false;
117
+ reason: string;
118
+ }>;
119
+ static create(postProcessing?: ExperimentalWebGpuPostProcessingOptions, adapter?: GPUAdapter): Promise<ExperimentalWebGpuBackend>;
104
120
  static supportsCamera(camera: THREE.Camera): camera is SupportedCamera;
105
121
  setSize(width: number, height: number, presentationPixelRatio: number, renderScale?: number): void;
106
122
  initTexture(texture: THREE.Texture): void;
@@ -117,6 +133,7 @@ export declare class ExperimentalWebGpuBackend {
117
133
  }[], lights?: readonly THREE.DirectionalLight[]): void;
118
134
  setDirectionalShadowOptions(enabled: boolean, mapSize: number): void;
119
135
  setWorldEnvironment(environment: WorldEnvironmentState | null): void;
136
+ getEnvironmentTexture(texture: THREE.Texture): THREE.Texture;
120
137
  /**
121
138
  * Invalidates state whose contents belong to the previously presented view.
122
139
  * GPU resource and pipeline caches intentionally remain resident.
@@ -1,4 +1,4 @@
1
- import*as e from"three";import{NodeMaterialWebGpuResolver as t}from"./node-material-webgpu-resolver.js";import{float as i,varyingTransformed as n,vec4 as o}from"three-shader-graph";import{NodeShaderMaterial as r}from"../shader-nodes/index.js";import{sceneMapUniformName as s}from"../shader-nodes/scene-sample.js";import{depthUniformName as a}from"../shader-nodes/depth.js";import{MATERIAL_FLAG_ALPHA_TEST as l,MATERIAL_FLAG_RECEIVE_DECALS as d}from"../shader-nodes/material-flags.js";import{createMotionVectorOutput as c}from"./motion-vector-node.js";export class ExperimentalWebGpuBackend{constructor(e,t,i,n,o,r,s,a,l,d,c,h,u,p,m,g,f,S,v,w){this.renderer=e,this.fallbackMaterial=t,this.nodeMaterialResolver=i,this.gBufferFallbackSource=n,this.bloom=o,this.fxaa=r,this.smaa=s,this.gtao=a,this.ssr=l,this.taa=d,this.motionBlur=c,this.volumetricFog=h,this.colorGrading=u,this.depthOfField=p,this.outline=m,this.postProcessEffects=g,this.renderGraphExtensions=f,this.antiAliasingState=S,this.directionalShadowState=v,this.renderScale=1,this.pmremGenerator=null,this.pmremResults=new WeakMap,this.ownedPmremResults=new Set,this.warnedUnsupportedPostProcessStages=new Set,this.canvas=w}static async create(p={}){const m=await import("@hology/webgpu-renderer"),g=document.createElement("canvas");g.dataset.hologyRenderer="webgpu-experimental";const f=new m.WGSLShaderMaterial({vertexShader:h,fragmentShader:u});f.side=m.DoubleSide;const S=m,v=null!=p.motionBlur&&!1!==p.motionBlur,w=!1!==p.gtao&&(null==p.gtao||!1!==p.gtao.temporal),P=!1!==p.volumetricFog&&(null==p.volumetricFog||!1!==p.volumetricFog.temporal),x=null!=(b=p).antiAliasing?b.antiAliasing:null!=b.taa&&!1!==b.taa?"taa":null!=b.smaa&&!1!==b.smaa?"smaa":null!=b.fxaa&&!1!==b.fxaa?"fxaa":!1===b.taa?"off":"taa";var b;const y=null!=p.antiAliasing,F=v||w||P||(y||"taa"===x),C=new t(S,(e,t)=>"opaque"===t?[e.outputColor.xyz.rgba(i(e.alphaTest>0?l:0).add(!1===e.userData.receiveDecals?0:d)),o((e.outputNormal??n.normal).multiplyScalar(.5).addScalar(.5),e.outputRoughness??i(1)),...F?[c(e)]:[]]:void 0),M=new e.MeshStandardMaterial({color:8688803,roughness:1});if(null==C.resolve(M,"opaque"))throw f.dispose(),M.dispose(),new Error("Failed to compile the WebGPU G-buffer fallback material.");const L=!1===p.gtao?null:new m.GTAOEffect({normalSpace:"view",...m.GTAO_PRESETS.high,...p.gtao??{}}),O=!1===p.ssr||null==p.ssr?null:new m.SSREffect({normalSpace:"view",resolutionScale:.5,...p.ssr??{}}),E=!1===p.bloom?null:new m.BloomEffect({threshold:1,strength:.9,radius:.2,...p.bloom??{}}),G=y||!1!==p.fxaa&&"fxaa"===x?new m.FXAAEffect(!1===p.fxaa?{}:p.fxaa):null,R=y||!1!==p.smaa&&"smaa"===x?new m.SMAAEffect(!1===p.smaa?{}:p.smaa):null,D=y||!1!==p.taa&&"taa"===x?new m.TemporalAAEffect({renderScale:1,...!1===p.taa?{}:p.taa}):null,B={mode:x},A=!1===p.motionBlur||null==p.motionBlur?null:new m.MotionBlurEffect(p.motionBlur),T=p.volumetricFog||void 0,V=!1===p.volumetricFog?null:new m.VolumetricFogEffect(void 0,{...m.VOLUMETRIC_FOG_PRESETS.high,maxDistance:64,spatialJitter:!0,scatteringIntensity:Math.PI,...T,temporal:!1!==T?.temporal&&{...m.VOLUMETRIC_FOG_PRESETS.high.temporal,...T?.temporal},blur:!1!==T?.blur&&{...!1===m.VOLUMETRIC_FOG_PRESETS.high.blur?{}:m.VOLUMETRIC_FOG_PRESETS.high.blur,depthAwareUpsample:!0,...T?.blur}}),W=!1===p.colorGrading?null:new m.ColorGradingEffect({enabled:!1,...p.colorGrading??{}}),k=!1===p.depthOfField?null:new m.DepthOfFieldEffect({enabled:!1,...p.depthOfField??{}}),I=!1===p.outline?null:new m.OutlineEffect({enabled:!1,...p.outline??{}}),N=[],U=new WeakMap,j=new Set,H=[],$=(e,t,i)=>{let n=i;const o=N.filter(e=>e.enabled&&e.stage===t).sort((e,t)=>e.priority-t.priority||e.id-t.id);for(const t of o){if(!(t.material instanceof r)){const e=`${t.id}:material`;j.has(e)||(j.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: only NodeShaderMaterial effects are supported.`));continue}try{let i=U.get(t.material);null!=i&&i.version===t.material.version||(i={version:t.material.version,shader:C.compileFullscreen(t.material)},U.set(t.material,i));const o=e.createColorTarget(`hologyCustomPostProcess${t.id}`);e.addNodeFullscreenPass({name:`HologyCustomPostProcess${t.id}`,shader:i.shader,inputOverrides:{[s]:n},outputs:o}),n=o}catch(e){const i=`${t.id}:compile:${t.material.version}`;j.has(i)||(j.add(i),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: ${e instanceof Error?e.message:String(e)}`,e))}}return n},_={enabled:!0},z=new m.WebGpuRenderer({canvas:g,fallbackMaterial:f,materialResolver:(e,t)=>C.resolve(e,t),invokeObjectRenderCallbacks:!1,hiZOcclusionCulling:!0,renderGraphProfiling:!1,sampleCount:1,multiDrawIndirect:!1});z.setRenderScale("taa"===x?D?.renderScale??1:1),z.setRenderGraphBuilder((e,t)=>{const i=new m.FrameGraphBuilder(t),n=i.createColorTarget("hologyNormalRoughness",{format:"rgba16float"}),o=F?i.createColorTarget("hologyMotionVectors",{format:"rgba16float"}):null;for(const e of H)"beforeScene"===e.stage&&e(i,i.sceneColor);_.enabled&&i.addDirectionalShadowPass(),i.addPointShadowPass(),i.addSpotShadowPass(),i.addDepthPrepass(),i.addHiZPasses(),i.addVisibilityPass(),i.addMaterialPass({name:"OpaqueGBufferPass",outputs:null==o?[i.sceneColor,n]:[i.sceneColor,n,o],drawStage:"opaque",loadDepth:!0}),i.addHiZHistoryPass("OpaqueGBufferPass");let r=i.sceneColor;if(L?.enabled){const e=L.addPasses(i,{depth:i.mainDepth,normal:n,velocity:o??void 0});r=L.addCompositePass(i,r,e)}null!=O&&(r=O.addPasses(i,{sceneColor:r,depth:i.mainDepth,normalRoughness:n}));const s=new Set(H.flatMap(e=>e.getSceneTextureReads?.()??[]));i.addSceneTextureCopyPass(r,{sceneColor:s.has("sceneColorSnapshot"),sceneDepth:s.has("sceneDepthSnapshot")||N.some(e=>e.enabled&&null!=e.material.uniforms[a])}),r=$(i,"beforeFog",r),i.addLatePass(r);for(const e of H)"beforeScene"!==e.stage&&e(i,r);null!=V&&(r=V.addPasses(i,{sceneColor:r,depth:i.mainDepth,velocity:o??void 0,volumeObjects:t.fogVolumeObjects,lights:t.extractedLights})),null!=A&&null!=o&&(r=A.addPass(i,r,o,i.mainDepth)),null!=E&&(r=E.addPass(i,r)),r=$(i,"beforeOutline",r),null!=I&&(r=I.addPass(i,r)),r=$(i,"beforeDepthOfField",r),null!=k&&(r=k.addPass(i,r,i.mainDepth)),r=$(i,"beforeColorAdjustment",r),null!=W&&(r=W.addPass(i,r)),r=$(i,"beforeAntiAliasing",r);let l="taa"===B.mode&&null!=D?D.addPass(i,r,i.mainDepth,o??void 0):r;"smaa"===B.mode&&null!=R?l=R.addPass(i,l):"fxaa"===B.mode&&null!=G&&(l=G.addPass(i,l)),l=$(i,"beforeOutput",l),i.present(l)});try{return await z.initialize(),new ExperimentalWebGpuBackend(z,f,C,M,E,G,R,L,O,D,A,V,W,k,I,N,H,B,_,g)}catch(e){throw z.destroy(),f.dispose(),C.dispose(),M.dispose(),L?.dispose(),R?.dispose(),A?.dispose(),V?.dispose(),I?.dispose(),e}}static supportsCamera(t){return t instanceof e.PerspectiveCamera||t instanceof e.OrthographicCamera}setSize(e,t,i,n=1){const o=this.canvas.width,r=this.canvas.height,s=Math.min(1,Math.max(.25,n)),a=s!==this.renderScale;this.renderScale=s,this.renderer.setRenderScale(s),this.taa?.setRenderScale(s),this.renderer.setSize(e,t,i),(a||this.canvas.width!==o||this.canvas.height!==r)&&this.resetViewHistory()}initTexture(e){this.renderer.initTexture(e)}setPostProcessEffects(e){this.postProcessEffects.splice(0,this.postProcessEffects.length,...e);for(const t of e){if("beforeLut"!==t.stage)continue;const e=`${t.id}:${t.stage}`;this.warnedUnsupportedPostProcessStages.has(e)||(this.warnedUnsupportedPostProcessStages.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: stage "${t.stage}" has no native WebGPU anchor.`))}}getDevice(){return this.renderer.getDevice()}setRenderGraphExtensions(e){this.renderGraphExtensions.length=0;for(const t of e)this.renderGraphExtensions.push(t)}setEnableOutlines(e){null!=this.outline&&(this.outline.enabled=e)}setDynamicBatchingEnabled(e){this.renderer.setDynamicBatchingEnabled(e)}setSelectedObjects(e){this.outline?.setSelectedObjects(e)}setSelectedObjectInstances(e){this.outline?.setSelectedInstances(e)}setCascadedShadowRanges(e,t=[]){this.renderer.setCascadedShadowRanges(e,t),this.volumetricFog?.setCascadedDirectionalLights(t)}setDirectionalShadowOptions(e,t){this.directionalShadowState.enabled=e,this.renderer.setDirectionalShadowsEnabled(e),this.renderer.setDirectionalShadowMapSize(t)}setWorldEnvironment(t){if(null==t)return void this.nodeMaterialResolver.setWorldEnvironment(null);let i=t.source;if(i.mapping!==e.CubeUVReflectionMapping){let e=this.pmremResults.get(i);null==e&&(this.pmremGenerator??(this.pmremGenerator=this.renderer.createPMREMGenerator()),e=this.pmremGenerator.fromEquirectangular(i),this.pmremResults.set(i,e),this.ownedPmremResults.add(e)),i=e.texture}this.nodeMaterialResolver.setWorldEnvironment({texture:i,intensity:t.intensity})}resetViewHistory(){this.renderer.resetViewHistory(),this.taa?.reset(),this.motionBlur?.reset(),this.gtao?.reset(),this.volumetricFog?.reset()}async compile(e,t){await this.renderer.compileAsync(e,t)}createStaticDrawSet(e,t,i=!1){this.renderer.setHiZOcclusionCullingEnabled(!0);const n=this.renderer.createStaticDrawSet(e,{label:t,onUnsupported:"skip",allowUnsortedLateDraws:i});return 0===n.drawCount?(n.dispose(),null):n}render(e,t,i){const n="taa"===this.antiAliasingState.mode?this.taa:null;this.volumetricFog?.setScene(e),this.renderer.setMotionVectorProjection(t.projectionMatrix),this.motionBlur?.prepareCamera(t,this.canvas.width,this.canvas.height,i),this.motionBlur?.requiresRendererHistoryReset()&&(this.renderer.resetViewHistory(),this.gtao?.reset(),this.volumetricFog?.reset()),n?.prepareCamera(t,this.canvas.width,this.canvas.height),this.motionBlur?.setJitterUv(n?.currentJitterUv.x??0,n?.currentJitterUv.y??0);let o=!1;try{this.renderer.render(e,t,i),o=!0}finally{n?.finishCamera(t),o&&this.motionBlur?.commitCamera()}}setMotionBlurOptions(e){null!=this.motionBlur&&Object.assign(this.motionBlur.options,e)}setGTAOOptions(e){this.gtao?.setOptions(e)}setAntiAliasingMode(e){e!==this.antiAliasingState.mode&&("taa"===e&&null==this.taa||"smaa"===e&&null==this.smaa||"fxaa"===e&&null==this.fxaa?console.warn(`[Hology WebGPU experiment] Anti-aliasing mode "${e}" was not initialized. Set webgpuPostProcessing.antiAliasing in the initial rendering configuration to enable runtime switching.`):(this.antiAliasingState.mode=e,this.resetTemporalHistory()))}setGTAOQuality(e){this.gtao?.applyPreset(e)}setVolumetricFogOptions(e){this.volumetricFog?.setOptions(e)}setVolumetricFogQuality(e){this.volumetricFog?.applyPreset(e)}pushMotionBlurOverride(e){return this.motionBlur?.pushOverride(e)??null}invalidateObjectMotion(e){this.renderer.invalidateObjectMotion(e)}getLastFrameProfile(){return this.renderer.getLastFrameProfile()}setPostProcessState(e){null!=this.colorGrading&&(Object.assign(this.colorGrading.options,e??{enabled:!1}),this.colorGrading.options.enabled=!0===e?.enabled),null!=this.depthOfField&&(this.depthOfField.options.enabled=null!=e?.depthFocus||null!=e?.depthAperture||null!=e?.depthMaxBlur,this.depthOfField.options.focus=e?.depthFocus,this.depthOfField.options.aperture=e?.depthAperture,this.depthOfField.options.maxBlur=e?.depthMaxBlur)}setProfilingEnabled(e){this.renderer.setRenderGraphProfilingEnabled(e)}resetTemporalHistory(){this.taa?.reset(),this.motionBlur?.reset(),this.gtao?.reset(),this.volumetricFog?.reset(),this.renderer.resetViewHistory()}inspect(e,t){return inspectWebGpuScene(e,t,this.nodeMaterialResolver)}destroy(){this.nodeMaterialResolver.dispose(),this.gBufferFallbackSource.dispose(),this.gtao?.dispose(),this.smaa?.dispose(),this.motionBlur?.dispose(),this.volumetricFog?.dispose();for(const e of this.ownedPmremResults)e.dispose();this.ownedPmremResults.clear(),this.renderer.destroy(),this.fallbackMaterial.dispose()}}export function inspectWebGpuScene(e,t,i){const n={meshes:0,skinnedMeshes:0,instancedMeshes:0,batchedMeshes:0,sprites:0,points:0,lines:0,missingPositionGeometry:0,transparentMaterials:0,shaderMaterialsReplaced:0,materialsReplaced:0,unsupportedCamera:ExperimentalWebGpuBackend.supportsCamera(t)?0:1};return e.traverse(e=>{if(e.isSprite)return void n.sprites++;if(e.isPoints)return void n.points++;if(e.isLine)return void n.lines++;if(!e.isMesh)return;const t=e;t.isBatchedMesh?n.batchedMeshes++:t.isInstancedMesh?n.instancedMeshes++:t.isSkinnedMesh?n.skinnedMeshes++:n.meshes++,null==t.geometry?.getAttribute("position")&&n.missingPositionGeometry++;const o=Array.isArray(t.material)?t.material:[t.material];for(const e of o){if(null==e)continue;e.transparent&&n.transparentMaterials++;const t=!0===e.isWGSLShaderMaterial||!0===e.isLineMaterial,o=!t&&!0===i?.canResolve(e);t||o||(n.materialsReplaced++,e.isShaderMaterial&&n.shaderMaterialsReplaced++)}}),n}export function formatWebGpuSceneCapabilitySummary(e){return`[Hology WebGPU experiment] ${JSON.stringify(e)}`}const h="\nstruct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) uv: vec2<f32>,\n @location(3) color: vec4<f32>,\n#ifdef USE_SKINNING\n @location(4) skinIndex: vec4<u32>,\n @location(5) skinWeight: vec4<f32>,\n#endif\n @builtin(instance_index) instanceIndex: u32,\n};\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\n@vertex\nfn vsMain(input: VertexInput) -> VertexOutput {\n var output: VertexOutput;\n#ifdef USE_SKINNING\n let localPosition = rendererSkinPosition(input.position, input.skinIndex, input.skinWeight);\n let localNormal = rendererSkinNormal(input.normal, input.skinIndex, input.skinWeight);\n#else\n let localPosition = input.position;\n let localNormal = input.normal;\n#endif\n let world = rendererWorldPosition(localPosition, input.instanceIndex);\n output.position = rendererClipPosition(localPosition, input.instanceIndex);\n output.worldPosition = world.xyz;\n output.worldNormal = rendererWorldNormal(localNormal, input.instanceIndex);\n output.color = input.color * rendererObjectColor(input.instanceIndex);\n return output;\n}\n",u="\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\nfn distanceAttenuation(distanceToLight: f32, cutoffDistance: f32, decayExponent: f32) -> f32 {\n var distanceFalloff = 1.0 / max(pow(distanceToLight, decayExponent), 0.01);\n if (cutoffDistance > 0.0) {\n let ratio = distanceToLight / cutoffDistance;\n let cutoff = clamp(1.0 - ratio * ratio * ratio * ratio, 0.0, 1.0);\n distanceFalloff *= cutoff * cutoff;\n }\n return distanceFalloff;\n}\n\n@fragment\nfn fsMain(input: VertexOutput) -> @location(0) vec4<f32> {\n let normal = normalize(input.worldNormal);\n let normalTint = normal * 0.5 + vec3<f32>(0.5);\n let base = mix(vec3<f32>(0.52, 0.58, 0.64), normalTint, 0.22) * input.color.rgb;\n var lighting = rendererIndirectDiffuse(normal) + vec3<f32>(0.08);\n var directionalLighting = vec3<f32>(0.0);\n let directionalCount = rendererDirectionalLightCount();\n\n for (var index: u32 = 0u; index < directionalCount; index = index + 1u) {\n let lightDirection = rendererDirectionalLightDirectionForLight(index);\n let shadow = rendererSampleDirectionalShadowForLightWithNormal(index, input.worldPosition, normal);\n directionalLighting += rendererDirectionalLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * shadow;\n }\n if (directionalCount > 0u) {\n lighting += directionalLighting / f32(directionalCount);\n }\n\n for (var index: u32 = 0u; index < rendererPointLightCount(); index = index + 1u) {\n let lightVector = rendererPointLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let shadow = rendererSamplePointShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererPointLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * distanceAttenuation(distanceToLight, rendererPointLightRangeForLight(index), rendererPointLightDecayForLight(index)) * shadow;\n }\n\n for (var index: u32 = 0u; index < rendererSpotLightCount(); index = index + 1u) {\n let lightVector = rendererSpotLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let angleCos = dot(-lightDirection, rendererSpotLightDirectionForLight(index));\n let cone = smoothstep(rendererSpotLightConeCosForLight(index), rendererSpotLightPenumbraCosForLight(index), angleCos);\n let shadow = rendererSampleSpotShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererSpotLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * cone * distanceAttenuation(distanceToLight, rendererSpotLightRangeForLight(index), rendererSpotLightDecayForLight(index)) * shadow;\n }\n\n return vec4<f32>(base * max(lighting, vec3<f32>(0.08)), input.color.a);\n}\n";/*
1
+ import*as e from"three";import{NodeMaterialWebGpuResolver as t}from"./node-material-webgpu-resolver.js";import{configureWebGpuRuntimeBindings as i}from"./webgpu-runtime-bridge.js";import{float as n,varyingTransformed as r,vec4 as o}from"three-shader-graph";import{NodeShaderMaterial as a}from"../shader-nodes/index.js";import{sceneMapUniformName as s}from"../shader-nodes/scene-sample.js";import{depthUniformName as l}from"../shader-nodes/depth.js";import{MATERIAL_FLAG_ALPHA_TEST as d,MATERIAL_FLAG_RECEIVE_DECALS as c}from"../shader-nodes/material-flags.js";import{createMotionVectorOutput as h}from"./motion-vector-node.js";export class ExperimentalWebGpuBackend{constructor(e,t,i,n,r,o,a,s,l,d,c,h,u,p,m,g,f,v,S,b,x){this.renderer=e,this.fallbackMaterial=t,this.nodeMaterialResolver=i,this.gBufferFallbackSource=n,this.bloom=r,this.fxaa=o,this.smaa=a,this.gtao=s,this.ssr=l,this.taa=d,this.motionBlur=c,this.volumetricFog=h,this.colorGrading=u,this.depthOfField=p,this.outline=m,this.postProcessEffects=g,this.renderGraphExtensions=f,this.antiAliasingState=v,this.directionalShadowState=S,this.nativeDlss=b,this.kind="webgpu",this.renderScale=1,this.pmremGenerator=null,this.pmremResults=new WeakMap,this.ownedPmremResults=new Set,this.warnedUnsupportedPostProcessStages=new Set,this.canvas=x}static async probeAvailability(){if("undefined"==typeof navigator||!("gpu"in navigator))return{available:!1,reason:"The runtime does not expose navigator.gpu."};try{const e=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});return null==e?{available:!1,reason:"No WebGPU adapter is available."}:{available:!0,adapter:e}}catch(e){return{available:!1,reason:`Requesting a WebGPU adapter failed: ${e instanceof Error?e.message:String(e)}`}}}static async create(m={},g){const f=await import("@hology/webgpu-renderer");i({createComputeKernel:(e,t)=>new f.ComputeKernel(e,t),buildParticleLightingShaderHeader:f.buildParticleLightingShaderHeader});const v=document.createElement("canvas");v.dataset.hologyRenderer="webgpu-experimental";const S=new f.WGSLShaderMaterial({vertexShader:u,fragmentShader:p}),b=!1!==m.nativeUpscaling&&"dlss"===m.nativeUpscaling?.method,x=b?(await import("./native-dlss-upscaler.js")).createNativeDlssUpscaler(m.nativeUpscaling?.mode??"quality"):null,P=null!=x;S.side=f.DoubleSide;const w=f,y=null!=m.motionBlur&&!1!==m.motionBlur,F=!1!==m.gtao&&(null==m.gtao||!1!==m.gtao.temporal),M=!1!==m.volumetricFog&&(null==m.volumetricFog||!1!==m.volumetricFog.temporal),C=P?"off":b?"taa":null!=(D=m).antiAliasing?D.antiAliasing:null!=D.taa&&!1!==D.taa?"taa":null!=D.smaa&&!1!==D.smaa?"smaa":null!=D.fxaa&&!1!==D.fxaa?"fxaa":!1===D.taa?"off":"taa";var D;const E=null!=m.antiAliasing,L=y||F||M||(E||"taa"===C)||P;let O=null;const G=new t(w,(e,t)=>"opaque"===t?[e.outputColor.xyz.rgba(n(e.alphaTest>0?d:0).add(!1===e.userData.receiveDecals?0:c)),o((e.outputNormal??r.normal).multiplyScalar(.5).addScalar(.5),e.outputRoughness??n(1)),...L?[h(e)]:[]]:void 0,e=>O?.getEnvironmentTexture(e)??e),R=new e.MeshStandardMaterial({color:8688803,roughness:1});if(null==G.resolve(R,"opaque"))throw S.dispose(),R.dispose(),new Error("Failed to compile the WebGPU G-buffer fallback material.");const T=!1===m.gtao?null:new f.GTAOEffect({normalSpace:"view",...f.GTAO_PRESETS.high,...m.gtao??{}}),A=!1===m.ssr||null==m.ssr?null:new f.SSREffect({normalSpace:"view",resolutionScale:.5,...m.ssr??{}}),B=!1===m.bloom?null:new f.BloomEffect({threshold:1,strength:.9,radius:.2,...m.bloom??{}}),W=E||!1!==m.fxaa&&"fxaa"===C?new f.FXAAEffect(!1===m.fxaa?{}:m.fxaa):null,V=E||!1!==m.smaa&&"smaa"===C?new f.SMAAEffect(!1===m.smaa?{}:m.smaa):null,k=P||E||!1!==m.taa&&"taa"===C?new f.TemporalAAEffect({renderScale:1,...!1===m.taa?{}:m.taa}):null,U={mode:C},I=!1===m.motionBlur||null==m.motionBlur?null:new f.MotionBlurEffect(m.motionBlur),j=m.volumetricFog||void 0,N=!1===m.volumetricFog?null:new f.VolumetricFogEffect(void 0,{...f.VOLUMETRIC_FOG_PRESETS.high,maxDistance:64,spatialJitter:!0,scatteringIntensity:Math.PI,...j,temporal:!1!==j?.temporal&&{...f.VOLUMETRIC_FOG_PRESETS.high.temporal,...j?.temporal},blur:!1!==j?.blur&&{...!1===f.VOLUMETRIC_FOG_PRESETS.high.blur?{}:f.VOLUMETRIC_FOG_PRESETS.high.blur,depthAwareUpsample:!0,...j?.blur}}),H=!1===m.colorGrading?null:new f.ColorGradingEffect({enabled:!1,...m.colorGrading??{}}),$=!1===m.depthOfField?null:new f.DepthOfFieldEffect({enabled:!1,...m.depthOfField??{}}),_=!1===m.outline?null:new f.OutlineEffect({enabled:!1,...m.outline??{}}),q=[],z=new WeakMap,J=new Set,K=[],Z=(e,t,i)=>{let n=i;const r=q.filter(e=>e.enabled&&e.stage===t).sort((e,t)=>e.priority-t.priority||e.id-t.id);for(const t of r){if(!(t.material instanceof a)){const e=`${t.id}:material`;J.has(e)||(J.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: only NodeShaderMaterial effects are supported.`));continue}try{let i=z.get(t.material);null!=i&&i.version===t.material.version||(i={version:t.material.version,shader:G.compileFullscreen(t.material)},z.set(t.material,i));const r=e.createColorTarget(`hologyCustomPostProcess${t.id}`);e.addNodeFullscreenPass({name:`HologyCustomPostProcess${t.id}`,shader:i.shader,inputOverrides:{[s]:n},outputs:r}),n=r}catch(e){const i=`${t.id}:compile:${t.material.version}`;J.has(i)||(J.add(i),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: ${e instanceof Error?e.message:String(e)}`,e))}}return n},Q={enabled:!0},X=new f.WebGpuRenderer({canvas:v,fallbackMaterial:S,materialResolver:(e,t)=>G.resolve(e,t),invokeObjectRenderCallbacks:!1,hiZOcclusionCulling:!0,renderGraphProfiling:!1,sampleCount:1,multiDrawIndirect:!1,nativePostSubmit:x?.postSubmit});X.setRenderScale("taa"===C?k?.renderScale??1:1),X.setRenderGraphBuilder((e,t)=>{const i=new f.FrameGraphBuilder(t),n=i.createColorTarget("hologyNormalRoughness",{format:"rgba16float"}),r=L?i.createColorTarget("hologyMotionVectors",{format:"rgba16float"}):null;for(const e of K)"beforeScene"===e.stage&&e(i,i.sceneColor);Q.enabled&&i.addDirectionalShadowPass(),i.addPointShadowPass(),i.addSpotShadowPass(),i.addDepthPrepass(),i.addHiZPasses(),i.addVisibilityPass(),i.addMaterialPass({name:"OpaqueGBufferPass",outputs:null==r?[i.sceneColor,n]:[i.sceneColor,n,r],drawStage:"opaque",loadDepth:!0}),i.addHiZHistoryPass("OpaqueGBufferPass");let o=i.sceneColor;if(T?.enabled){const e=T.addPasses(i,{depth:i.mainDepth,normal:n,velocity:r??void 0});o=T.addCompositePass(i,o,e)}null!=A&&(o=A.addPasses(i,{sceneColor:o,depth:i.mainDepth,normalRoughness:n}));const a=new Set(K.flatMap(e=>e.getSceneTextureReads?.()??[]));i.addSceneTextureCopyPass(o,{sceneColor:a.has("sceneColorSnapshot"),sceneDepth:a.has("sceneDepthSnapshot")||q.some(e=>e.enabled&&null!=e.material.uniforms[l])}),o=Z(i,"beforeFog",o),i.addLatePass(o);for(const e of K)"beforeScene"!==e.stage&&e(i,o);null!=N&&(o=N.addPasses(i,{sceneColor:o,depth:i.mainDepth,velocity:r??void 0,volumeObjects:t.fogVolumeObjects,lights:t.extractedLights})),null!=I&&null!=r&&(o=I.addPass(i,o,r,i.mainDepth)),null!=B&&(o=B.addPass(i,o)),o=Z(i,"beforeOutline",o),null!=_&&(o=_.addPass(i,o)),o=Z(i,"beforeDepthOfField",o),null!=$&&(o=$.addPass(i,o,i.mainDepth)),o=Z(i,"beforeColorAdjustment",o),null!=H&&(o=H.addPass(i,o)),o=Z(i,"beforeAntiAliasing",o);let s="taa"===U.mode&&null!=k?k.addPass(i,o,i.mainDepth,r??void 0):o;"smaa"===U.mode&&null!=V?s=V.addPass(i,s):"fxaa"===U.mode&&null!=W&&(s=W.addPass(i,s)),s=Z(i,"beforeOutput",s),!0===x?.enabled&&null!=r?x.addInputPass(i,s,r):i.present(s)});try{return await X.initialize(g),O=new ExperimentalWebGpuBackend(X,S,G,R,B,W,V,T,A,k,I,N,H,$,_,q,K,U,Q,x,v),O}catch(e){throw X.destroy(),S.dispose(),G.dispose(),R.dispose(),T?.dispose(),V?.dispose(),I?.dispose(),N?.dispose(),_?.dispose(),e}}static supportsCamera(t){return t instanceof e.PerspectiveCamera||t instanceof e.OrthographicCamera}setSize(e,t,i,n=1){const r=this.canvas.width,o=this.canvas.height;let a=Math.min(1,Math.max(.25,n));if(!0===this.nativeDlss?.enabled){const n=Math.max(1,Math.floor(e*i)),r=Math.max(1,Math.floor(t*i));a=this.nativeDlss.getRenderScale(n,r)}const s=a!==this.renderScale;this.renderScale=a,this.renderer.setRenderScale(a),this.taa?.setRenderScale(a),this.renderer.setSize(e,t,i),(s||this.canvas.width!==r||this.canvas.height!==o)&&this.resetViewHistory()}initTexture(e){this.renderer.initTexture(e)}setPostProcessEffects(e){this.postProcessEffects.splice(0,this.postProcessEffects.length,...e);for(const t of e){if("beforeLut"!==t.stage)continue;const e=`${t.id}:${t.stage}`;this.warnedUnsupportedPostProcessStages.has(e)||(this.warnedUnsupportedPostProcessStages.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: stage "${t.stage}" has no native WebGPU anchor.`))}}getDevice(){return this.renderer.getDevice()}setRenderGraphExtensions(e){this.renderGraphExtensions.length=0;for(const t of e)this.renderGraphExtensions.push(t)}setEnableOutlines(e){null!=this.outline&&(this.outline.enabled=e)}setDynamicBatchingEnabled(e){this.renderer.setDynamicBatchingEnabled(e)}setSelectedObjects(e){this.outline?.setSelectedObjects(e)}setSelectedObjectInstances(e){this.outline?.setSelectedInstances(e)}setCascadedShadowRanges(e,t=[]){this.renderer.setCascadedShadowRanges(e,t),this.volumetricFog?.setCascadedDirectionalLights(t)}setDirectionalShadowOptions(e,t){this.directionalShadowState.enabled=e,this.renderer.setDirectionalShadowsEnabled(e),this.renderer.setDirectionalShadowMapSize(t)}setWorldEnvironment(e){if(null==e)return void this.nodeMaterialResolver.setWorldEnvironment(null);const t=this.getEnvironmentTexture(e.source);this.nodeMaterialResolver.setWorldEnvironment({texture:t,intensity:e.intensity})}getEnvironmentTexture(t){if(t.mapping===e.CubeUVReflectionMapping)return t;let i=this.pmremResults.get(t);return null==i&&(this.pmremGenerator??(this.pmremGenerator=this.renderer.createPMREMGenerator()),i=this.pmremGenerator.fromEquirectangular(t),this.pmremResults.set(t,i),this.ownedPmremResults.add(i)),i.texture}resetViewHistory(){this.renderer.resetViewHistory(),this.taa?.reset(),this.motionBlur?.reset(),this.gtao?.reset(),this.volumetricFog?.reset(),this.nativeDlss?.reset()}async compile(e,t){await this.renderer.compileAsync(e,t)}createStaticDrawSet(e,t,i=!1){this.renderer.setHiZOcclusionCullingEnabled(!0);const n=this.renderer.createStaticDrawSet(e,{label:t,onUnsupported:"skip",allowUnsortedLateDraws:i});return 0===n.drawCount?(n.dispose(),null):n}render(e,t,i){const n="taa"===this.antiAliasingState.mode?this.taa:null;this.volumetricFog?.setScene(e),this.renderer.setMotionVectorProjection(t.projectionMatrix),this.motionBlur?.prepareCamera(t,this.canvas.width,this.canvas.height,i),this.motionBlur?.requiresRendererHistoryReset()&&(this.renderer.resetViewHistory(),this.gtao?.reset(),this.volumetricFog?.reset()),n?.prepareCamera(t,this.canvas.width,this.canvas.height),this.nativeDlss?.prepareFrame(t);const r=!0===this.nativeDlss?.enabled?this.nativeDlss.jitter:null;this.motionBlur?.setJitterUv(n?.currentJitterUv.x??(null==r?0:r.x/Math.max(1,this.canvas.width*this.renderScale)),n?.currentJitterUv.y??(null==r?0:-r.y/Math.max(1,this.canvas.height*this.renderScale))),null!=r&&this.renderer.setProjectionJitter(r.x,r.y);let o=!1;try{this.renderer.render(e,t,i),o=!0}finally{null!=r&&this.renderer.clearProjectionJitter(),n?.finishCamera(t),o&&this.motionBlur?.commitCamera(),o&&this.nativeDlss?.finishFrame(t)}}setMotionBlurOptions(e){null!=this.motionBlur&&Object.assign(this.motionBlur.options,e)}setGTAOOptions(e){this.gtao?.setOptions(e)}setAntiAliasingMode(e){e!==this.antiAliasingState.mode&&("taa"===e&&null==this.taa||"smaa"===e&&null==this.smaa||"fxaa"===e&&null==this.fxaa?console.warn(`[Hology WebGPU experiment] Anti-aliasing mode "${e}" was not initialized. Set webgpuPostProcessing.antiAliasing in the initial rendering configuration to enable runtime switching.`):(this.antiAliasingState.mode=e,this.resetTemporalHistory()))}setGTAOQuality(e){this.gtao?.applyPreset(e)}setVolumetricFogOptions(e){this.volumetricFog?.setOptions(e)}setVolumetricFogQuality(e){this.volumetricFog?.applyPreset(e)}pushMotionBlurOverride(e){return this.motionBlur?.pushOverride(e)??null}invalidateObjectMotion(e){this.renderer.invalidateObjectMotion(e)}getLastFrameProfile(){return this.renderer.getLastFrameProfile()}setPostProcessState(e){null!=this.colorGrading&&(Object.assign(this.colorGrading.options,e??{enabled:!1}),this.colorGrading.options.enabled=!0===e?.enabled),null!=this.depthOfField&&(this.depthOfField.options.enabled=null!=e?.depthFocus||null!=e?.depthAperture||null!=e?.depthMaxBlur,this.depthOfField.options.focus=e?.depthFocus,this.depthOfField.options.aperture=e?.depthAperture,this.depthOfField.options.maxBlur=e?.depthMaxBlur)}setProfilingEnabled(e){this.renderer.setRenderGraphProfilingEnabled(e)}resetTemporalHistory(){this.taa?.reset(),this.motionBlur?.reset(),this.gtao?.reset(),this.volumetricFog?.reset(),this.renderer.resetViewHistory(),this.nativeDlss?.reset()}inspect(e,t){return inspectWebGpuScene(e,t,this.nodeMaterialResolver)}destroy(){this.nativeDlss?.dispose(),this.nodeMaterialResolver.dispose(),this.gBufferFallbackSource.dispose(),this.gtao?.dispose(),this.smaa?.dispose(),this.motionBlur?.dispose(),this.volumetricFog?.dispose();for(const e of this.ownedPmremResults)e.dispose();this.ownedPmremResults.clear(),this.renderer.destroy(),this.fallbackMaterial.dispose()}}export function inspectWebGpuScene(e,t,i){const n={meshes:0,skinnedMeshes:0,instancedMeshes:0,batchedMeshes:0,sprites:0,points:0,lines:0,missingPositionGeometry:0,transparentMaterials:0,shaderMaterialsReplaced:0,materialsReplaced:0,unsupportedCamera:ExperimentalWebGpuBackend.supportsCamera(t)?0:1};return e.traverse(e=>{if(e.isSprite)return void n.sprites++;if(e.isPoints)return void n.points++;if(e.isLine)return void n.lines++;if(!e.isMesh)return;const t=e;t.isBatchedMesh?n.batchedMeshes++:t.isInstancedMesh?n.instancedMeshes++:t.isSkinnedMesh?n.skinnedMeshes++:n.meshes++,null==t.geometry?.getAttribute("position")&&n.missingPositionGeometry++;const r=Array.isArray(t.material)?t.material:[t.material];for(const e of r){if(null==e)continue;e.transparent&&n.transparentMaterials++;const t=!0===e.isWGSLShaderMaterial||!0===e.isLineMaterial,r=!t&&!0===i?.canResolve(e);t||r||(n.materialsReplaced++,e.isShaderMaterial&&n.shaderMaterialsReplaced++)}}),n}export function formatWebGpuSceneCapabilitySummary(e){return`[Hology WebGPU experiment] ${JSON.stringify(e)}`}const u="\nstruct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) uv: vec2<f32>,\n @location(3) color: vec4<f32>,\n#ifdef USE_SKINNING\n @location(4) skinIndex: vec4<u32>,\n @location(5) skinWeight: vec4<f32>,\n#endif\n @builtin(instance_index) instanceIndex: u32,\n};\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\n@vertex\nfn vsMain(input: VertexInput) -> VertexOutput {\n var output: VertexOutput;\n#ifdef USE_SKINNING\n let localPosition = rendererSkinPosition(input.position, input.skinIndex, input.skinWeight);\n let localNormal = rendererSkinNormal(input.normal, input.skinIndex, input.skinWeight);\n#else\n let localPosition = input.position;\n let localNormal = input.normal;\n#endif\n let world = rendererWorldPosition(localPosition, input.instanceIndex);\n output.position = rendererClipPosition(localPosition, input.instanceIndex);\n output.worldPosition = world.xyz;\n output.worldNormal = rendererWorldNormal(localNormal, input.instanceIndex);\n output.color = input.color * rendererObjectColor(input.instanceIndex);\n return output;\n}\n",p="\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\nfn distanceAttenuation(distanceToLight: f32, cutoffDistance: f32, decayExponent: f32) -> f32 {\n var distanceFalloff = 1.0 / max(pow(distanceToLight, decayExponent), 0.01);\n if (cutoffDistance > 0.0) {\n let ratio = distanceToLight / cutoffDistance;\n let cutoff = clamp(1.0 - ratio * ratio * ratio * ratio, 0.0, 1.0);\n distanceFalloff *= cutoff * cutoff;\n }\n return distanceFalloff;\n}\n\n@fragment\nfn fsMain(input: VertexOutput) -> @location(0) vec4<f32> {\n let normal = normalize(input.worldNormal);\n let normalTint = normal * 0.5 + vec3<f32>(0.5);\n let base = mix(vec3<f32>(0.52, 0.58, 0.64), normalTint, 0.22) * input.color.rgb;\n var lighting = rendererIndirectDiffuse(normal) + vec3<f32>(0.08);\n var directionalLighting = vec3<f32>(0.0);\n let directionalCount = rendererDirectionalLightCount();\n\n for (var index: u32 = 0u; index < directionalCount; index = index + 1u) {\n let lightDirection = rendererDirectionalLightDirectionForLight(index);\n let shadow = rendererSampleDirectionalShadowForLightWithNormal(index, input.worldPosition, normal);\n directionalLighting += rendererDirectionalLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * shadow;\n }\n if (directionalCount > 0u) {\n lighting += directionalLighting / f32(directionalCount);\n }\n\n for (var index: u32 = 0u; index < rendererPointLightCount(); index = index + 1u) {\n let lightVector = rendererPointLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let shadow = rendererSamplePointShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererPointLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * distanceAttenuation(distanceToLight, rendererPointLightRangeForLight(index), rendererPointLightDecayForLight(index)) * shadow;\n }\n\n for (var index: u32 = 0u; index < rendererSpotLightCount(); index = index + 1u) {\n let lightVector = rendererSpotLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let angleCos = dot(-lightDirection, rendererSpotLightDirectionForLight(index));\n let cone = smoothstep(rendererSpotLightConeCosForLight(index), rendererSpotLightPenumbraCosForLight(index), angleCos);\n let shadow = rendererSampleSpotShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererSpotLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * cone * distanceAttenuation(distanceToLight, rendererSpotLightRangeForLight(index), rendererSpotLightDecayForLight(index)) * shadow;\n }\n\n return vec4<f32>(base * max(lighting, vec3<f32>(0.08)), input.color.a);\n}\n";/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -0,0 +1,22 @@
1
+ export interface WebGpuComputeKernelDescriptor {
2
+ label?: string;
3
+ code: string;
4
+ entryPoint?: string;
5
+ bindGroupLayoutEntries: GPUBindGroupLayoutEntry[];
6
+ }
7
+ export interface WebGpuComputeKernel {
8
+ readonly layout: GPUBindGroupLayout;
9
+ readonly pipeline: GPUComputePipeline;
10
+ createBindGroup(device: GPUDevice, entries: GPUBindGroupEntry[], label?: string): GPUBindGroup;
11
+ }
12
+ interface WebGpuRuntimeBindings {
13
+ createComputeKernel(device: GPUDevice, descriptor: WebGpuComputeKernelDescriptor): WebGpuComputeKernel;
14
+ buildParticleLightingShaderHeader(receiveShadow?: boolean, modelMatrixBody?: string): string;
15
+ }
16
+ export declare function configureWebGpuRuntimeBindings(value: WebGpuRuntimeBindings): void;
17
+ /** Loads renderer-side helpers only after a WebGPU-specific feature is requested. */
18
+ export declare function ensureWebGpuRuntimeBindings(): Promise<void>;
19
+ export declare function createWebGpuComputeKernel(device: GPUDevice, descriptor: WebGpuComputeKernelDescriptor): WebGpuComputeKernel;
20
+ export declare function buildWebGpuParticleLightingShaderHeader(receiveShadow?: boolean, modelMatrixBody?: string): string;
21
+ export {};
22
+ //# sourceMappingURL=webgpu-runtime-bridge.d.ts.map
@@ -0,0 +1,4 @@
1
+ let e=null,n=null;export function configureWebGpuRuntimeBindings(n){e=n}export async function ensureWebGpuRuntimeBindings(){null==e&&(n??(n=import("@hology/webgpu-renderer").then(e=>{configureWebGpuRuntimeBindings({createComputeKernel:(n,i)=>new e.ComputeKernel(n,i),buildParticleLightingShaderHeader:e.buildParticleLightingShaderHeader})}).catch(e=>{throw n=null,e})),await n)}export function createWebGpuComputeKernel(n,i){if(null==e)throw new Error("WebGPU runtime bindings are unavailable. Initialize the WebGPU rendering backend first.");return e.createComputeKernel(n,i)}export function buildWebGpuParticleLightingShaderHeader(n=!0,i){if(null==e)throw new Error("WebGPU runtime bindings are unavailable. Initialize the WebGPU rendering backend first.");return e.buildParticleLightingShaderHeader(n,i)}/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -18,7 +18,9 @@ import type { VfxBackendPreference } from './effects/vfx/gpu-sprite-compiler.js'
18
18
  export type { UpscalingOptions } from "./rendering/upscaling-pass.js";
19
19
  export type { AntiAliasingMode, ExperimentalWebGpuPostProcessingOptions, ExperimentalWebGpuRenderGraphExtension } from './rendering/webgpu-experimental-backend.js';
20
20
  export type { GTAOOptions, GTAOQuality, MotionBlurOptions, MotionBlurOverride, MotionBlurOverrideHandle, VolumetricFogOptions, VolumetricFogQuality } from './rendering/webgpu-experimental-backend.js';
21
- export type RenderingBackend = 'webgl' | 'webgpu-experimental';
21
+ /** Renderer requested by a view. `webgpu-experimental` is a deprecated alias. */
22
+ export type RenderingBackend = 'webgl' | 'webgpu' | 'webgpu-experimental';
23
+ export type ActiveRenderingBackend = 'webgl' | 'webgpu';
22
24
  export interface DirectionalShadowOptions {
23
25
  enabled: boolean;
24
26
  mapSize: number;
@@ -101,6 +103,7 @@ export type RenderingViewOptions = {
101
103
  enabled?: boolean;
102
104
  };
103
105
  shadows?: {
106
+ enabled?: boolean;
104
107
  autoUpdate?: boolean;
105
108
  /**
106
109
  * Array of update intervals (ms) for each CSM cascade. The first value is for the closest shadow, the next for the next cascade, etc.
@@ -115,27 +118,36 @@ export type RenderingViewOptions = {
115
118
  export declare class RenderingView {
116
119
  container: HTMLElement;
117
120
  readonly options: RenderingViewOptions;
121
+ private static readonly webGpuBackendPool;
118
122
  private static activeView;
119
- private static sharedExperimentalWebGpuBackend;
120
- private static sharedExperimentalWebGpuBackendPromise;
121
123
  private static experimentalWebGpuPresentationView;
122
- private _activeBackend;
124
+ private backendHandle;
125
+ private webGlBackend;
123
126
  private experimentalWebGpuBackend;
127
+ private experimentalWebGpuBackendPoolKey;
124
128
  private experimentalWebGpuFailed;
129
+ private webGpuRuntimeErrorReported;
125
130
  private experimentalWebGpuCapabilityReported;
126
131
  private experimentalWebGpuDynamicBatchingEnabled;
132
+ private ambientOcclusionSettings;
127
133
  private experimentalWebGpuSelectedObjectInstances;
134
+ private outlinesEnabled;
135
+ private selectedOutlineObjects;
128
136
  private experimentalStaticDrawSetRegistrations;
129
137
  private experimentalWebGpuRenderGraphExtensions;
130
138
  private worldEnvironment;
131
- get activeBackend(): RenderingBackend;
132
- get requestedBackend(): RenderingBackend;
139
+ get activeBackend(): ActiveRenderingBackend | null;
140
+ get canvas(): HTMLCanvasElement | null;
141
+ get initialized(): boolean;
142
+ get requestedBackend(): ActiveRenderingBackend;
133
143
  get vfxBackendPreference(): VfxBackendPreference;
134
144
  get webgpuVfxInstancesPerTemplate(): number;
135
145
  get webgpuVfxTemplateMemoryBudgetBytes(): number;
136
146
  get webgpuVfxWorldMemoryBudgetBytes(): number;
137
147
  /** @deprecated Retained for source compatibility; GPU VFX no longer performs timed eviction. */
138
148
  get webgpuVfxColdTemplateSeconds(): number;
149
+ get webGpuDevice(): GPUDevice | null;
150
+ /** @deprecated Use webGpuDevice. */
139
151
  get experimentalWebGpuDevice(): GPUDevice | null;
140
152
  /**
141
153
  * Snapshots a materialized static root after the experimental renderer has
@@ -143,14 +155,18 @@ export declare class RenderingView {
143
155
  * so WebGL fallback continues to render the normal Three.js objects.
144
156
  */
145
157
  registerExperimentalStaticDrawSet(root: THREE.Object3D, label: string, allowUnsortedLateDraws?: boolean): () => void;
146
- /** Registers a view-local extension executed by the shared WebGPU backend. */
158
+ /** @deprecated Use registerWebGpuRenderGraphExtension. */
147
159
  registerExperimentalWebGpuRenderGraphExtension(extension: ExperimentalWebGpuRenderGraphExtension): () => void;
148
160
  private isIntersecting;
149
161
  private needsPausedRender;
150
162
  private wakePausedRenderer;
151
163
  camera: THREE.Camera;
152
164
  windowVisible: boolean;
165
+ /** @deprecated WebGL-specific escape hatch. Use webGlRenderer and backend-neutral RenderingView APIs. */
153
166
  renderer: WebGLRenderer;
167
+ /** Returns the WebGL renderer only when the active backend is WebGL. */
168
+ get webGlRenderer(): WebGLRenderer | null;
169
+ registerWebGpuRenderGraphExtension(extension: ExperimentalWebGpuRenderGraphExtension): () => void;
154
170
  rendererDepth: WebGLRenderer;
155
171
  private composer;
156
172
  private bloomComposer;
@@ -193,8 +209,8 @@ export declare class RenderingView {
193
209
  private volumetricFogPass;
194
210
  private postProcessEffectId;
195
211
  private postProcessEffects;
196
- private readonly postProcessEffectResolution;
197
- private readonly postProcessEffectUniformState;
212
+ private postProcessEffectResolution;
213
+ private postProcessEffectUniformState;
198
214
  private fquadCopySceneColor;
199
215
  private fquadCopySceneDepth;
200
216
  private occlusionClusters;
@@ -212,6 +228,7 @@ export declare class RenderingView {
212
228
  * additively combined. Normals as well could simply be overwritten for SSR.
213
229
  */
214
230
  private fquadBlendAO;
231
+ private createAoblendQuad;
215
232
  setPaused(value: boolean): void;
216
233
  resolutionScale: number;
217
234
  maxPixelRatio: number;
@@ -270,6 +287,8 @@ export declare class RenderingView {
270
287
  private outlineEffect;
271
288
  private gRenderTarget;
272
289
  private phasedRenderPass;
290
+ private webGlInitialized;
291
+ private setupWebGlPipeline;
273
292
  constructor(container: HTMLElement, options?: RenderingViewOptions);
274
293
  addCluster(cluster: Cluster): void;
275
294
  /**
@@ -286,6 +305,11 @@ export declare class RenderingView {
286
305
  setMotionBlurOptions(options: MotionBlurOptions): void;
287
306
  setDirectionalShadowOptions(options: DirectionalShadowOptions): void;
288
307
  setGTAOOptions(options: GTAOOptions): void;
308
+ configureAmbientOcclusion(enabled: boolean, blendIntensity?: number, options?: Record<string, unknown>): void;
309
+ invalidateShadows(): void;
310
+ initTexture(texture: Texture): void;
311
+ setBaseToneMapping(mapping: THREE.ToneMapping, exposure: number): void;
312
+ get supportsWebGlDepthTexture(): boolean;
289
313
  setAntiAliasingMode(mode: AntiAliasingMode): void;
290
314
  setGTAOQuality(quality: GTAOQuality): void;
291
315
  setVolumetricFogOptions(options: VolumetricFogOptions): void;
@@ -330,7 +354,8 @@ export declare class RenderingView {
330
354
  private syncWebGpuPassStatsDom;
331
355
  private updateWebGpuPassStats;
332
356
  private getActiveRendererCanvas;
333
- private disableExperimentalWebGpu;
357
+ private requireInitializedBackend;
358
+ private fallbackToWebGlForUnavailableWebGpu;
334
359
  private activateExperimentalStaticDrawSets;
335
360
  private disposeExperimentalStaticDrawSets;
336
361
  private applyEnvMap;
@@ -405,6 +430,12 @@ export declare class RenderingView {
405
430
  private unapplyGBufferMaterials;
406
431
  private applyGBufferShadowUniformUpdater;
407
432
  initTextures(scene?: THREE.Scene): void;
433
+ /**
434
+ * Initializes scene textures without monopolizing the host event loop.
435
+ * Intended for loading boundaries where native hosts must continue pumping
436
+ * their window and presenting a loading UI while uploads are prepared.
437
+ */
438
+ initTexturesAsync(scene?: THREE.Scene): Promise<void>;
408
439
  private _initiatedMaterialTextures;
409
440
  private _initiatedTextures;
410
441
  private _initMaterialTextures;
@@ -412,15 +443,15 @@ export declare class RenderingView {
412
443
  private compileInProgress;
413
444
  compileAsync(scene?: Object3D): Promise<void>;
414
445
  private compileExperimentalWebGpu;
415
- private static acquireSharedExperimentalWebGpuBackend;
446
+ private acquireWebGpuBackend;
447
+ private releaseExperimentalWebGpuBackend;
416
448
  private applyExperimentalWebGpuViewState;
449
+ private syncWebGpuOutlineState;
417
450
  private depthMaterialCachedMaterials;
418
451
  private applyDepthMaterial;
419
452
  private unapplyDepthMaterial;
420
453
  private renderScene;
421
- private pmremGenerator?;
422
- private pmremGeneratorResults;
423
- getEnvTexture(texture: Texture): THREE.Texture;
454
+ getEnvTexture(texture: Texture): Texture;
424
455
  private applyPostProcessSettings;
425
456
  private updatePostProcessEffectUniforms;
426
457
  private insetHeight;
@@ -439,8 +470,6 @@ export declare class RenderingView {
439
470
  private bloomStoredMaterials;
440
471
  private bloomHidden;
441
472
  private hasBloom;
442
- private darkenNonBloomed;
443
- private restoreMaterial;
444
473
  private initSceneColorUniform;
445
474
  private initDepthUniform;
446
475
  private initNormalUniform;