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,182 @@
1
+ const PI = 3.14159265359;
2
+
3
+ struct VertexOutput {
4
+ @builtin(position) position: vec4<f32>,
5
+ @location(0) uv: vec2<f32>,
6
+ }
7
+
8
+ struct Uniforms {
9
+ inverseProjection: mat4x4<f32>,
10
+ projection: mat4x4<f32>,
11
+ view: mat4x4<f32>,
12
+ aoSize: vec2f, // AO render target size (may be scaled)
13
+ gbufferSize: vec2f, // GBuffer full resolution size
14
+ // AO params: x = intensity, y = radius, z = fadeDistance, w = bias
15
+ aoParams: vec4f,
16
+ // Noise params: x = size, y = offsetX, z = offsetY, w = time
17
+ noiseParams: vec4f,
18
+ // Camera params: x = near, y = far
19
+ cameraParams: vec2f,
20
+ }
21
+
22
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
23
+ @group(0) @binding(1) var gDepth: texture_depth_2d;
24
+ @group(0) @binding(2) var gNormal: texture_2d<f32>;
25
+ @group(0) @binding(3) var gArm: texture_2d<f32>;
26
+ @group(0) @binding(4) var noiseTexture: texture_2d<f32>;
27
+
28
+ // Poisson disk offsets for 16 samples - well distributed pattern
29
+ const OFFSETS_16 = array<vec2f, 16>(
30
+ vec2f(0.063, 0.000),
31
+ vec2f(0.079, 0.097),
32
+ vec2f(-0.039, 0.183),
33
+ vec2f(-0.223, 0.113),
34
+ vec2f(-0.285, -0.127),
35
+ vec2f(-0.097, -0.362),
36
+ vec2f(0.257, -0.354),
37
+ vec2f(0.499, -0.026),
38
+ vec2f(0.376, 0.418),
39
+ vec2f(-0.098, 0.617),
40
+ vec2f(-0.595, 0.344),
41
+ vec2f(-0.700, -0.269),
42
+ vec2f(-0.251, -0.773),
43
+ vec2f(0.477, -0.734),
44
+ vec2f(0.932, -0.098),
45
+ vec2f(0.707, 0.707)
46
+ );
47
+
48
+ // Convert linear depth buffer value back to view-space distance
49
+ // Inverse of: depth = (z - near) / (far - near)
50
+ // Result: z = near + depth * (far - near)
51
+ fn depthToLinear(depth: f32) -> f32 {
52
+ let near = uniforms.cameraParams.x;
53
+ let far = uniforms.cameraParams.y;
54
+ return near + depth * (far - near);
55
+ }
56
+
57
+ // Get linear depth at pixel coordinate (converts from depth buffer)
58
+ fn getDepth(coord: vec2i) -> f32 {
59
+ let bufferDepth = textureLoad(gDepth, coord, 0);
60
+ return depthToLinear(bufferDepth);
61
+ }
62
+
63
+ // Sample noise at screen position
64
+ fn sampleNoise(screenPos: vec2f) -> f32 {
65
+ let noiseSize = i32(uniforms.noiseParams.x);
66
+ let noiseOffsetX = i32(uniforms.noiseParams.y * f32(noiseSize));
67
+ let noiseOffsetY = i32(uniforms.noiseParams.z * f32(noiseSize));
68
+
69
+ let texCoord = vec2i(
70
+ (i32(screenPos.x) + noiseOffsetX) % noiseSize,
71
+ (i32(screenPos.y) + noiseOffsetY) % noiseSize
72
+ );
73
+ return textureLoad(noiseTexture, texCoord, 0).r;
74
+ }
75
+
76
+ // Rotate a 2D vector by angle
77
+ fn rotate2D(v: vec2f, angle: f32) -> vec2f {
78
+ let s = sin(angle);
79
+ let c = cos(angle);
80
+ return vec2f(v.x * c - v.y * s, v.x * s + v.y * c);
81
+ }
82
+
83
+ @vertex
84
+ fn vertexMain(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
85
+ var output: VertexOutput;
86
+ let x = f32(vertexIndex & 1u) * 4.0 - 1.0;
87
+ let y = f32(vertexIndex >> 1u) * 4.0 - 1.0;
88
+ output.position = vec4f(x, y, 0.0, 1.0);
89
+ output.uv = vec2f((x + 1.0) * 0.5, (1.0 - y) * 0.5);
90
+ return output;
91
+ }
92
+
93
+ @fragment
94
+ fn fragmentMain(input: VertexOutput) -> @location(0) f32 {
95
+ // Use UV to sample GBuffer at correct position regardless of AO resolution
96
+ let gbufferCoord = vec2i(floor(input.uv * uniforms.gbufferSize));
97
+ let aoCoord = vec2i(floor(input.uv * uniforms.aoSize));
98
+ let screenPos = input.position.xy;
99
+
100
+ // Get linear depth in meters (sample from full-res GBuffer)
101
+ let depth = getDepth(gbufferCoord);
102
+ let normal = normalize(textureLoad(gNormal, gbufferCoord, 0).xyz);
103
+
104
+ // Parameters
105
+ let aoIntensity = uniforms.aoParams.x;
106
+ let aoRadius = uniforms.aoParams.y;
107
+ let aoFadeDistance = uniforms.aoParams.z;
108
+ let aoBias = uniforms.aoParams.w;
109
+ let far = uniforms.cameraParams.y;
110
+
111
+ // Early out for sky
112
+ if (depth > far * 0.95) {
113
+ return 1.0;
114
+ }
115
+
116
+ // Distance fade
117
+ let distanceFade = 1.0 - smoothstep(aoFadeDistance * 0.5, aoFadeDistance, depth);
118
+ if (distanceFade < 0.01) {
119
+ return 1.0;
120
+ }
121
+
122
+ // Blue noise jitter
123
+ let noise = sampleNoise(screenPos);
124
+ let rotationAngle = noise * PI * 2.0;
125
+
126
+ // Sample radius in pixels - scale with depth so AO is consistent across distances
127
+ let sampleRadius = aoRadius / max(depth * 0.2, 1.0);
128
+
129
+ var occlusion = 0.0;
130
+ var validSamples = 0.0;
131
+
132
+ // Occlusion threshold in meters - scales with depth
133
+ let occlusionThreshold = 0.1 + depth * 0.02; // 10cm + 2% of depth
134
+ let maxOcclusionDist = occlusionThreshold * 5.0;
135
+
136
+ // Scale factor from AO space to GBuffer space
137
+ let scaleToGBuffer = uniforms.gbufferSize / uniforms.aoSize;
138
+
139
+ for (var i = 0; i < 16; i++) {
140
+ let offset = rotate2D(OFFSETS_16[i], rotationAngle) * sampleRadius;
141
+ // Scale offset from AO-space to GBuffer-space pixels
142
+ let scaledOffset = offset * scaleToGBuffer;
143
+ let sampleCoord = gbufferCoord + vec2i(i32(scaledOffset.x), i32(scaledOffset.y));
144
+
145
+ // Bounds check against GBuffer size
146
+ if (sampleCoord.x < 0 || sampleCoord.x >= i32(uniforms.gbufferSize.x) ||
147
+ sampleCoord.y < 0 || sampleCoord.y >= i32(uniforms.gbufferSize.y)) {
148
+ continue;
149
+ }
150
+
151
+ let sampleDepth = getDepth(sampleCoord);
152
+
153
+ // Simple depth-based AO like the reference shader
154
+ // ddiff > 0 means sample is closer to camera (we're behind it = occluded)
155
+ let ddiff = depth - sampleDepth;
156
+
157
+ // If sample is closer (ddiff > 0), we're occluded
158
+ // If sample is further or same (ddiff <= 0), we're not occluded
159
+ let unoccluded = select(1.0, 0.0, ddiff > aoBias);
160
+
161
+ // Ignore samples that are much closer (edge/discontinuity)
162
+ let relevant = 1.0 - smoothstep(occlusionThreshold, maxOcclusionDist, ddiff);
163
+
164
+ occlusion += unoccluded * relevant;
165
+ validSamples += relevant;
166
+ }
167
+
168
+ // Final AO calculation
169
+ // occlusion = sum of unoccluded samples, validSamples = sum of relevant weights
170
+ // Higher unoccluded ratio = less darkening
171
+ var ao = 1.0;
172
+ if (validSamples > 0.5) {
173
+ let unoccludedRatio = occlusion / (validSamples * 0.5); // Like reference shader
174
+ let aoFactor = 1.0 - clamp(unoccludedRatio, 0.0, 1.0);
175
+ ao = 1.0 - aoFactor * aoIntensity * 0.5;
176
+ }
177
+
178
+ // Apply distance fade
179
+ ao = mix(1.0, ao, distanceFade);
180
+
181
+ return ao;
182
+ }
@@ -0,0 +1,97 @@
1
+ // Bloom bright pass shader
2
+ // Extracts bright and emissive pixels from HDR lighting output
3
+ // Uses exponential falloff so dark pixels contribute exponentially less
4
+
5
+ struct Uniforms {
6
+ threshold: f32, // Brightness threshold (e.g., 0.8)
7
+ softThreshold: f32, // Soft knee (0 = hard cutoff, 1 = very soft)
8
+ intensity: f32, // Overall bloom intensity
9
+ emissiveBoost: f32, // Extra boost for emissive pixels
10
+ maxBrightness: f32, // Clamp input brightness (prevents specular halos)
11
+ }
12
+
13
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
14
+ @group(0) @binding(1) var inputTexture: texture_2d<f32>; // HDR lighting output
15
+ @group(0) @binding(2) var inputSampler: sampler;
16
+
17
+ struct VertexOutput {
18
+ @builtin(position) position: vec4f,
19
+ @location(0) uv: vec2f,
20
+ }
21
+
22
+ @vertex
23
+ fn vertexMain(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
24
+ // Full-screen triangle
25
+ var positions = array<vec2f, 3>(
26
+ vec2f(-1.0, -1.0),
27
+ vec2f(3.0, -1.0),
28
+ vec2f(-1.0, 3.0)
29
+ );
30
+ var uvs = array<vec2f, 3>(
31
+ vec2f(0.0, 1.0),
32
+ vec2f(2.0, 1.0),
33
+ vec2f(0.0, -1.0)
34
+ );
35
+
36
+ var output: VertexOutput;
37
+ output.position = vec4f(positions[vertexIndex], 0.0, 1.0);
38
+ output.uv = uvs[vertexIndex];
39
+ return output;
40
+ }
41
+
42
+ // Calculate brightness as max RGB (treats all colors equally for bloom threshold)
43
+ fn brightness(color: vec3f) -> f32 {
44
+ return max(max(color.r, color.g), color.b);
45
+ }
46
+
47
+ // Soft threshold with knee curve
48
+ // Creates smooth transition around threshold instead of hard cutoff
49
+ fn softThresholdCurve(brightness: f32, threshold: f32, knee: f32) -> f32 {
50
+ let soft = threshold * knee;
51
+ let softMin = threshold - soft;
52
+ let softMax = threshold + soft;
53
+
54
+ if (brightness <= softMin) {
55
+ // Below threshold - exponential falloff
56
+ // Instead of 0, use exponential curve so bright-ish pixels still contribute slightly
57
+ let ratio = brightness / max(softMin, 0.001);
58
+ return pow(ratio, 4.0) * brightness; // Very aggressive falloff
59
+ } else if (brightness >= softMax) {
60
+ // Above threshold - full contribution
61
+ return brightness;
62
+ } else {
63
+ // In the soft knee region - smooth interpolation
64
+ let t = (brightness - softMin) / (softMax - softMin);
65
+ let smoothT = t * t * (3.0 - 2.0 * t); // Smoothstep
66
+ return mix(pow(brightness / threshold, 4.0) * brightness, brightness, smoothT);
67
+ }
68
+ }
69
+
70
+ @fragment
71
+ fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
72
+ var color = textureSample(inputTexture, inputSampler, input.uv).rgb;
73
+
74
+ // Clamp extremely bright values (specular highlights) to prevent excessive bloom
75
+ let bright = brightness(color);
76
+ if (bright > uniforms.maxBrightness) {
77
+ color = color * (uniforms.maxBrightness / bright);
78
+ }
79
+ let clampedBright = min(bright, uniforms.maxBrightness);
80
+
81
+ // Apply soft threshold with exponential falloff
82
+ let contribution = softThresholdCurve(clampedBright, uniforms.threshold, uniforms.softThreshold);
83
+
84
+ // Calculate the extraction factor (how much of the original color to keep)
85
+ let factor = contribution / max(clampedBright, 0.001);
86
+
87
+ // Extract bloom color
88
+ var bloomColor = color * factor * uniforms.intensity;
89
+
90
+ // Note: Emissive is already included in the HDR color from lighting pass
91
+ // Very bright pixels (brightness > 1.0) are likely emissive or highly lit
92
+ // Give them extra boost based on how much they exceed 1.0
93
+ let emissiveFactor = max(0.0, clampedBright - 1.0);
94
+ bloomColor *= 1.0 + emissiveFactor * uniforms.emissiveBoost;
95
+
96
+ return vec4f(bloomColor, 1.0);
97
+ }
@@ -0,0 +1,80 @@
1
+ // Bloom blur shader - Separable Gaussian blur
2
+ // Run twice: once horizontal, once vertical
3
+
4
+ struct Uniforms {
5
+ direction: vec2f, // (1,0) for horizontal, (0,1) for vertical
6
+ texelSize: vec2f, // 1.0 / textureSize
7
+ blurRadius: f32, // Blur radius in pixels
8
+ padding: f32,
9
+ }
10
+
11
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
12
+ @group(0) @binding(1) var inputTexture: texture_2d<f32>;
13
+ @group(0) @binding(2) var inputSampler: sampler;
14
+
15
+ struct VertexOutput {
16
+ @builtin(position) position: vec4f,
17
+ @location(0) uv: vec2f,
18
+ }
19
+
20
+ @vertex
21
+ fn vertexMain(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
22
+ // Full-screen triangle
23
+ var positions = array<vec2f, 3>(
24
+ vec2f(-1.0, -1.0),
25
+ vec2f(3.0, -1.0),
26
+ vec2f(-1.0, 3.0)
27
+ );
28
+ var uvs = array<vec2f, 3>(
29
+ vec2f(0.0, 1.0),
30
+ vec2f(2.0, 1.0),
31
+ vec2f(0.0, -1.0)
32
+ );
33
+
34
+ var output: VertexOutput;
35
+ output.position = vec4f(positions[vertexIndex], 0.0, 1.0);
36
+ output.uv = uvs[vertexIndex];
37
+ return output;
38
+ }
39
+
40
+ // Gaussian weight function
41
+ fn gaussian(x: f32, sigma: f32) -> f32 {
42
+ return exp(-(x * x) / (2.0 * sigma * sigma));
43
+ }
44
+
45
+ @fragment
46
+ fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
47
+ let uv = input.uv;
48
+ let direction = uniforms.direction;
49
+ let texelSize = uniforms.texelSize;
50
+ let radius = uniforms.blurRadius;
51
+
52
+ // Sigma is radius / 3 for good coverage (99.7% of gaussian within 3 sigma)
53
+ let sigma = radius / 3.0;
54
+
55
+ // Sample center
56
+ var color = textureSample(inputTexture, inputSampler, uv).rgb;
57
+ var totalWeight = 1.0;
58
+
59
+ // Use incremental offsets for better cache coherency
60
+ // Sample in both directions from center
61
+ let stepSize = 1.5; // Sample every 1.5 pixels for quality/performance balance
62
+ let numSamples = i32(ceil(radius / stepSize));
63
+
64
+ for (var i = 1; i <= numSamples; i++) {
65
+ let offset = f32(i) * stepSize;
66
+ let weight = gaussian(offset, sigma);
67
+
68
+ // Positive direction
69
+ let uvPos = uv + direction * texelSize * offset;
70
+ color += textureSample(inputTexture, inputSampler, uvPos).rgb * weight;
71
+
72
+ // Negative direction
73
+ let uvNeg = uv - direction * texelSize * offset;
74
+ color += textureSample(inputTexture, inputSampler, uvNeg).rgb * weight;
75
+
76
+ totalWeight += weight * 2.0;
77
+ }
78
+
79
+ return vec4f(color / totalWeight, 1.0);
80
+ }