@hology/core 0.0.250 → 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.
- package/dist/effects/vfx/gpu-sprite-runtime.js +1 -1
- package/dist/effects/vfx/gpu-vfx-world-service.js +1 -1
- package/dist/gameplay/actors/actor.js +1 -1
- package/dist/gameplay/actors/camera/third-person-camera-component.js +1 -1
- package/dist/gameplay/ai/dynamic-tiled-navmesh.js +1 -1
- package/dist/gameplay/initiate.d.ts +4 -0
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/services/render.d.ts +11 -3
- package/dist/gameplay/services/render.js +1 -1
- package/dist/rendering/native-dlss-upscaler.d.ts +104 -0
- package/dist/rendering/native-dlss-upscaler.js +4 -0
- package/dist/rendering/node-material-webgpu-resolver.d.ts +2 -1
- package/dist/rendering/node-material-webgpu-resolver.js +1 -1
- package/dist/rendering/post-process-effect.d.ts +1 -1
- package/dist/rendering/post-process-effect.js +1 -1
- package/dist/rendering/rendering-backend.d.ts +9 -0
- package/dist/rendering/rendering-backend.js +4 -0
- package/dist/rendering/upscaling-pass.d.ts +9 -1
- package/dist/rendering/upscaling-pass.js +1 -1
- package/dist/rendering/webgl-backend.d.ts +32 -0
- package/dist/rendering/webgl-backend.js +4 -0
- package/dist/rendering/webgpu-experimental-backend.d.ts +19 -2
- package/dist/rendering/webgpu-experimental-backend.js +1 -1
- package/dist/rendering/webgpu-runtime-bridge.d.ts +22 -0
- package/dist/rendering/webgpu-runtime-bridge.js +4 -0
- package/dist/rendering.d.ts +45 -16
- package/dist/rendering.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +5 -0
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/materials/water.js +1 -1
- package/dist/scene/runtime-bundled-backend-service.d.ts +7 -0
- package/dist/scene/runtime-bundled-backend-service.js +1 -1
- package/dist/scene/storage/packed-json.js +1 -1
- package/dist/secondary-motion/runtime.d.ts +1 -1
- package/dist/secondary-motion/runtime.js +1 -1
- package/dist/test/actor-attachment.test.d.ts +2 -0
- package/dist/test/actor-attachment.test.js +4 -0
- package/dist/test/gpu-sprite-compiler.test.js +1 -1
- package/dist/test/native-dlss-upscaler.test.d.ts +2 -0
- package/dist/test/native-dlss-upscaler.test.js +4 -0
- package/dist/test/node-material-webgpu-resolver.test.js +1 -1
- package/dist/test/webgpu-experimental-backend.test.js +1 -1
- package/dist/utils/uuid.js +1 -1
- package/package.json +1 -1
- 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
|
|
@@ -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
|
|
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
|
+
*/
|
package/dist/rendering.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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():
|
|
132
|
-
get
|
|
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
|
-
/**
|
|
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
|
|
197
|
-
private
|
|
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
|
|
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
|
|
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
|
-
|
|
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;
|