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,308 @@
1
+ import { BasePass } from "./BasePass.js"
2
+ import { Texture } from "../../Texture.js"
3
+
4
+ import aoWGSL from "../shaders/ao.wgsl"
5
+
6
+ /**
7
+ * AOPass - Screen Space Ambient Occlusion
8
+ *
9
+ * Pass 5 in the 7-pass pipeline.
10
+ * Calculates ambient occlusion from depth and normal buffers.
11
+ *
12
+ * Features:
13
+ * - Cavity/corner darkening (traditional SSAO)
14
+ * - Normal-based darkening (plasticity for objects in shadow)
15
+ * - Blue noise jittered sampling
16
+ * - Reflectivity-based fade (reflective surfaces have no AO)
17
+ * - Distance fade (fades to 0 at configurable distance)
18
+ *
19
+ * Inputs: GBuffer (depth, normal, ARM)
20
+ * Output: AO texture (r8unorm - single channel)
21
+ */
22
+ class AOPass extends BasePass {
23
+ constructor(engine = null) {
24
+ super('AO', engine)
25
+
26
+ this.renderPipeline = null
27
+ this.outputTexture = null
28
+ this.gbuffer = null
29
+ this.noiseTexture = null
30
+ this.noiseSize = 128
31
+ this.noiseAnimated = true
32
+
33
+ // Render dimensions (may differ from canvas when effect scaling is applied)
34
+ this.width = 0
35
+ this.height = 0
36
+ }
37
+
38
+ // Convenience getters for AO settings (with defaults for backward compatibility)
39
+ get aoIntensity() { return this.settings?.ao?.intensity ?? 1.0 }
40
+ get aoRadius() {
41
+ // Scale radius by renderScale and height relative to 1080p
42
+ // Settings are authored for 1080p, so scale proportionally
43
+ const baseRadius = this.settings?.ao?.radius ?? 64.0
44
+ const renderScale = this.settings?.rendering?.renderScale ?? 1.0
45
+ const heightScale = this.height > 0 ? this.height / 1080 : 1.0
46
+ return baseRadius * renderScale * heightScale
47
+ }
48
+ get aoFadeDistance() { return this.settings?.ao?.fadeDistance ?? 40.0 }
49
+ get aoBias() { return this.settings?.ao?.bias ?? 0.005 }
50
+ get sampleCount() { return this.settings?.ao?.sampleCount ?? 16 }
51
+ get aoLevel() { return this.settings?.ao?.level ?? 0.5 }
52
+
53
+ /**
54
+ * Set the GBuffer from GBufferPass
55
+ * @param {GBuffer} gbuffer - GBuffer textures
56
+ */
57
+ async setGBuffer(gbuffer) {
58
+ this.gbuffer = gbuffer
59
+ this._needsRebuild = true
60
+ }
61
+
62
+ /**
63
+ * Set the noise texture for jittering
64
+ * @param {Texture} noise - Noise texture (blue noise or bayer dither)
65
+ * @param {number} size - Texture size
66
+ * @param {boolean} animated - Whether to animate noise offset each frame
67
+ */
68
+ setNoise(noise, size = 64, animated = true) {
69
+ this.noiseTexture = noise
70
+ this.noiseSize = size
71
+ this.noiseAnimated = animated
72
+ this._needsRebuild = true
73
+ }
74
+
75
+ async _init() {
76
+ // Create output texture (single channel AO)
77
+ this.outputTexture = await Texture.renderTarget(this.engine, 'r8unorm')
78
+ }
79
+
80
+ async _buildPipeline() {
81
+ if (!this.gbuffer) {
82
+ return
83
+ }
84
+
85
+ const { device } = this.engine
86
+
87
+ // Create bind group layout
88
+ const bglEntries = [
89
+ // Uniforms
90
+ { binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },
91
+ // Depth texture
92
+ { binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'depth' } },
93
+ // Normal texture
94
+ { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'unfilterable-float' } },
95
+ // ARM texture (for reflectivity)
96
+ { binding: 3, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'unfilterable-float' } },
97
+ ]
98
+
99
+ // Add blue noise if available
100
+ if (this.noiseTexture) {
101
+ bglEntries.push(
102
+ { binding: 4, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
103
+ )
104
+ }
105
+
106
+ const bindGroupLayout = device.createBindGroupLayout({
107
+ label: 'AO Bind Group Layout',
108
+ entries: bglEntries,
109
+ })
110
+
111
+ // Create uniform buffer (256 bytes minimum required by WebGPU)
112
+ // inverseProjection(64) + projection(64) + view(64) + canvasSize(8) + aoParams(16) + noiseParams(16) + cameraParams(8) + padding(16) = 256 bytes
113
+ this.uniformBuffer = device.createBuffer({
114
+ label: 'AO Uniforms',
115
+ size: 256,
116
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
117
+ })
118
+
119
+ // Create shader module
120
+ const shaderModule = device.createShaderModule({
121
+ label: 'AO Shader',
122
+ code: aoWGSL,
123
+ })
124
+
125
+ // Check for compilation errors
126
+ const compilationInfo = await shaderModule.getCompilationInfo()
127
+ for (const message of compilationInfo.messages) {
128
+ if (message.type === 'error') {
129
+ console.error('AO Shader Error:', message.message)
130
+ return
131
+ }
132
+ }
133
+
134
+ // Create pipeline
135
+ const pipelineLayout = device.createPipelineLayout({
136
+ label: 'AO Pipeline Layout',
137
+ bindGroupLayouts: [bindGroupLayout],
138
+ })
139
+
140
+ // Use async pipeline creation for non-blocking initialization
141
+ this.renderPipeline = await device.createRenderPipelineAsync({
142
+ label: 'AO Pipeline',
143
+ layout: pipelineLayout,
144
+ vertex: {
145
+ module: shaderModule,
146
+ entryPoint: 'vertexMain',
147
+ },
148
+ fragment: {
149
+ module: shaderModule,
150
+ entryPoint: 'fragmentMain',
151
+ targets: [{ format: 'r8unorm' }],
152
+ },
153
+ primitive: {
154
+ topology: 'triangle-list',
155
+ },
156
+ })
157
+
158
+ // Create bind group
159
+ const entries = [
160
+ { binding: 0, resource: { buffer: this.uniformBuffer } },
161
+ { binding: 1, resource: this.gbuffer.depth.view },
162
+ { binding: 2, resource: this.gbuffer.normal.view },
163
+ { binding: 3, resource: this.gbuffer.arm.view },
164
+ ]
165
+
166
+ if (this.noiseTexture) {
167
+ entries.push({ binding: 4, resource: this.noiseTexture.view })
168
+ }
169
+
170
+ this.bindGroup = device.createBindGroup({
171
+ label: 'AO Bind Group',
172
+ layout: bindGroupLayout,
173
+ entries: entries,
174
+ })
175
+
176
+ this.bindGroupLayout = bindGroupLayout
177
+ this._needsRebuild = false
178
+ }
179
+
180
+ async _execute(context) {
181
+ const { device, canvas } = this.engine
182
+ const { camera } = context
183
+
184
+ // Check if AO is enabled - if not, clear to white (no occlusion)
185
+ if (!this.settings?.ao?.enabled) {
186
+ if (this.outputTexture) {
187
+ const commandEncoder = device.createCommandEncoder({ label: 'AOClear' })
188
+ const passEncoder = commandEncoder.beginRenderPass({
189
+ colorAttachments: [{
190
+ view: this.outputTexture.view,
191
+ clearValue: { r: 1, g: 1, b: 1, a: 1 }, // White = no occlusion
192
+ loadOp: 'clear',
193
+ storeOp: 'store',
194
+ }],
195
+ })
196
+ passEncoder.end()
197
+ device.queue.submit([commandEncoder.finish()])
198
+ }
199
+ return
200
+ }
201
+
202
+ // Rebuild pipeline if needed
203
+ if (this._needsRebuild) {
204
+ await this._buildPipeline()
205
+ }
206
+
207
+ // If rebuild was attempted but failed, don't use stale pipeline with old bind groups
208
+ if (!this.renderPipeline || !this.gbuffer || this._needsRebuild) {
209
+ return
210
+ }
211
+
212
+ // Update uniforms
213
+ const uniformData = new Float32Array(64) // 256 bytes / 4
214
+
215
+ // Inverse projection matrix (for reconstructing view-space position)
216
+ if (camera.iProj) {
217
+ uniformData.set(camera.iProj, 0)
218
+ }
219
+
220
+ // Projection matrix
221
+ uniformData.set(camera.proj, 16)
222
+
223
+ // View matrix
224
+ uniformData.set(camera.view, 32)
225
+
226
+ // AO size (vec2f at offset 192 = float index 48)
227
+ // Use stored dimensions (may differ from canvas when effect scaling is applied)
228
+ uniformData[48] = this.width || canvas.width
229
+ uniformData[49] = this.height || canvas.height
230
+
231
+ // GBuffer size (vec2f at offset 200 = float index 50)
232
+ // Always full resolution canvas size for GBuffer sampling
233
+ uniformData[50] = canvas.width
234
+ uniformData[51] = canvas.height
235
+
236
+ // AO parameters: intensity, radius, fadeDistance, bias (vec4f at offset 208 = float index 52)
237
+ uniformData[52] = this.aoIntensity
238
+ uniformData[53] = this.aoRadius
239
+ uniformData[54] = this.aoFadeDistance
240
+ uniformData[55] = this.aoBias
241
+
242
+ // Noise parameters: size, offsetX, offsetY, frame (vec4f at offset 224 = float index 56)
243
+ uniformData[56] = this.noiseSize
244
+ uniformData[57] = this.noiseAnimated ? (Math.random() * 0.1) : 0 // Animated offset X
245
+ uniformData[58] = this.noiseAnimated ? (Math.random() * 0.1) : 0 // Animated offset Y
246
+ uniformData[59] = performance.now() / 1000 // Time for animation
247
+
248
+ // Camera near/far (vec2f at offset 240 = float index 60)
249
+ uniformData[60] = camera.near || 0.1
250
+ uniformData[61] = camera.far || 1000
251
+
252
+ device.queue.writeBuffer(this.uniformBuffer, 0, uniformData)
253
+
254
+ // Render AO pass
255
+ const commandEncoder = device.createCommandEncoder({ label: 'AO Pass' })
256
+
257
+ const renderPass = commandEncoder.beginRenderPass({
258
+ label: 'AO Render Pass',
259
+ colorAttachments: [{
260
+ view: this.outputTexture.view,
261
+ clearValue: { r: 1, g: 1, b: 1, a: 1 }, // White = no occlusion
262
+ loadOp: 'clear',
263
+ storeOp: 'store',
264
+ }],
265
+ })
266
+
267
+ renderPass.setPipeline(this.renderPipeline)
268
+ renderPass.setBindGroup(0, this.bindGroup)
269
+ renderPass.draw(3) // Full-screen triangle
270
+ renderPass.end()
271
+
272
+ device.queue.submit([commandEncoder.finish()])
273
+ }
274
+
275
+ async _resize(width, height) {
276
+ // Store dimensions for height-based scaling
277
+ this.width = width
278
+ this.height = height
279
+
280
+ // Recreate output texture at new size
281
+ this.outputTexture = await Texture.renderTarget(this.engine, 'r8unorm')
282
+ this._needsRebuild = true
283
+ }
284
+
285
+ _destroy() {
286
+ this.renderPipeline = null
287
+ this.outputTexture = null
288
+ }
289
+
290
+ /**
291
+ * Get the output AO texture
292
+ */
293
+ getOutputTexture() {
294
+ return this.outputTexture
295
+ }
296
+
297
+ /**
298
+ * Configure AO parameters
299
+ */
300
+ configure(options) {
301
+ if (options.intensity !== undefined) this.aoIntensity = options.intensity
302
+ if (options.radius !== undefined) this.aoRadius = options.radius
303
+ if (options.fadeDistance !== undefined) this.aoFadeDistance = options.fadeDistance
304
+ if (options.bias !== undefined) this.aoBias = options.bias
305
+ }
306
+ }
307
+
308
+ export { AOPass }