topazcube 0.1.30 → 0.1.33

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 (96) hide show
  1. package/LICENSE.txt +0 -0
  2. package/README.md +0 -0
  3. package/dist/Renderer.cjs +18200 -0
  4. package/dist/Renderer.cjs.map +1 -0
  5. package/dist/Renderer.js +18183 -0
  6. package/dist/Renderer.js.map +1 -0
  7. package/dist/client.cjs +94 -260
  8. package/dist/client.cjs.map +1 -1
  9. package/dist/client.js +71 -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} +173 -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 +572 -0
  33. package/src/renderer/Geometry.js +1049 -0
  34. package/src/renderer/Material.js +61 -0
  35. package/src/renderer/Mesh.js +211 -0
  36. package/src/renderer/Node.js +112 -0
  37. package/src/renderer/Pipeline.js +643 -0
  38. package/src/renderer/Renderer.js +1324 -0
  39. package/src/renderer/Skin.js +792 -0
  40. package/src/renderer/Texture.js +584 -0
  41. package/src/renderer/core/AssetManager.js +359 -0
  42. package/src/renderer/core/CullingSystem.js +307 -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 +546 -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 +2064 -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 +417 -0
  58. package/src/renderer/rendering/passes/FogPass.js +419 -0
  59. package/src/renderer/rendering/passes/GBufferPass.js +706 -0
  60. package/src/renderer/rendering/passes/HiZPass.js +714 -0
  61. package/src/renderer/rendering/passes/LightingPass.js +739 -0
  62. package/src/renderer/rendering/passes/ParticlePass.js +835 -0
  63. package/src/renderer/rendering/passes/PlanarReflectionPass.js +456 -0
  64. package/src/renderer/rendering/passes/PostProcessPass.js +282 -0
  65. package/src/renderer/rendering/passes/ReflectionPass.js +157 -0
  66. package/src/renderer/rendering/passes/RenderPostPass.js +364 -0
  67. package/src/renderer/rendering/passes/SSGIPass.js +265 -0
  68. package/src/renderer/rendering/passes/SSGITilePass.js +296 -0
  69. package/src/renderer/rendering/passes/ShadowPass.js +1822 -0
  70. package/src/renderer/rendering/passes/TransparentPass.js +831 -0
  71. package/src/renderer/rendering/shaders/ao.wgsl +182 -0
  72. package/src/renderer/rendering/shaders/bloom.wgsl +97 -0
  73. package/src/renderer/rendering/shaders/bloom_blur.wgsl +80 -0
  74. package/src/renderer/rendering/shaders/depth_copy.wgsl +17 -0
  75. package/src/renderer/rendering/shaders/geometry.wgsl +550 -0
  76. package/src/renderer/rendering/shaders/hiz_reduce.wgsl +114 -0
  77. package/src/renderer/rendering/shaders/light_culling.wgsl +204 -0
  78. package/src/renderer/rendering/shaders/lighting.wgsl +932 -0
  79. package/src/renderer/rendering/shaders/lighting_common.wgsl +143 -0
  80. package/src/renderer/rendering/shaders/particle_render.wgsl +525 -0
  81. package/src/renderer/rendering/shaders/particle_simulate.wgsl +440 -0
  82. package/src/renderer/rendering/shaders/postproc.wgsl +272 -0
  83. package/src/renderer/rendering/shaders/render_post.wgsl +289 -0
  84. package/src/renderer/rendering/shaders/shadow.wgsl +76 -0
  85. package/src/renderer/rendering/shaders/ssgi.wgsl +266 -0
  86. package/src/renderer/rendering/shaders/ssgi_accumulate.wgsl +114 -0
  87. package/src/renderer/rendering/shaders/ssgi_propagate.wgsl +132 -0
  88. package/src/renderer/utils/BoundingSphere.js +439 -0
  89. package/src/renderer/utils/Frustum.js +281 -0
  90. package/dist/client.d.cts +0 -211
  91. package/dist/client.d.ts +0 -211
  92. package/dist/server.d.cts +0 -120
  93. package/dist/server.d.ts +0 -120
  94. package/dist/terminal.d.cts +0 -64
  95. package/dist/terminal.d.ts +0 -64
  96. package/src/utils.ts +0 -403
