@aura3d/rendering 1.5.2 → 2.0.0

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 (196) hide show
  1. package/README.md +8 -2
  2. package/dist/ArchitecturalLighting.d.ts +35 -0
  3. package/dist/ArchitecturalLighting.d.ts.map +1 -0
  4. package/dist/ArchitecturalLighting.js +162 -0
  5. package/dist/ArchitecturalLighting.js.map +1 -0
  6. package/dist/ArchitecturalMaterialCatalog.d.ts +1 -1
  7. package/dist/ArchitecturalMaterialCatalog.d.ts.map +1 -1
  8. package/dist/ArchitecturalMaterialCatalog.js +1 -1
  9. package/dist/ArchitecturalMaterialCatalog.js.map +1 -1
  10. package/dist/ArchitecturalMeasurement.d.ts +27 -0
  11. package/dist/ArchitecturalMeasurement.d.ts.map +1 -0
  12. package/dist/ArchitecturalMeasurement.js +112 -0
  13. package/dist/ArchitecturalMeasurement.js.map +1 -0
  14. package/dist/CanonicalProductScene.d.ts +13 -0
  15. package/dist/CanonicalProductScene.d.ts.map +1 -0
  16. package/dist/CanonicalProductScene.js +78 -0
  17. package/dist/CanonicalProductScene.js.map +1 -0
  18. package/dist/CascadedShadowMaps.d.ts +1 -1
  19. package/dist/CascadedShadowMaps.d.ts.map +1 -1
  20. package/dist/CascadedShadowMaps.js +1 -1
  21. package/dist/CascadedShadowMaps.js.map +1 -1
  22. package/dist/DepthPass.d.ts +1 -1
  23. package/dist/DepthPass.d.ts.map +1 -1
  24. package/dist/DepthPass.js +2 -2
  25. package/dist/DepthPass.js.map +1 -1
  26. package/dist/EnvironmentBackgroundPass.d.ts +1 -1
  27. package/dist/EnvironmentBackgroundPass.d.ts.map +1 -1
  28. package/dist/EnvironmentBackgroundPass.js +2 -2
  29. package/dist/EnvironmentBackgroundPass.js.map +1 -1
  30. package/dist/EnvironmentPlatform.js +2 -2
  31. package/dist/EnvironmentPlatform.js.map +1 -1
  32. package/dist/ForwardPass.d.ts +1 -1
  33. package/dist/ForwardPass.d.ts.map +1 -1
  34. package/dist/ForwardPass.js +24 -10
  35. package/dist/ForwardPass.js.map +1 -1
  36. package/dist/Geometry.d.ts +2 -0
  37. package/dist/Geometry.d.ts.map +1 -1
  38. package/dist/Geometry.js +15 -0
  39. package/dist/Geometry.js.map +1 -1
  40. package/dist/InstancedPBRMaterial.js +1 -1
  41. package/dist/InstancedPBRMaterial.js.map +1 -1
  42. package/dist/InstancedUnlitMaterial.js +1 -1
  43. package/dist/InstancedUnlitMaterial.js.map +1 -1
  44. package/dist/Material.js +2 -2
  45. package/dist/Material.js.map +1 -1
  46. package/dist/MaterialBinding.js +4 -4
  47. package/dist/MaterialBinding.js.map +1 -1
  48. package/dist/MaterialInstance.js +2 -2
  49. package/dist/MaterialInstance.js.map +1 -1
  50. package/dist/MorphUnlitMaterial.js +1 -1
  51. package/dist/MorphUnlitMaterial.js.map +1 -1
  52. package/dist/NormalMappedPBRMaterial.js +1 -1
  53. package/dist/NormalMappedPBRMaterial.js.map +1 -1
  54. package/dist/OceanSurface.d.ts +62 -0
  55. package/dist/OceanSurface.d.ts.map +1 -0
  56. package/dist/OceanSurface.js +240 -0
  57. package/dist/OceanSurface.js.map +1 -0
  58. package/dist/PBRMaterial.d.ts.map +1 -1
  59. package/dist/PBRMaterial.js +3 -3
  60. package/dist/PBRMaterial.js.map +1 -1
  61. package/dist/PortableShaderMaterial.d.ts +60 -0
  62. package/dist/PortableShaderMaterial.d.ts.map +1 -0
  63. package/dist/PortableShaderMaterial.js +223 -0
  64. package/dist/PortableShaderMaterial.js.map +1 -0
  65. package/dist/PostProcessPass.d.ts.map +1 -1
  66. package/dist/PostProcessPass.js +30 -6
  67. package/dist/PostProcessPass.js.map +1 -1
  68. package/dist/ProceduralTexture.d.ts +27 -0
  69. package/dist/ProceduralTexture.d.ts.map +1 -0
  70. package/dist/ProceduralTexture.js +336 -0
  71. package/dist/ProceduralTexture.js.map +1 -0
  72. package/dist/ProductTurntable.d.ts +96 -0
  73. package/dist/ProductTurntable.d.ts.map +1 -0
  74. package/dist/ProductTurntable.js +639 -0
  75. package/dist/ProductTurntable.js.map +1 -0
  76. package/dist/RenderDevice.d.ts +30 -0
  77. package/dist/RenderDevice.d.ts.map +1 -1
  78. package/dist/RenderDevice.js.map +1 -1
  79. package/dist/Renderer.d.ts +3 -2
  80. package/dist/Renderer.d.ts.map +1 -1
  81. package/dist/Renderer.js +23 -9
  82. package/dist/Renderer.js.map +1 -1
  83. package/dist/RendererPostprocessPlan.js +4 -4
  84. package/dist/RendererPostprocessPlan.js.map +1 -1
  85. package/dist/ScreenSpaceLineMaterial.js +1 -1
  86. package/dist/ScreenSpaceLineMaterial.js.map +1 -1
  87. package/dist/ShaderChunks.d.ts.map +1 -1
  88. package/dist/ShaderChunks.js +81 -19
  89. package/dist/ShaderChunks.js.map +1 -1
  90. package/dist/ShaderLibrary.d.ts +2 -78
  91. package/dist/ShaderLibrary.d.ts.map +1 -1
  92. package/dist/ShaderLibrary.js +127 -793
  93. package/dist/ShaderLibrary.js.map +1 -1
  94. package/dist/ShaderLibraryCore.d.ts +100 -0
  95. package/dist/ShaderLibraryCore.d.ts.map +1 -0
  96. package/dist/ShaderLibraryCore.js +800 -0
  97. package/dist/ShaderLibraryCore.js.map +1 -0
  98. package/dist/ShaderModule.d.ts +1 -1
  99. package/dist/ShaderModule.d.ts.map +1 -1
  100. package/dist/ShaderModule.js +4 -2
  101. package/dist/ShaderModule.js.map +1 -1
  102. package/dist/ShadowPass.d.ts +1 -1
  103. package/dist/ShadowPass.d.ts.map +1 -1
  104. package/dist/ShadowPass.js +6 -4
  105. package/dist/ShadowPass.js.map +1 -1
  106. package/dist/SkinnedLitMaterial.js +1 -1
  107. package/dist/SkinnedLitMaterial.js.map +1 -1
  108. package/dist/SkinnedUnlitMaterial.js +1 -1
  109. package/dist/SkinnedUnlitMaterial.js.map +1 -1
  110. package/dist/SpaceEnvironment.d.ts +54 -0
  111. package/dist/SpaceEnvironment.d.ts.map +1 -0
  112. package/dist/SpaceEnvironment.js +116 -0
  113. package/dist/SpaceEnvironment.js.map +1 -0
  114. package/dist/TerrainHeightfield.d.ts +60 -0
  115. package/dist/TerrainHeightfield.d.ts.map +1 -0
  116. package/dist/TerrainHeightfield.js +239 -0
  117. package/dist/TerrainHeightfield.js.map +1 -0
  118. package/dist/TextureBinding.d.ts +14 -0
  119. package/dist/TextureBinding.d.ts.map +1 -1
  120. package/dist/TextureBinding.js +17 -0
  121. package/dist/TextureBinding.js.map +1 -1
  122. package/dist/TexturedPBRMaterial.js +1 -1
  123. package/dist/TexturedPBRMaterial.js.map +1 -1
  124. package/dist/TexturedUnlitMaterial.js +1 -1
  125. package/dist/TexturedUnlitMaterial.js.map +1 -1
  126. package/dist/UnlitMaterial.js +1 -1
  127. package/dist/UnlitMaterial.js.map +1 -1
  128. package/dist/VegetationFixtures.d.ts +1 -1
  129. package/dist/VegetationFixtures.d.ts.map +1 -1
  130. package/dist/VegetationFixtures.js +1 -1
  131. package/dist/VegetationFixtures.js.map +1 -1
  132. package/dist/VegetationScatter.d.ts +68 -0
  133. package/dist/VegetationScatter.d.ts.map +1 -0
  134. package/dist/VegetationScatter.js +241 -0
  135. package/dist/VegetationScatter.js.map +1 -0
  136. package/dist/VoxelWorld.d.ts +51 -0
  137. package/dist/VoxelWorld.d.ts.map +1 -0
  138. package/dist/VoxelWorld.js +183 -0
  139. package/dist/VoxelWorld.js.map +1 -0
  140. package/dist/Weather.d.ts +44 -0
  141. package/dist/Weather.d.ts.map +1 -0
  142. package/dist/Weather.js +140 -0
  143. package/dist/Weather.js.map +1 -0
  144. package/dist/WebGL2Device.d.ts +22 -0
  145. package/dist/WebGL2Device.d.ts.map +1 -1
  146. package/dist/WebGL2Device.js +134 -23
  147. package/dist/WebGL2Device.js.map +1 -1
  148. package/dist/WebGPUDevice.d.ts +19 -2
  149. package/dist/WebGPUDevice.d.ts.map +1 -1
  150. package/dist/WebGPUDevice.js +188 -9
  151. package/dist/WebGPUDevice.js.map +1 -1
  152. package/dist/index.d.ts +25 -32
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.js +35 -19
  155. package/dist/index.js.map +1 -1
  156. package/dist/lean/LeanProductRenderer.d.ts +29 -0
  157. package/dist/lean/LeanProductRenderer.d.ts.map +1 -0
  158. package/dist/lean/LeanProductRenderer.js +38 -0
  159. package/dist/lean/LeanProductRenderer.js.map +1 -0
  160. package/dist/lean/LeanProductionRenderer.d.ts +38 -0
  161. package/dist/lean/LeanProductionRenderer.d.ts.map +1 -0
  162. package/dist/lean/LeanProductionRenderer.js +88 -0
  163. package/dist/lean/LeanProductionRenderer.js.map +1 -0
  164. package/dist/lean-runtime.d.ts +18 -0
  165. package/dist/lean-runtime.d.ts.map +1 -0
  166. package/dist/lean-runtime.js +13 -0
  167. package/dist/lean-runtime.js.map +1 -0
  168. package/dist/postprocess/EffectComposer.d.ts.map +1 -1
  169. package/dist/postprocess/EffectComposer.js +1 -3
  170. package/dist/postprocess/EffectComposer.js.map +1 -1
  171. package/dist/production-runtime/PBRHDRPipeline.d.ts.map +1 -1
  172. package/dist/production-runtime/PBRHDRPipeline.js +5 -1
  173. package/dist/production-runtime/PBRHDRPipeline.js.map +1 -1
  174. package/dist/production-runtime/ProductionRendererTypes.d.ts +9 -0
  175. package/dist/production-runtime/ProductionRendererTypes.d.ts.map +1 -1
  176. package/dist/production-runtime/ProductionRendererTypes.js.map +1 -1
  177. package/dist/production-runtime/ProductionRuntimeRenderer.d.ts +5 -0
  178. package/dist/production-runtime/ProductionRuntimeRenderer.d.ts.map +1 -1
  179. package/dist/production-runtime/ProductionRuntimeRenderer.js +53 -5
  180. package/dist/production-runtime/ProductionRuntimeRenderer.js.map +1 -1
  181. package/dist/production-runtime/ProductionWebGL2Renderer.d.ts +10 -0
  182. package/dist/production-runtime/ProductionWebGL2Renderer.d.ts.map +1 -1
  183. package/dist/production-runtime/ProductionWebGL2Renderer.js +21 -2
  184. package/dist/production-runtime/ProductionWebGL2Renderer.js.map +1 -1
  185. package/dist/production-runtime/ProductionWebGPURenderer.d.ts.map +1 -1
  186. package/dist/production-runtime/ProductionWebGPURenderer.js +4 -1
  187. package/dist/production-runtime/ProductionWebGPURenderer.js.map +1 -1
  188. package/dist/webgpu-device-entry.d.ts +25 -0
  189. package/dist/webgpu-device-entry.d.ts.map +1 -0
  190. package/dist/webgpu-device-entry.js +24 -0
  191. package/dist/webgpu-device-entry.js.map +1 -0
  192. package/dist/webgpu.d.ts +25 -0
  193. package/dist/webgpu.d.ts.map +1 -0
  194. package/dist/webgpu.js +24 -0
  195. package/dist/webgpu.js.map +1 -0
  196. package/package.json +11 -3
