topazcube 0.1.31 → 0.1.35

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 (103) hide show
  1. package/LICENSE.txt +0 -0
  2. package/README.md +0 -0
  3. package/dist/Renderer.cjs +20844 -0
  4. package/dist/Renderer.cjs.map +1 -0
  5. package/dist/Renderer.js +20827 -0
  6. package/dist/Renderer.js.map +1 -0
  7. package/dist/client.cjs +91 -260
  8. package/dist/client.cjs.map +1 -1
  9. package/dist/client.js +68 -215
  10. package/dist/client.js.map +1 -1
  11. package/dist/server.cjs +165 -432
  12. package/dist/server.cjs.map +1 -1
  13. package/dist/server.js +117 -370
  14. package/dist/server.js.map +1 -1
  15. package/dist/terminal.cjs +113 -200
  16. package/dist/terminal.cjs.map +1 -1
  17. package/dist/terminal.js +50 -51
  18. package/dist/terminal.js.map +1 -1
  19. package/dist/utils-CRhi1BDa.cjs +259 -0
  20. package/dist/utils-CRhi1BDa.cjs.map +1 -0
  21. package/dist/utils-D7tXt6-2.js +260 -0
  22. package/dist/utils-D7tXt6-2.js.map +1 -0
  23. package/package.json +19 -15
  24. package/src/{client.ts → network/client.js} +170 -403
  25. package/src/{compress-browser.ts → network/compress-browser.js} +2 -4
  26. package/src/{compress-node.ts → network/compress-node.js} +8 -14
  27. package/src/{server.ts → network/server.js} +229 -317
  28. package/src/{terminal.js → network/terminal.js} +0 -0
  29. package/src/{topazcube.ts → network/topazcube.js} +2 -2
  30. package/src/network/utils.js +375 -0
  31. package/src/renderer/Camera.js +191 -0
  32. package/src/renderer/DebugUI.js +703 -0
  33. package/src/renderer/Geometry.js +1049 -0
  34. package/src/renderer/Material.js +64 -0
  35. package/src/renderer/Mesh.js +211 -0
  36. package/src/renderer/Node.js +112 -0
  37. package/src/renderer/Pipeline.js +645 -0
  38. package/src/renderer/Renderer.js +1496 -0
  39. package/src/renderer/Skin.js +792 -0
  40. package/src/renderer/Texture.js +584 -0
  41. package/src/renderer/core/AssetManager.js +394 -0
  42. package/src/renderer/core/CullingSystem.js +308 -0
  43. package/src/renderer/core/EntityManager.js +541 -0
  44. package/src/renderer/core/InstanceManager.js +343 -0
  45. package/src/renderer/core/ParticleEmitter.js +358 -0
  46. package/src/renderer/core/ParticleSystem.js +564 -0
  47. package/src/renderer/core/SpriteSystem.js +349 -0
  48. package/src/renderer/gltf.js +563 -0
  49. package/src/renderer/math.js +161 -0
  50. package/src/renderer/rendering/HistoryBufferManager.js +333 -0
  51. package/src/renderer/rendering/ProbeCapture.js +1495 -0
  52. package/src/renderer/rendering/ReflectionProbeManager.js +352 -0
  53. package/src/renderer/rendering/RenderGraph.js +2258 -0
  54. package/src/renderer/rendering/passes/AOPass.js +308 -0
  55. package/src/renderer/rendering/passes/AmbientCapturePass.js +593 -0
  56. package/src/renderer/rendering/passes/BasePass.js +101 -0
  57. package/src/renderer/rendering/passes/BloomPass.js +420 -0
  58. package/src/renderer/rendering/passes/CRTPass.js +724 -0
  59. package/src/renderer/rendering/passes/FogPass.js +445 -0
  60. package/src/renderer/rendering/passes/GBufferPass.js +730 -0
  61. package/src/renderer/rendering/passes/HiZPass.js +744 -0
  62. package/src/renderer/rendering/passes/LightingPass.js +753 -0
  63. package/src/renderer/rendering/passes/ParticlePass.js +841 -0
  64. package/src/renderer/rendering/passes/PlanarReflectionPass.js +456 -0
  65. package/src/renderer/rendering/passes/PostProcessPass.js +405 -0
  66. package/src/renderer/rendering/passes/ReflectionPass.js +157 -0
  67. package/src/renderer/rendering/passes/RenderPostPass.js +364 -0
  68. package/src/renderer/rendering/passes/SSGIPass.js +266 -0
  69. package/src/renderer/rendering/passes/SSGITilePass.js +305 -0
  70. package/src/renderer/rendering/passes/ShadowPass.js +2072 -0
  71. package/src/renderer/rendering/passes/TransparentPass.js +831 -0
  72. package/src/renderer/rendering/passes/VolumetricFogPass.js +715 -0
  73. package/src/renderer/rendering/shaders/ao.wgsl +182 -0
  74. package/src/renderer/rendering/shaders/bloom.wgsl +97 -0
  75. package/src/renderer/rendering/shaders/bloom_blur.wgsl +80 -0
  76. package/src/renderer/rendering/shaders/crt.wgsl +455 -0
  77. package/src/renderer/rendering/shaders/depth_copy.wgsl +17 -0
  78. package/src/renderer/rendering/shaders/geometry.wgsl +580 -0
  79. package/src/renderer/rendering/shaders/hiz_reduce.wgsl +114 -0
  80. package/src/renderer/rendering/shaders/light_culling.wgsl +204 -0
  81. package/src/renderer/rendering/shaders/lighting.wgsl +932 -0
  82. package/src/renderer/rendering/shaders/lighting_common.wgsl +143 -0
  83. package/src/renderer/rendering/shaders/particle_render.wgsl +672 -0
  84. package/src/renderer/rendering/shaders/particle_simulate.wgsl +440 -0
  85. package/src/renderer/rendering/shaders/postproc.wgsl +293 -0
  86. package/src/renderer/rendering/shaders/render_post.wgsl +289 -0
  87. package/src/renderer/rendering/shaders/shadow.wgsl +117 -0
  88. package/src/renderer/rendering/shaders/ssgi.wgsl +266 -0
  89. package/src/renderer/rendering/shaders/ssgi_accumulate.wgsl +114 -0
  90. package/src/renderer/rendering/shaders/ssgi_propagate.wgsl +132 -0
  91. package/src/renderer/rendering/shaders/volumetric_blur.wgsl +80 -0
  92. package/src/renderer/rendering/shaders/volumetric_composite.wgsl +80 -0
  93. package/src/renderer/rendering/shaders/volumetric_raymarch.wgsl +634 -0
  94. package/src/renderer/utils/BoundingSphere.js +439 -0
  95. package/src/renderer/utils/Frustum.js +281 -0
  96. package/src/renderer/utils/Raycaster.js +761 -0
  97. package/dist/client.d.cts +0 -211
  98. package/dist/client.d.ts +0 -211
  99. package/dist/server.d.cts +0 -120
  100. package/dist/server.d.ts +0 -120
  101. package/dist/terminal.d.cts +0 -64
  102. package/dist/terminal.d.ts +0 -64
  103. package/src/utils.ts +0 -403