@@ -0,0 +1,282 @@
1
+ import { BasePass } from "./BasePass.js"
2
+ import { Pipeline } from "../../Pipeline.js"
3
+
4
+ import postProcessingWGSL from "../shaders/postproc.wgsl"
5
+
6
+ /**
7
+ * PostProcessPass - Final post-processing and tone mapping
8
+ *
9
+ * Pass 7 in the 7-pass pipeline (final pass).
10
+ * Applies tone mapping and outputs to the canvas.
11
+ *
12
+ * Input: HDR lit image from LightingPass
13
+ * Output: Final SDR image to canvas
14
+ */
15
+ class PostProcessPass extends BasePass {
16
+ constructor(engine = null) {
17
+ super('PostProcess', engine)
18
+
19
+ this.pipeline = null
20
+ this.inputTexture = null
21
+ this.bloomTexture = null
22
+ this.dummyBloomTexture = null // 1x1 black texture when bloom disabled
23
+ this.noiseTexture = null
24
+ this.noiseSize = 64
25
+ this.noiseAnimated = true
26
+ this.guiCanvas = null // 2D canvas for GUI overlay
27
+ this.guiTexture = null // GPU texture for GUI
28
+ this.guiSampler = null
29
+ }
30
+
31
+ // Convenience getter for exposure setting
32
+ get exposure() { return this.settings?.environment?.exposure ?? 1.6 }
33
+
34
+ // Convenience getter for fxaa setting
35
+ get fxaa() { return this.settings?.rendering?.fxaa ?? true }
36
+
37
+ // Convenience getter for dithering settings
38
+ get ditheringEnabled() { return this.settings?.dithering?.enabled ?? true }
39
+ get colorLevels() { return this.settings?.dithering?.colorLevels ?? 32 }
40
+
41
+ // Convenience getters for bloom settings
42
+ get bloomEnabled() { return this.settings?.bloom?.enabled ?? true }
43
+ get bloomIntensity() { return this.settings?.bloom?.intensity ?? 1.0 }
44
+ get bloomRadius() { return this.settings?.bloom?.radius ?? 5 }
45
+
46
+ /**
47
+ * Set the input texture (HDR image from LightingPass)
48
+ * @param {Texture} texture - Input HDR texture
49
+ */
50
+ setInputTexture(texture) {
51
+ if (this.inputTexture !== texture) {
52
+ this.inputTexture = texture
53
+ this._needsRebuild = true
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Set the bloom texture (from BloomPass)
59
+ * @param {Object} bloomTexture - Bloom texture with mip levels
60
+ */
61
+ setBloomTexture(bloomTexture) {
62
+ if (this.bloomTexture !== bloomTexture) {
63
+ this.bloomTexture = bloomTexture
64
+ this._needsRebuild = true
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Set the noise texture for dithering
70
+ * @param {Texture} texture - Noise texture (blue noise or bayer dither)
71
+ * @param {number} size - Texture size
72
+ * @param {boolean} animated - Whether to animate noise offset each frame
73
+ */
74
+ setNoise(texture, size = 64, animated = true) {
75
+ this.noiseTexture = texture
76
+ this.noiseSize = size
77
+ this.noiseAnimated = animated
78
+ this._needsRebuild = true
79
+ }
80
+
81
+ /**
82
+ * Set the GUI canvas for overlay rendering
83
+ * @param {HTMLCanvasElement} canvas - 2D canvas with GUI content
84
+ */
85
+ setGuiCanvas(canvas) {
86
+ this.guiCanvas = canvas
87
+ }
88
+
89
+ async _init() {
90
+ // Create dummy 1x1 black bloom texture for when bloom is disabled
91
+ // This ensures shader bindings are always valid
92
+ const { device } = this.engine
93
+
94
+ const dummyTexture = device.createTexture({
95
+ label: 'Dummy Bloom Texture',
96
+ size: [1, 1, 1],
97
+ format: 'rgba16float',
98
+ mipLevelCount: 1,
99
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
100
+ })
101
+
102
+ // Fill with black (no bloom)
103
+ device.queue.writeTexture(
104
+ { texture: dummyTexture },
105
+ new Float32Array([0, 0, 0, 0]).buffer,
106
+ { bytesPerRow: 8 },
107
+ { width: 1, height: 1 }
108
+ )
109
+
110
+ const dummySampler = device.createSampler({
111
+ label: 'Dummy Bloom Sampler',
112
+ minFilter: 'linear',
113
+ magFilter: 'linear',
114
+ })
115
+
116
+ this.dummyBloomTexture = {
117
+ texture: dummyTexture,
118
+ view: dummyTexture.createView(),
119
+ sampler: dummySampler,
120
+ mipCount: 1,
121
+ }
122
+
123
+ // Create sampler for GUI texture
124
+ this.guiSampler = device.createSampler({
125
+ label: 'GUI Sampler',
126
+ minFilter: 'linear',
127
+ magFilter: 'linear',
128
+ })
129
+
130
+ // Create dummy 1x1 transparent GUI texture
131
+ const dummyGuiTexture = device.createTexture({
132
+ label: 'Dummy GUI Texture',
133
+ size: [1, 1, 1],
134
+ format: 'rgba8unorm',
135
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
136
+ })
137
+ device.queue.writeTexture(
138
+ { texture: dummyGuiTexture },
139
+ new Uint8Array([0, 0, 0, 0]),
140
+ { bytesPerRow: 4 },
141
+ { width: 1, height: 1 }
142
+ )
143
+ this.dummyGuiTexture = {
144
+ texture: dummyGuiTexture,
145
+ view: dummyGuiTexture.createView(),
146
+ sampler: this.guiSampler,
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Build or rebuild the pipeline
152
+ */
153
+ async _buildPipeline() {
154
+ if (!this.inputTexture) {
155
+ return
156
+ }
157
+
158
+ const textures = [this.inputTexture]
159
+ if (this.noiseTexture) {
160
+ textures.push(this.noiseTexture)
161
+ }
162
+ // Always include bloom texture (real or dummy) so shader bindings are valid
163
+ const effectiveBloomTexture = this.bloomTexture || this.dummyBloomTexture
164
+ textures.push(effectiveBloomTexture)
165
+
166
+ // Always include GUI texture (real or dummy) so shader bindings are valid
167
+ const effectiveGuiTexture = this.guiTexture || this.dummyGuiTexture
168
+ textures.push(effectiveGuiTexture)
169
+
170
+ const hasBloom = this.bloomTexture && this.bloomEnabled
171
+
172
+ this.pipeline = await Pipeline.create(this.engine, {
173
+ label: 'postProcess',
174
+ wgslSource: postProcessingWGSL,
175
+ isPostProcessing: true,
176
+ textures: textures,
177
+ uniforms: () => ({
178
+ noiseParams: [this.noiseSize, this.noiseAnimated ? Math.random() : 0, this.noiseAnimated ? Math.random() : 0, this.fxaa ? 1.0 : 0.0],
179
+ ditherParams: [this.ditheringEnabled ? 1.0 : 0.0, this.colorLevels, 0, 0],
180
+ bloomParams: [hasBloom ? 1.0 : 0.0, this.bloomIntensity, this.bloomRadius, effectiveBloomTexture?.mipCount ?? 1]
181
+ }),
182
+ // No renderTarget = output to canvas
183
+ })
184
+
185
+ this._needsRebuild = false
186
+ }
187
+
188
+ async _execute(context) {
189
+ const { device } = this.engine
190
+
191
+ // Update GUI texture from canvas if available
192
+ if (this.guiCanvas && this.guiCanvas.width > 0 && this.guiCanvas.height > 0) {
193
+ // Check if we need to recreate the texture (size changed)
194
+ const needsNewTexture = !this.guiTexture ||
195
+ this.guiTexture.width !== this.guiCanvas.width ||
196
+ this.guiTexture.height !== this.guiCanvas.height
197
+
198
+ if (needsNewTexture) {
199
+ // Destroy old texture if it exists
200
+ if (this.guiTexture?.texture) {
201
+ this.guiTexture.texture.destroy()
202
+ }
203
+
204
+ // Create new texture matching canvas size
205
+ const texture = device.createTexture({
206
+ label: 'GUI Texture',
207
+ size: [this.guiCanvas.width, this.guiCanvas.height, 1],
208
+ format: 'rgba8unorm',
209
+ usage: GPUTextureUsage.TEXTURE_BINDING |
210
+ GPUTextureUsage.COPY_DST |
211
+ GPUTextureUsage.RENDER_ATTACHMENT,
212
+ })
213
+
214
+ this.guiTexture = {
215
+ texture: texture,
216
+ view: texture.createView(),
217
+ sampler: this.guiSampler,
218
+ width: this.guiCanvas.width,
219
+ height: this.guiCanvas.height,
220
+ }
221
+
222
+ // Force pipeline rebuild to use new texture
223
+ this._needsRebuild = true
224
+ }
225
+
226
+ // Copy canvas content to GPU texture
227
+ device.queue.copyExternalImageToTexture(
228
+ { source: this.guiCanvas },
229
+ { texture: this.guiTexture.texture },
230
+ [this.guiCanvas.width, this.guiCanvas.height]
231
+ )
232
+ }
233
+
234
+ // Rebuild pipeline if needed
235
+ if (this._needsRebuild) {
236
+ await this._buildPipeline()
237
+ }
238
+
239
+ // If rebuild was attempted but failed, don't use stale pipeline with old bind groups
240
+ if (!this.pipeline || this._needsRebuild) {
241
+ console.warn('PostProcessPass: Pipeline not ready')
242
+ return
243
+ }
244
+
245
+ // Determine if bloom is effectively enabled
246
+ const hasBloom = this.bloomTexture && this.bloomEnabled
247
+ const effectiveBloomTexture = this.bloomTexture || this.dummyBloomTexture
248
+
249
+ // Update uniforms each frame
250
+ this.pipeline.uniformValues.set({
251
+ noiseParams: [this.noiseSize, this.noiseAnimated ? Math.random() : 0, this.noiseAnimated ? Math.random() : 0, this.fxaa ? 1.0 : 0.0],
252
+ ditherParams: [this.ditheringEnabled ? 1.0 : 0.0, this.colorLevels, 0, 0],
253
+ bloomParams: [hasBloom ? 1.0 : 0.0, this.bloomIntensity, this.bloomRadius, effectiveBloomTexture?.mipCount ?? 1]
254
+ })
255
+
256
+ // Render to canvas
257
+ this.pipeline.render()
258
+ }
259
+
260
+ async _resize(width, height) {
261
+ // Pipeline needs rebuild since canvas size changed
262
+ this._needsRebuild = true
263
+ }
264
+
265
+ _destroy() {
266
+ this.pipeline = null
267
+ if (this.dummyBloomTexture?.texture) {
268
+ this.dummyBloomTexture.texture.destroy()
269
+ this.dummyBloomTexture = null
270
+ }
271
+ if (this.guiTexture?.texture) {
272
+ this.guiTexture.texture.destroy()
273
+ this.guiTexture = null
274
+ }
275
+ if (this.dummyGuiTexture?.texture) {
276
+ this.dummyGuiTexture.texture.destroy()
277
+ this.dummyGuiTexture = null
278
+ }
279
+ }
280
+ }
281
+
282
+ export { PostProcessPass }
@@ -0,0 +1,157 @@
1
+ import { BasePass } from "./BasePass.js"
2
+ import { Texture } from "../../Texture.js"
3
+ import { ProbeCapture } from "../ProbeCapture.js"
4
+ import { ReflectionProbeManager } from "../ReflectionProbeManager.js"
5
+
6
+ /**
7
+ * ReflectionPass - Manages reflection probes and environment lighting
8
+ *
9
+ * Pass 2 in the 7-pass pipeline.
10
+ * Handles:
11
+ * - Loading/managing reflection probes
12
+ * - Real-time probe capture (when triggered)
13
+ * - Probe interpolation based on camera position
14
+ *
15
+ * Configuration:
16
+ * - 1024x1024 octahedral HDR texture per probe
17
+ * - Interpolates between closest 2 probes
18
+ */
19
+ class ReflectionPass extends BasePass {
20
+ constructor(engine = null) {
21
+ super('Reflection', engine)
22
+
23
+ // Probe capture system
24
+ this.probeCapture = null
25
+
26
+ // Probe manager for loading/interpolating
27
+ this.probeManager = null
28
+
29
+ // Current world ID
30
+ this.currentWorldId = 'default'
31
+
32
+ // Capture request queue
33
+ this.captureRequests = []
34
+
35
+ // Output: combined/interpolated probe texture
36
+ this.outputTexture = null
37
+ }
38
+
39
+ async _init() {
40
+ // Initialize probe manager (lightweight, always works)
41
+ this.probeManager = new ReflectionProbeManager(this.engine)
42
+
43
+ // Initialize probe capture system (can fail on some systems)
44
+ try {
45
+ this.probeCapture = new ProbeCapture(this.engine)
46
+ await this.probeCapture.initialize()
47
+ } catch (e) {
48
+ console.warn('ReflectionPass: Probe capture initialization failed:', e)
49
+ this.probeCapture = null
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Set fallback environment map (used when no probes available)
55
+ * @param {Texture} envMap - Environment map texture
56
+ * @param {number} encoding - 0 = equirectangular, 1 = octahedral
57
+ */
58
+ setFallbackEnvironment(envMap, encoding = 0) {
59
+ if (this.probeManager) {
60
+ this.probeManager.setFallbackEnvironment(envMap)
61
+ }
62
+ if (this.probeCapture) {
63
+ this.probeCapture.setFallbackEnvironment(envMap)
64
+ this.probeCapture.envEncoding = encoding
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Load probes for a world
70
+ */
71
+ async loadWorldProbes(worldId) {
72
+ this.currentWorldId = worldId
73
+ if (this.probeManager) {
74
+ await this.probeManager.loadWorldProbes(worldId)
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Request a probe capture at position
80
+ * Will be processed during next execute()
81
+ */
82
+ requestCapture(position, worldId = null) {
83
+ this.captureRequests.push({
84
+ position: [...position],
85
+ worldId: worldId || this.currentWorldId
86
+ })
87
+ }
88
+
89
+ /**
90
+ * Load a specific probe from URL
91
+ */
92
+ async loadProbe(url, position, worldId = null) {
93
+ if (this.probeManager) {
94
+ return await this.probeManager.loadProbe(url, position, worldId || this.currentWorldId)
95
+ }
96
+ return null
97
+ }
98
+
99
+ async _execute(context) {
100
+ const { camera } = context
101
+
102
+ // Update active probes based on camera position
103
+ if (this.probeManager && camera) {
104
+ this.probeManager.updateActiveProbes(camera.position, this.currentWorldId)
105
+ }
106
+
107
+ // Process capture requests (one per frame max)
108
+ if (this.captureRequests.length > 0 && !this.probeCapture?.isCapturing) {
109
+ const request = this.captureRequests.shift()
110
+ // Capture would happen here - requires renderGraph reference
111
+ // For now, log the request
112
+ console.log(`ReflectionPass: Capture requested at [${request.position.join(', ')}]`)
113
+ }
114
+ }
115
+
116
+ async _resize(width, height) {
117
+ // Reflection maps are fixed size, doesn't resize with screen
118
+ }
119
+
120
+ _destroy() {
121
+ if (this.probeCapture) {
122
+ this.probeCapture.destroy()
123
+ }
124
+ if (this.probeManager) {
125
+ this.probeManager.destroy()
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Get probe manager for external access
131
+ */
132
+ getProbeManager() {
133
+ return this.probeManager
134
+ }
135
+
136
+ /**
137
+ * Get probe capture system for manual triggering
138
+ */
139
+ getProbeCapture() {
140
+ return this.probeCapture
141
+ }
142
+
143
+ /**
144
+ * Get active probe data for lighting pass
145
+ */
146
+ getActiveProbeData() {
147
+ if (this.probeManager) {
148
+ return this.probeManager.getActiveProbeData()
149
+ }
150
+ return {
151
+ textures: [null, null],
152
+ weights: [1.0, 0.0]
153
+ }
154
+ }
155
+ }
156
+
157
+ export { ReflectionPass }