@@ -1,6 +1,6 @@
1
1
  import { RenderDeviceError, } from "./RenderDevice.js";
2
2
  import { Texture, isCompressedTextureFormat, isFloatColorTextureFormat } from "./Texture.js";
3
- import { TextureBinding } from "./TextureBinding.js";
3
+ import { isTextureBinding, TextureBinding } from "./TextureBinding.js";
4
4
  import {} from "./VertexFormat.js";
5
5
  import { WebGL2StateCache } from "./WebGL2StateCache.js";
6
6
  import { BLOOM_BRIGHT_LUT_HEIGHT, BLOOM_BRIGHT_LUT_WIDTH, BLOOM_COMPOSITE_LUT_SIZE, OUTLINE_BLEND_LUT_WIDTH, OUTLINE_LIMB_RADIX, createOutlineBlendLut, createOutlineGradientBound, createBloomBrightThresholdLut, createBloomCompositeLut } from "./postprocess/NativeLdrEffectLuts.js";
@@ -169,6 +169,16 @@ export class WebGL2Device {
169
169
  maxVertexAttributes;
170
170
  anisotropicFilteringExtension;
171
171
  maxTextureAnisotropy;
172
+ /**
173
+ * WS-2.6 — subscribers for context loss and restoration.
174
+ *
175
+ * The device has tracked `contextLost` since before 1.6 and acted on it internally, but nothing
176
+ * could *observe* it: there was no callback, so a consumer could only poll `diagnostics()`. That is
177
+ * why the parity table listed context-loss recovery as a gap while the listeners existed — the
178
+ * device layer was never the gap, the absence of a public signal was.
179
+ */
180
+ deviceLostListeners = new Set();
181
+ deviceRestoredListeners = new Set();
172
182
  contextLostListener;
173
183
  contextRestoredListener;
174
184
  canvas;
@@ -196,6 +206,16 @@ export class WebGL2Device {
196
206
  constructor(gl, canvas, errorCheckMode) {
197
207
  this.errorCheckMode = errorCheckMode;
198
208
  this.gl = gl;
209
+ // A browser returns the same WebGL2 context object after `webglcontextrestored`.
210
+ // The controller that owned it before the loss is disposed before a replacement
211
+ // device mounts, and Chromium can leave an INVALID_OPERATION from that stale
212
+ // resource teardown in the context's error queue. A fresh device must establish
213
+ // its own error boundary; otherwise its first valid uniform upload or presentation
214
+ // is blamed for an error produced by the previous owner.
215
+ for (let index = 0; index < 16 && gl.getError() !== gl.NO_ERROR; index += 1) {
216
+ // Drain only errors that predate this device. Normal frame/strict checks still
217
+ // report every error generated after construction.
218
+ }
199
219
  this.maxVertexAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
200
220
  this.anisotropicFilteringExtension = gl.getExtension("EXT_texture_filter_anisotropic");
201
221
  this.maxTextureAnisotropy = this.anisotropicFilteringExtension
@@ -230,15 +250,53 @@ export class WebGL2Device {
230
250
  this.contextLost = true;
231
251
  this.lastError = "CONTEXT_LOST";
232
252
  this.frameActive = false;
253
+ // WS-2.6: notify subscribers. Errors in a listener must not prevent the others from running,
254
+ // nor leave the device in a half-notified state during an already-degraded condition.
255
+ for (const listener of [...this.deviceLostListeners]) {
256
+ try {
257
+ listener();
258
+ }
259
+ catch {
260
+ // A listener that throws is the listener's problem; the device stays consistent.
261
+ }
262
+ }
233
263
  });
234
264
  this.contextRestoredListener = (() => {
235
265
  this.contextLost = false;
236
266
  this.lastError = null;
267
+ for (const listener of [...this.deviceRestoredListeners]) {
268
+ try {
269
+ listener();
270
+ }
271
+ catch {
272
+ // As above.
273
+ }
274
+ }
237
275
  });
238
276
  canvas.addEventListener("webglcontextlost", this.contextLostListener);
239
277
  canvas.addEventListener("webglcontextrestored", this.contextRestoredListener);
240
278
  }
241
279
  }