@@ -0,0 +1,420 @@
1
+ import { BasePass } from "./BasePass.js"
2
+
3
+ import bloomExtractWGSL from "../shaders/bloom.wgsl"
4
+ import bloomBlurWGSL from "../shaders/bloom_blur.wgsl"
5
+
6
+ /**
7
+ * BloomPass - HDR Bloom/Glare effect
8
+ *
9
+ * Extracts bright pixels with exponential falloff and applies
10
+ * two-pass diagonal Gaussian blur for X-shaped glare effect.
11
+ *
12
+ * Input: HDR lighting output
13
+ * Output: Blurred bloom texture with X-shaped glare
14
+ */
15
+ class BloomPass extends BasePass {
16
+ constructor(engine = null) {
17
+ super('Bloom', engine)
18
+
19
+ // Pipelines
20
+ this.extractPipeline = null
21
+ this.blurPipeline = null
22
+
23
+ // Textures (ping-pong for blur)
24
+ this.brightTexture = null // Extracted bright pixels
25
+ this.blurTextureA = null // After horizontal blur
26
+ this.blurTextureB = null // After vertical blur (final output)
27
+
28
+ // Resources
29
+ this.inputTexture = null
30
+ this.extractUniformBuffer = null
31
+ this.blurUniformBufferH = null // Horizontal blur uniforms
32
+ this.blurUniformBufferV = null // Vertical blur uniforms
33
+ this.extractBindGroup = null
34
+ this.blurBindGroupH = null // Horizontal blur
35
+ this.blurBindGroupV = null // Vertical blur
36
+ this.sampler = null
37
+
38
+ // Textures pending destruction (wait for GPU to finish using them)
39
+ // Use a ring buffer of 3 frames to ensure GPU is definitely done
40
+ this._pendingDestroyRing = [[], [], []]
41
+ this._pendingDestroyIndex = 0
42
+
43
+ // Render dimensions (may differ from canvas when effect scaling is applied)
44
+ this.width = 0
45
+ this.height = 0
46
+ // Bloom internal resolution (scaled down for performance)
47
+ this.bloomWidth = 0
48
+ this.bloomHeight = 0
49
+ }
50
+
51
+ // Convenience getters for bloom settings
52
+ get bloomEnabled() { return this.settings?.bloom?.enabled ?? true }
53
+ get intensity() { return this.settings?.bloom?.intensity ?? 1.0 }
54
+ get threshold() { return this.settings?.bloom?.threshold ?? 0.8 }
55
+ get softThreshold() { return this.settings?.bloom?.softThreshold ?? 0.5 }
56
+ get radius() { return this.settings?.bloom?.radius ?? 32 }
57
+ get emissiveBoost() { return this.settings?.bloom?.emissiveBoost ?? 2.0 }
58
+ get maxBrightness() { return this.settings?.bloom?.maxBrightness ?? 4.0 }
59
+ get renderScale() { return this.settings?.rendering?.renderScale ?? 1.0 }
60
+ // Bloom resolution scale - 0.5 = half res (faster), 1.0 = full res (quality)
61
+ get bloomScale() { return this.settings?.bloom?.scale ?? 0.5 }
62
+
63
+ /**
64
+ * Set the input texture (HDR lighting output)
65
+ * @param {Object} texture - Input texture with view property
66
+ */
67
+ setInputTexture(texture) {
68
+ // Only rebuild if the texture actually changed
69
+ if (this.inputTexture !== texture) {
70
+ this.inputTexture = texture
71
+ this._needsRebuild = true
72
+ }
73
+ }
74
+
75
+ async _init() {
76
+ const { device } = this.engine
77
+
78
+ // Create sampler for all bloom textures
79
+ this.sampler = device.createSampler({
80
+ label: 'Bloom Sampler',
81
+ minFilter: 'linear',
82
+ magFilter: 'linear',
83
+ addressModeU: 'clamp-to-edge',
84
+ addressModeV: 'clamp-to-edge',
85
+ })
86
+ }
87
+
88
+ /**
89
+ * Create or recreate bloom textures at scaled resolution
90
+ */
91
+ _createTextures(width, height) {
92
+ const { device } = this.engine
93
+
94
+ // Queue old textures for deferred destruction (GPU may still be using them)
95
+ // Add to current slot in ring buffer - will be destroyed 3 frames later
96
+ const slot = this._pendingDestroyRing[this._pendingDestroyIndex]
97
+ if (this.brightTexture?.texture) slot.push(this.brightTexture.texture)
98
+ if (this.blurTextureA?.texture) slot.push(this.blurTextureA.texture)
99
+ if (this.blurTextureB?.texture) slot.push(this.blurTextureB.texture)
100
+
101
+ // Calculate scaled resolution for bloom (0.5 = half res for performance)
102
+ // Bloom is blurry anyway, so half-res is usually sufficient
103
+ const scale = this.bloomScale
104
+ const bloomWidth = Math.max(1, Math.floor(width * scale))
105
+ const bloomHeight = Math.max(1, Math.floor(height * scale))
106
+
107
+ // Only log if dimensions actually changed
108
+ if (this.bloomWidth !== bloomWidth || this.bloomHeight !== bloomHeight) {
109
+ console.log(`Bloom: ${width}x${height} -> ${bloomWidth}x${bloomHeight} (scale: ${scale})`)
110
+ }
111
+
112
+ this.bloomWidth = bloomWidth
113
+ this.bloomHeight = bloomHeight
114
+
115
+ // Create textures at scaled resolution
116
+ const createBloomTexture = (label) => {
117
+ const texture = device.createTexture({
118
+ label,
119
+ size: { width: bloomWidth, height: bloomHeight, depthOrArrayLayers: 1 },
120
+ format: 'rgba16float',
121
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
122
+ })
123
+ return {
124
+ texture,
125
+ view: texture.createView({ label: `${label} View` }),
126
+ sampler: this.sampler,
127
+ width: bloomWidth,
128
+ height: bloomHeight,
129
+ }
130
+ }
131
+
132
+ this.brightTexture = createBloomTexture('Bloom Bright')
133
+ this.blurTextureA = createBloomTexture('Bloom Blur A')
134
+ this.blurTextureB = createBloomTexture('Bloom Blur B')
135
+ }
136
+
137
+ async _buildPipeline() {
138
+ if (!this.inputTexture) {
139
+ return
140
+ }
141
+
142
+ const { device, canvas } = this.engine
143
+ // Store initial dimensions (may be updated by resize)
144
+ this.width = canvas.width
145
+ this.height = canvas.height
146
+
147
+ // Create bloom textures
148
+ this._createTextures(this.width, this.height)
149
+
150
+ // Create uniform buffers
151
+ this.extractUniformBuffer = device.createBuffer({
152
+ label: 'Bloom Extract Uniforms',
153
+ size: 32, // 5 floats + padding for 16-byte alignment
154
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
155
+ })
156
+
157
+ this.blurUniformBufferH = device.createBuffer({
158
+ label: 'Bloom Blur H Uniforms',
159
+ size: 32, // 8 floats (2 vec2 + 2 float + padding)
160
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
161
+ })
162
+
163
+ this.blurUniformBufferV = device.createBuffer({
164
+ label: 'Bloom Blur V Uniforms',
165
+ size: 32,
166
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
167
+ })
168
+
169
+ // ===== EXTRACT PIPELINE =====
170
+ const extractBGL = device.createBindGroupLayout({
171
+ label: 'Bloom Extract BGL',
172
+ entries: [
173
+ { binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },
174
+ { binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
175
+ { binding: 2, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
176
+ ],
177
+ })
178
+
179
+ const extractModule = device.createShaderModule({
180
+ label: 'Bloom Extract Shader',
181
+ code: bloomExtractWGSL,
182
+ })
183
+
184
+ // ===== BLUR PIPELINE =====
185
+ const blurBGL = device.createBindGroupLayout({
186
+ label: 'Bloom Blur BGL',
187
+ entries: [
188
+ { binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },
189
+ { binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
190
+ { binding: 2, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
191
+ ],
192
+ })
193
+
194
+ const blurModule = device.createShaderModule({
195
+ label: 'Bloom Blur Shader',
196
+ code: bloomBlurWGSL,
197
+ })
198
+
199
+ // Create both pipelines in parallel for faster initialization
200
+ const [extractPipeline, blurPipeline] = await Promise.all([
201
+ device.createRenderPipelineAsync({
202
+ label: 'Bloom Extract Pipeline',
203
+ layout: device.createPipelineLayout({ bindGroupLayouts: [extractBGL] }),
204
+ vertex: { module: extractModule, entryPoint: 'vertexMain' },
205
+ fragment: {
206
+ module: extractModule,
207
+ entryPoint: 'fragmentMain',
208
+ targets: [{ format: 'rgba16float' }],
209
+ },
210
+ primitive: { topology: 'triangle-list' },
211
+ }),
212
+ device.createRenderPipelineAsync({
213
+ label: 'Bloom Blur Pipeline',
214
+ layout: device.createPipelineLayout({ bindGroupLayouts: [blurBGL] }),
215
+ vertex: { module: blurModule, entryPoint: 'vertexMain' },
216
+ fragment: {
217
+ module: blurModule,
218
+ entryPoint: 'fragmentMain',
219
+ targets: [{ format: 'rgba16float' }],
220
+ },
221
+ primitive: { topology: 'triangle-list' },
222
+ })
223
+ ])
224
+
225
+ this.extractPipeline = extractPipeline
226
+ this.blurPipeline = blurPipeline
227
+
228
+ this.extractBindGroup = device.createBindGroup({
229
+ label: 'Bloom Extract Bind Group',
230
+ layout: extractBGL,
231
+ entries: [
232
+ { binding: 0, resource: { buffer: this.extractUniformBuffer } },
233
+ { binding: 1, resource: this.inputTexture.view },
234
+ { binding: 2, resource: this.sampler },
235
+ ],
236
+ })
237
+
238
+ // Horizontal blur: brightTexture -> blurTextureA
239
+ this.blurBindGroupH = device.createBindGroup({
240
+ label: 'Bloom Blur H Bind Group',
241
+ layout: blurBGL,
242
+ entries: [
243
+ { binding: 0, resource: { buffer: this.blurUniformBufferH } },
244
+ { binding: 1, resource: this.brightTexture.view },
245
+ { binding: 2, resource: this.sampler },
246
+ ],
247
+ })
248
+
249
+ // Vertical blur: blurTextureA -> blurTextureB
250
+ this.blurBindGroupV = device.createBindGroup({
251
+ label: 'Bloom Blur V Bind Group',
252
+ layout: blurBGL,
253
+ entries: [
254
+ { binding: 0, resource: { buffer: this.blurUniformBufferV } },
255
+ { binding: 1, resource: this.blurTextureA.view },
256
+ { binding: 2, resource: this.sampler },
257
+ ],
258
+ })
259
+
260
+ this._needsRebuild = false
261
+ }
262
+
263
+ async _execute(context) {
264
+ // Skip if bloom is disabled in settings
265
+ if (!this.bloomEnabled) {
266
+ return
267
+ }
268
+
269
+ const { device, canvas } = this.engine
270
+
271
+ // Rotate ring buffer and destroy textures from 3 frames ago
272
+ this._pendingDestroyIndex = (this._pendingDestroyIndex + 1) % 3
273
+ const toDestroy = this._pendingDestroyRing[this._pendingDestroyIndex]
274
+ for (const tex of toDestroy) {
275
+ tex.destroy()
276
+ }
277
+ this._pendingDestroyRing[this._pendingDestroyIndex] = []
278
+
279
+ // Rebuild pipeline if needed
280
+ if (this._needsRebuild) {
281
+ await this._buildPipeline()
282
+ }
283
+
284
+ // If rebuild was attempted but failed, don't use stale pipeline with old bind groups
285
+ if (!this.extractPipeline || !this.blurPipeline || !this.inputTexture || this._needsRebuild) {
286
+ return
287
+ }
288
+
289
+ // Use bloom-specific dimensions (may be scaled down for performance)
290
+ const bloomWidth = this.bloomWidth
291
+ const bloomHeight = this.bloomHeight
292
+
293
+ // Scale radius based on bloom height relative to 1080p (settings are authored for 1080p)
294
+ // Also scale by bloomScale since we're working at lower resolution
295
+ const heightScale = bloomHeight / 1080
296
+ const blurRadius = this.radius * this.renderScale * heightScale
297
+
298
+ // Update all uniforms BEFORE creating command encoder
299
+ // (writeBuffer is immediate, commands are batched)
300
+ device.queue.writeBuffer(this.extractUniformBuffer, 0, new Float32Array([
301
+ this.threshold,
302
+ this.softThreshold,
303
+ this.intensity,
304
+ this.emissiveBoost,
305
+ this.maxBrightness,
306
+ 0.0, 0.0, 0.0, // padding
307
+ ]))
308
+
309
+ // Diagonal blur uniforms (X-shaped glare)
310
+ const diag = 0.7071067811865476 // 1/sqrt(2)
311
+ device.queue.writeBuffer(this.blurUniformBufferH, 0, new Float32Array([
312
+ diag, diag, // direction (diagonal: top-left to bottom-right)
313
+ 1.0 / bloomWidth, 1.0 / bloomHeight, // texelSize (at bloom resolution)
314
+ blurRadius, 0.0, // blurRadius, padding
315
+ 0.0, 0.0, // more padding for alignment
316
+ ]))
317
+
318
+ // Second diagonal blur uniforms
319
+ device.queue.writeBuffer(this.blurUniformBufferV, 0, new Float32Array([
320
+ diag, -diag, // direction (diagonal: bottom-left to top-right)
321
+ 1.0 / bloomWidth, 1.0 / bloomHeight, // texelSize (at bloom resolution)
322
+ blurRadius, 0.0, // blurRadius, padding
323
+ 0.0, 0.0, // more padding for alignment
324
+ ]))
325
+
326
+ const commandEncoder = device.createCommandEncoder({ label: 'Bloom Pass' })
327
+
328
+ // ===== PASS 1: Extract bright pixels =====
329
+ {
330
+ const pass = commandEncoder.beginRenderPass({
331
+ label: 'Bloom Extract',
332
+ colorAttachments: [{
333
+ view: this.brightTexture.view,
334
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
335
+ loadOp: 'clear',
336
+ storeOp: 'store',
337
+ }],
338
+ })
339
+ pass.setPipeline(this.extractPipeline)
340
+ pass.setBindGroup(0, this.extractBindGroup)
341
+ pass.draw(3)
342
+ pass.end()
343
+ }
344
+
345
+ // ===== PASS 2: Diagonal blur (top-left to bottom-right) =====
346
+ {
347
+ const pass = commandEncoder.beginRenderPass({
348
+ label: 'Bloom Blur Diag1',
349
+ colorAttachments: [{
350
+ view: this.blurTextureA.view,
351
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
352
+ loadOp: 'clear',
353
+ storeOp: 'store',
354
+ }],
355
+ })
356
+ pass.setPipeline(this.blurPipeline)
357
+ pass.setBindGroup(0, this.blurBindGroupH)
358
+ pass.draw(3)
359
+ pass.end()
360
+ }
361
+
362
+ // ===== PASS 3: Diagonal blur (bottom-left to top-right) =====
363
+ {
364
+ const pass = commandEncoder.beginRenderPass({
365
+ label: 'Bloom Blur Diag2',
366
+ colorAttachments: [{
367
+ view: this.blurTextureB.view,
368
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
369
+ loadOp: 'clear',
370
+ storeOp: 'store',
371
+ }],
372
+ })
373
+ pass.setPipeline(this.blurPipeline)
374
+ pass.setBindGroup(0, this.blurBindGroupV)
375
+ pass.draw(3)
376
+ pass.end()
377
+ }
378
+
379
+ device.queue.submit([commandEncoder.finish()])
380
+ }
381
+
382
+ async _resize(width, height) {
383
+ this.width = width
384
+ this.height = height
385
+ this._needsRebuild = true
386
+ }
387
+
388
+ _destroy() {
389
+ if (this.brightTexture?.texture) this.brightTexture.texture.destroy()
390
+ if (this.blurTextureA?.texture) this.blurTextureA.texture.destroy()
391
+ if (this.blurTextureB?.texture) this.blurTextureB.texture.destroy()
392
+ // Clean up any pending textures in all ring buffer slots
393
+ for (const slot of this._pendingDestroyRing) {
394
+ for (const tex of slot) {
395
+ tex.destroy()
396
+ }
397
+ }
398
+ this._pendingDestroyRing = [[], [], []]
399
+ this.extractPipeline = null
400
+ this.blurPipeline = null
401
+ }
402
+
403
+ /**
404
+ * Get the final bloom texture (after blur)
405
+ */
406
+ getOutputTexture() {
407
+ return this.blurTextureB
408
+ }
409
+
410
+ /**
411
+ * Get the bright extraction texture (before blur)
412
+ * Used by SSGITilePass for directional light accumulation
413
+ */
414
+ getBrightTexture() {
415
+ return this.brightTexture
416
+ }
417
+ }
418
+
419
+
420
+ export { BloomPass }