280
+ /**
281
+ * Subscribe to WebGL context loss. Returns an unsubscribe function.
282
+ *
283
+ * A lost context is not an error a caller can prevent — the browser reclaims GPU resources under
284
+ * memory pressure, on driver reset, or when a tab is backgrounded too long. What a caller can do is
285
+ * be told, so it can recreate resources rather than render nothing.
286
+ */
287
+ onDeviceLost(listener) {
288
+ this.deviceLostListeners.add(listener);
289
+ return () => this.deviceLostListeners.delete(listener);
290
+ }
291
+ /** Subscribe to context restoration. Returns an unsubscribe function. */
292
+ onDeviceRestored(listener) {
293
+ this.deviceRestoredListeners.add(listener);
294
+ return () => this.deviceRestoredListeners.delete(listener);
295
+ }
296
+ /** True while the WebGL context is lost. Polling alternative to {@link onDeviceLost}. */
297
+ isDeviceLost() {
298
+ return this.contextLost;
299
+ }
242
300
  createBuffer(usage, byteLength, initialData) {
243
301
  this.assertAlive();
244
302
  if (byteLength <= 0 || !Number.isInteger(byteLength)) {
@@ -574,13 +632,6 @@ export class WebGL2Device {
574
632
  format: source.colorTexture.format
575
633
  });
576
634
  }
577
- if (source.colorTexture.format !== "rgba8" && bloomPass) {
578
- throw new RenderDeviceError("WebGL2 native LUT bloom accepts rgba8 input; HDR bloom must use the renderer float-bloom path before tone mapping.", "WEBGL_LDR_POSTPROCESS_FORMAT_UNSUPPORTED", {
579
- targetId: source.id,
580
- format: source.colorTexture.format,
581
- pass: "bloom"
582
- });
583
- }
584
635
  if (source.colorTexture.format !== "rgba8" && (depthOfFieldPass || motionBlurPass || ssaoPass || ssrPass || taaPass || outlinePass) && !tonePass) {
585
636
  throw new RenderDeviceError("WebGL2 byte-kernel postprocess requires rgba8 input or a preceding tone-mapping pass.", "WEBGL_LDR_POSTPROCESS_FORMAT_UNSUPPORTED", {
586
637
  targetId: source.id,
@@ -628,10 +679,11 @@ export class WebGL2Device {
628
679
  const outlineOptions = outlinePass ? normalizeNativeOutlineOptions(outlinePass.options) : undefined;
629
680
  const program = this.ensureLdrPostprocessProgram();
630
681
  const vertexArray = this.ensurePresentationVertexArray();
682
+ const sourceIsHdr = source.colorTexture.format !== "rgba8";
631
683
  const bloomResources = bloomOptions || depthOfFieldOptions || motionBlurOptions || ssaoOptions || ssrOptions || taaOptions || outlineOptions
632
- ? this.ensureBloomPingPongResources(source.width, source.height)
684
+ ? this.ensureBloomPingPongResources(source.width, source.height, sourceIsHdr && Boolean(bloomOptions))
633
685
  : undefined;
634
- if (bloomOptions) {
686
+ if (bloomOptions && !sourceIsHdr) {
635
687
  this.ensureBloomLutTextures(bloomOptions);
636
688
  }
637
689
  if (outlineOptions) {
@@ -650,7 +702,7 @@ export class WebGL2Device {
650
702
  let ldrSourceHandle = source.colorHandle;
651
703
  let temporarySourceIndex = -1;
652
704
  if (bloomOptions && bloomResources) {
653
- ldrSourceHandle = this.executeNativeBloomPasses(ldrSourceHandle, bloomResources, bloomOptions, vertexArray);
705
+ ldrSourceHandle = this.executeNativeBloomPasses(ldrSourceHandle, bloomResources, bloomOptions, vertexArray, sourceIsHdr);
654
706
  temporarySourceIndex = 1;
655
707
  }
656
708
  if ((depthOfFieldOptions || motionBlurOptions || ssaoOptions || ssrOptions || taaOptions || outlineOptions) && bloomResources) {
@@ -1008,6 +1060,8 @@ export class WebGL2Device {
1008
1060
  }
1009
1061
  dispose() {
1010
1062
  if (this.canvas && "removeEventListener" in this.canvas) {
1063
+ this.deviceLostListeners.clear();
1064
+ this.deviceRestoredListeners.clear();
1011
1065
  if (this.contextLostListener)
1012
1066
  this.canvas.removeEventListener("webglcontextlost", this.contextLostListener);
1013
1067
  if (this.contextRestoredListener)
@@ -1223,9 +1277,9 @@ export class WebGL2Device {
1223
1277
  this.restoreFullscreenPresentationState(previousState, outputWidth, outputHeight);
1224
1278
  }
1225
1279
  }
1226
- ensureBloomPingPongResources(width, height) {
1280
+ ensureBloomPingPongResources(width, height, hdr = false) {
1227
1281
  const current = this.bloomPingPongResources;
1228
- if (current && current.width === width && current.height === height) {
1282
+ if (current && current.width === width && current.height === height && current.hdr === hdr) {
1229
1283
  return current;
1230
1284
  }
1231
1285
  this.disposeBloomPingPongResources();
@@ -1255,7 +1309,7 @@ export class WebGL2Device {
1255
1309
  this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
1256
1310
  this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
1257
1311
  this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
1258
- this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA8, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, null);
1312
+ this.gl.texImage2D(this.gl.TEXTURE_2D, 0, hdr ? this.gl.RGBA16F : this.gl.RGBA8, width, height, 0, this.gl.RGBA, hdr ? this.gl.HALF_FLOAT : this.gl.UNSIGNED_BYTE, null);
1259
1313
  this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
1260
1314
  this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, texture, 0);
1261
1315
  const status = this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);
@@ -1271,6 +1325,7 @@ export class WebGL2Device {
1271
1325
  const resources = {
1272
1326
  width,
1273
1327
  height,
1328
+ hdr,
1274
1329
  textures: [textures[0], textures[1]],
1275
1330
  framebuffers: [framebuffers[0], framebuffers[1]]
1276
1331
  };
@@ -1412,10 +1467,10 @@ export class WebGL2Device {
1412
1467
  this.gl.uniform1f(this.gl.getUniformLocation(program, "u_subpixelBlend"), numberOption(fxaaOptions, "subpixelBlend", 0.75));
1413
1468
  this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1414
1469
  }
1415
- executeNativeBloomPasses(sourceTexture, resources, options, vertexArray) {
1470
+ executeNativeBloomPasses(sourceTexture, resources, options, vertexArray, hdr) {
1416
1471
  const brightLut = this.bloomBrightLutTexture;
1417
1472
  const compositeLut = this.bloomCompositeLutTexture;
1418
- if (!brightLut || !compositeLut) {
1473
+ if (!hdr && (!brightLut || !compositeLut)) {
1419
1474
  throw new RenderDeviceError("WebGL2 bloom lookup textures were not initialized", "WEBGL_ALLOCATION_FAILED");
1420
1475
  }
1421
1476
  const [textureA, textureB] = resources.textures;
@@ -1426,9 +1481,12 @@ export class WebGL2Device {
1426
1481
  this.gl.useProgram(brightProgram);
1427
1482
  this.gl.bindVertexArray(vertexArray);
1428
1483
  this.bindFullscreenTexture(0, sourceTexture);
1429
- this.bindFullscreenTexture(1, brightLut);
1484
+ if (brightLut)
1485
+ this.bindFullscreenTexture(1, brightLut);
1430
1486
  this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_source"), 0);
1431
1487
  this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_brightLut"), 1);
1488
+ this.gl.uniform1i(this.gl.getUniformLocation(brightProgram, "u_hdr"), hdr ? 1 : 0);
1489
+ this.gl.uniform1f(this.gl.getUniformLocation(brightProgram, "u_threshold"), options.threshold);
1432
1490
  this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1433
1491
  const blurProgram = this.ensureBloomBlurProgram();
1434
1492
  this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebufferB);
@@ -1438,6 +1496,7 @@ export class WebGL2Device {
1438
1496
  this.gl.uniform2i(this.gl.getUniformLocation(blurProgram, "u_size"), resources.width, resources.height);
1439
1497
  this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_radius"), options.radius);
1440
1498
  this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_horizontal"), 1);
1499
+ this.gl.uniform1i(this.gl.getUniformLocation(blurProgram, "u_hdr"), hdr ? 1 : 0);
1441
1500
  this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1442
1501
  this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebufferA);
1443
1502
  this.bindFullscreenTexture(0, textureB);
@@ -1448,10 +1507,13 @@ export class WebGL2Device {
1448
1507
  this.gl.useProgram(compositeProgram);
1449
1508
  this.bindFullscreenTexture(0, sourceTexture);
1450
1509
  this.bindFullscreenTexture(1, textureA);
1451
- this.bindFullscreenTexture(2, compositeLut);
1510
+ if (compositeLut)
1511
+ this.bindFullscreenTexture(2, compositeLut);
1452
1512
  this.gl.uniform1i(this.gl.getUniformLocation(compositeProgram, "u_source"), 0);
1453
1513
  this.gl.uniform1i(this.gl.getUniformLocation(compositeProgram, "u_blurred"), 1);
1454
1514
  this.gl.uniform1i(this.gl.getUniformLocation(compositeProgram, "u_compositeLut"), 2);
1515
+ this.gl.uniform1i(this.gl.getUniformLocation(compositeProgram, "u_hdr"), hdr ? 1 : 0);
1516
+ this.gl.uniform1f(this.gl.getUniformLocation(compositeProgram, "u_intensity"), options.intensity);
1455
1517
  this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
1456
1518
  return textureB;
1457
1519
  }
@@ -1792,6 +1854,8 @@ precision highp float;
1792
1854
  precision highp int;
1793
1855
  uniform sampler2D u_source;
1794
1856
  uniform sampler2D u_brightLut;
1857
+ uniform int u_hdr;
1858
+ uniform float u_threshold;
1795
1859
  out vec4 outColor;
1796
1860
 
1797
1861
  uvec4 byteTexel(sampler2D source, ivec2 coordinate) {
@@ -1800,6 +1864,12 @@ uvec4 byteTexel(sampler2D source, ivec2 coordinate) {
1800
1864
 
1801
1865
  void main() {
1802
1866
  ivec2 pixel = ivec2(gl_FragCoord.xy);
1867
+ if (u_hdr == 1) {
1868
+ vec4 source = texelFetch(u_source, pixel, 0);
1869
+ float luma = dot(source.rgb, vec3(0.2126, 0.7152, 0.0722));
1870
+ outColor = luma >= u_threshold ? source : vec4(0.0);
1871
+ return;
1872
+ }
1803
1873
  uvec4 source = byteTexel(u_source, pixel);
1804
1874
  uint colorIndex = (source.r << 16u) | (source.g << 8u) | source.b;
1805
1875
  uint byteIndex = colorIndex >> 3u;
@@ -1834,6 +1904,7 @@ uniform sampler2D u_source;
1834
1904
  uniform ivec2 u_size;
1835
1905
  uniform int u_radius;
1836
1906
  uniform int u_horizontal;
1907
+ uniform int u_hdr;
1837
1908
  out vec4 outColor;
1838
1909
 
1839
1910
  uvec4 sourceByte(ivec2 coordinate) {
@@ -1843,6 +1914,16 @@ uvec4 sourceByte(ivec2 coordinate) {
1843
1914
 
1844
1915
  void main() {
1845
1916
  ivec2 pixel = ivec2(gl_FragCoord.xy);
1917
+ if (u_hdr == 1) {
1918
+ vec4 sum = vec4(0.0);
1919
+ for (int offset = -16; offset <= 16; offset += 1) {
1920
+ if (abs(offset) > u_radius) continue;
1921
+ ivec2 sampleCoordinate = pixel + (u_horizontal == 1 ? ivec2(offset, 0) : ivec2(0, offset));
1922
+ sum += texelFetch(u_source, clamp(sampleCoordinate, ivec2(0), u_size - ivec2(1)), 0);
1923
+ }
1924
+ outColor = sum / float(u_radius * 2 + 1);
1925
+ return;
1926
+ }
1846
1927
  uvec4 sum = uvec4(0u);
1847
1928
  for (int offset = -16; offset <= 16; offset += 1) {
1848
1929
  if (abs(offset) > u_radius) {
@@ -1872,6 +1953,8 @@ precision highp int;
1872
1953
  uniform sampler2D u_source;
1873
1954
  uniform sampler2D u_blurred;
1874
1955
  uniform sampler2D u_compositeLut;
1956
+ uniform int u_hdr;
1957
+ uniform float u_intensity;
1875
1958
  out vec4 outColor;
1876
1959
 
1877
1960
  uvec4 byteTexel(sampler2D source, ivec2 coordinate) {
@@ -1884,6 +1967,12 @@ float compositeChannel(uint source, uint blurred) {
1884
1967
 
1885
1968
  void main() {
1886
1969
  ivec2 pixel = ivec2(gl_FragCoord.xy);
1970
+ if (u_hdr == 1) {
1971
+ vec4 source = texelFetch(u_source, pixel, 0);
1972
+ vec3 blurred = texelFetch(u_blurred, pixel, 0).rgb;
1973
+ outColor = vec4(source.rgb + blurred * u_intensity, source.a);
1974
+ return;
1975
+ }
1887
1976
  uvec4 source = byteTexel(u_source, pixel);
1888
1977
  uvec4 blurred = byteTexel(u_blurred, pixel);
1889
1978
  outColor = vec4(
@@ -2238,8 +2327,28 @@ vec3 encodeColor(vec3 color) {
2238
2327
  return u_outputColorSpace == 1 ? vec3(linearToSrgb(linear.r), linearToSrgb(linear.g), linearToSrgb(linear.b)) : linear;
2239
2328
  }
2240
2329
 
2241
- float aces(float value) {
2242
- return (value * (2.51 * value + 0.03)) / (value * (2.43 * value + 0.59) + 0.14);
2330
+ vec3 acesRrtAndOdtFit(vec3 value) {
2331
+ vec3 numerator = value * (value + 0.0245786) - 0.000090537;
2332
+ vec3 denominator = value * (0.983729 * value + 0.4329510) + 0.238081;
2333
+ return numerator / denominator;
2334
+ }
2335
+
2336
+ vec3 acesFilmic(vec3 color) {
2337
+ // Match current Three.js ACESFilmicToneMapping. ACES is a coupled RGB
2338
+ // transform; a scalar approximation shifts hue and washes saturated colors.
2339
+ const mat3 acesInput = mat3(
2340
+ vec3(0.59719, 0.07600, 0.02840),
2341
+ vec3(0.35458, 0.90834, 0.13383),
2342
+ vec3(0.04823, 0.01566, 0.83777)
2343
+ );
2344
+ const mat3 acesOutput = mat3(
2345
+ vec3(1.60475, -0.10208, -0.00327),
2346
+ vec3(-0.53108, 1.10813, -0.07276),
2347
+ vec3(-0.07367, -0.00605, 1.07602)
2348
+ );
2349
+ vec3 acesColor = acesInput * (color / 0.6);
2350
+ acesColor = acesRrtAndOdtFit(acesColor);
2351
+ return clamp(acesOutput * acesColor, 0.0, 1.0);
2243
2352
  }
2244
2353
 
2245
2354
  float filmic(float value) {
@@ -2279,7 +2388,7 @@ float toneMapChannel(float value) {
2279
2388
  float exposed = max(0.0, value * u_exposure) / max(0.0001, u_whitePoint);
2280
2389
  if (u_toneOperator == 0) return min(1.0, exposed);
2281
2390
  if (u_toneOperator == 1) return exposed / (1.0 + exposed);
2282
- if (u_toneOperator == 2) return aces(exposed);
2391
+ if (u_toneOperator == 2) return exposed;
2283
2392
  if (u_toneOperator == 3) return filmic(exposed);
2284
2393
  if (u_toneOperator == 4) return uncharted2(exposed);
2285
2394
  if (u_toneOperator == 5) return agx(exposed);
@@ -2289,7 +2398,9 @@ float toneMapChannel(float value) {
2289
2398
  vec3 applyToneMapping(vec3 color) {
2290
2399
  if (u_hasToneMapping == 0) return color;
2291
2400
  vec3 decoded = decodeColor(color);
2292
- vec3 mapped = vec3(toneMapChannel(decoded.r), toneMapChannel(decoded.g), toneMapChannel(decoded.b));
2401
+ vec3 mapped = u_toneOperator == 2
2402
+ ? acesFilmic(max(vec3(0.0), decoded * u_exposure) / max(0.0001, u_whitePoint))
2403
+ : vec3(toneMapChannel(decoded.r), toneMapChannel(decoded.g), toneMapChannel(decoded.b));
2293
2404
  return encodeColor(mapped);
2294
2405
  }
2295
2406
 
@@ -2422,7 +2533,7 @@ void main() {
2422
2533
  if (location === null) {
2423
2534
  throw new RenderDeviceError("Material tried to bind a missing shader uniform", "MISSING_UNIFORM", { name });
2424
2535
  }
2425
- if (value instanceof TextureBinding) {
2536
+ if (isTextureBinding(value)) {
2426
2537
  this.uploadTextureUniform(location, value, textureUnit);
2427
2538
  textureUnit += 1;
2428
2539
  }