@certe/atmos-renderer 0.1.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 (204) hide show
  1. package/LICENCE +674 -0
  2. package/README.md +166 -0
  3. package/dist/bloom-pass.d.ts +29 -0
  4. package/dist/bloom-pass.d.ts.map +1 -0
  5. package/dist/bloom-pass.js +173 -0
  6. package/dist/bloom-pass.js.map +1 -0
  7. package/dist/bloom-shader.d.ts +9 -0
  8. package/dist/bloom-shader.d.ts.map +1 -0
  9. package/dist/bloom-shader.js +69 -0
  10. package/dist/bloom-shader.js.map +1 -0
  11. package/dist/bounds.d.ts +10 -0
  12. package/dist/bounds.d.ts.map +1 -0
  13. package/dist/bounds.js +37 -0
  14. package/dist/bounds.js.map +1 -0
  15. package/dist/camera.d.ts +31 -0
  16. package/dist/camera.d.ts.map +1 -0
  17. package/dist/camera.js +53 -0
  18. package/dist/camera.js.map +1 -0
  19. package/dist/depth-prepass.d.ts +24 -0
  20. package/dist/depth-prepass.d.ts.map +1 -0
  21. package/dist/depth-prepass.js +107 -0
  22. package/dist/depth-prepass.js.map +1 -0
  23. package/dist/directional-light.d.ts +23 -0
  24. package/dist/directional-light.d.ts.map +1 -0
  25. package/dist/directional-light.js +36 -0
  26. package/dist/directional-light.js.map +1 -0
  27. package/dist/frustum.d.ts +15 -0
  28. package/dist/frustum.d.ts.map +1 -0
  29. package/dist/frustum.js +51 -0
  30. package/dist/frustum.js.map +1 -0
  31. package/dist/fullscreen-quad.d.ts +8 -0
  32. package/dist/fullscreen-quad.d.ts.map +1 -0
  33. package/dist/fullscreen-quad.js +30 -0
  34. package/dist/fullscreen-quad.js.map +1 -0
  35. package/dist/geometry.d.ts +28 -0
  36. package/dist/geometry.d.ts.map +1 -0
  37. package/dist/geometry.js +245 -0
  38. package/dist/geometry.js.map +1 -0
  39. package/dist/grid-renderer.d.ts +10 -0
  40. package/dist/grid-renderer.d.ts.map +1 -0
  41. package/dist/grid-renderer.js +77 -0
  42. package/dist/grid-renderer.js.map +1 -0
  43. package/dist/grid-shader.d.ts +3 -0
  44. package/dist/grid-shader.d.ts.map +1 -0
  45. package/dist/grid-shader.js +89 -0
  46. package/dist/grid-shader.js.map +1 -0
  47. package/dist/index.d.ts +64 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +45 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/light.d.ts +59 -0
  52. package/dist/light.d.ts.map +1 -0
  53. package/dist/light.js +184 -0
  54. package/dist/light.js.map +1 -0
  55. package/dist/material-asset.d.ts +19 -0
  56. package/dist/material-asset.d.ts.map +1 -0
  57. package/dist/material-asset.js +30 -0
  58. package/dist/material-asset.js.map +1 -0
  59. package/dist/material.d.ts +50 -0
  60. package/dist/material.d.ts.map +1 -0
  61. package/dist/material.js +48 -0
  62. package/dist/material.js.map +1 -0
  63. package/dist/mesh-renderer.d.ts +43 -0
  64. package/dist/mesh-renderer.d.ts.map +1 -0
  65. package/dist/mesh-renderer.js +162 -0
  66. package/dist/mesh-renderer.js.map +1 -0
  67. package/dist/mesh.d.ts +16 -0
  68. package/dist/mesh.d.ts.map +1 -0
  69. package/dist/mesh.js +33 -0
  70. package/dist/mesh.js.map +1 -0
  71. package/dist/mipmap-generator.d.ts +7 -0
  72. package/dist/mipmap-generator.d.ts.map +1 -0
  73. package/dist/mipmap-generator.js +96 -0
  74. package/dist/mipmap-generator.js.map +1 -0
  75. package/dist/pbr-wgsl.d.ts +12 -0
  76. package/dist/pbr-wgsl.d.ts.map +1 -0
  77. package/dist/pbr-wgsl.js +159 -0
  78. package/dist/pbr-wgsl.js.map +1 -0
  79. package/dist/pipeline.d.ts +13 -0
  80. package/dist/pipeline.d.ts.map +1 -0
  81. package/dist/pipeline.js +77 -0
  82. package/dist/pipeline.js.map +1 -0
  83. package/dist/point-light.d.ts +16 -0
  84. package/dist/point-light.d.ts.map +1 -0
  85. package/dist/point-light.js +22 -0
  86. package/dist/point-light.js.map +1 -0
  87. package/dist/point-shadow-pass.d.ts +24 -0
  88. package/dist/point-shadow-pass.d.ts.map +1 -0
  89. package/dist/point-shadow-pass.js +192 -0
  90. package/dist/point-shadow-pass.js.map +1 -0
  91. package/dist/point-shadow-shader.d.ts +12 -0
  92. package/dist/point-shadow-shader.d.ts.map +1 -0
  93. package/dist/point-shadow-shader.js +52 -0
  94. package/dist/point-shadow-shader.js.map +1 -0
  95. package/dist/register-builtins.d.ts +2 -0
  96. package/dist/register-builtins.d.ts.map +1 -0
  97. package/dist/register-builtins.js +98 -0
  98. package/dist/register-builtins.js.map +1 -0
  99. package/dist/render-system.d.ts +99 -0
  100. package/dist/render-system.d.ts.map +1 -0
  101. package/dist/render-system.js +476 -0
  102. package/dist/render-system.js.map +1 -0
  103. package/dist/scene-depth.d.ts +36 -0
  104. package/dist/scene-depth.d.ts.map +1 -0
  105. package/dist/scene-depth.js +183 -0
  106. package/dist/scene-depth.js.map +1 -0
  107. package/dist/shader.d.ts +3 -0
  108. package/dist/shader.d.ts.map +1 -0
  109. package/dist/shader.js +144 -0
  110. package/dist/shader.js.map +1 -0
  111. package/dist/shadow-fragment-wgsl.d.ts +13 -0
  112. package/dist/shadow-fragment-wgsl.d.ts.map +1 -0
  113. package/dist/shadow-fragment-wgsl.js +205 -0
  114. package/dist/shadow-fragment-wgsl.js.map +1 -0
  115. package/dist/shadow-manager.d.ts +46 -0
  116. package/dist/shadow-manager.d.ts.map +1 -0
  117. package/dist/shadow-manager.js +259 -0
  118. package/dist/shadow-manager.js.map +1 -0
  119. package/dist/shadow-pass.d.ts +31 -0
  120. package/dist/shadow-pass.d.ts.map +1 -0
  121. package/dist/shadow-pass.js +135 -0
  122. package/dist/shadow-pass.js.map +1 -0
  123. package/dist/shadow-shader.d.ts +10 -0
  124. package/dist/shadow-shader.d.ts.map +1 -0
  125. package/dist/shadow-shader.js +24 -0
  126. package/dist/shadow-shader.js.map +1 -0
  127. package/dist/shadow-uniforms.d.ts +38 -0
  128. package/dist/shadow-uniforms.d.ts.map +1 -0
  129. package/dist/shadow-uniforms.js +97 -0
  130. package/dist/shadow-uniforms.js.map +1 -0
  131. package/dist/skinned-geometry.d.ts +14 -0
  132. package/dist/skinned-geometry.d.ts.map +1 -0
  133. package/dist/skinned-geometry.js +23 -0
  134. package/dist/skinned-geometry.js.map +1 -0
  135. package/dist/skinned-mesh-renderer.d.ts +54 -0
  136. package/dist/skinned-mesh-renderer.d.ts.map +1 -0
  137. package/dist/skinned-mesh-renderer.js +177 -0
  138. package/dist/skinned-mesh-renderer.js.map +1 -0
  139. package/dist/skinned-pipeline.d.ts +16 -0
  140. package/dist/skinned-pipeline.d.ts.map +1 -0
  141. package/dist/skinned-pipeline.js +112 -0
  142. package/dist/skinned-pipeline.js.map +1 -0
  143. package/dist/skinned-shader.d.ts +7 -0
  144. package/dist/skinned-shader.d.ts.map +1 -0
  145. package/dist/skinned-shader.js +52 -0
  146. package/dist/skinned-shader.js.map +1 -0
  147. package/dist/skinned-shadow-shader.d.ts +6 -0
  148. package/dist/skinned-shadow-shader.d.ts.map +1 -0
  149. package/dist/skinned-shadow-shader.js +31 -0
  150. package/dist/skinned-shadow-shader.js.map +1 -0
  151. package/dist/spot-light.d.ts +24 -0
  152. package/dist/spot-light.d.ts.map +1 -0
  153. package/dist/spot-light.js +41 -0
  154. package/dist/spot-light.js.map +1 -0
  155. package/dist/spot-shadow-pass.d.ts +36 -0
  156. package/dist/spot-shadow-pass.d.ts.map +1 -0
  157. package/dist/spot-shadow-pass.js +144 -0
  158. package/dist/spot-shadow-pass.js.map +1 -0
  159. package/dist/ssao-pass.d.ts +37 -0
  160. package/dist/ssao-pass.d.ts.map +1 -0
  161. package/dist/ssao-pass.js +208 -0
  162. package/dist/ssao-pass.js.map +1 -0
  163. package/dist/ssao-shader.d.ts +9 -0
  164. package/dist/ssao-shader.d.ts.map +1 -0
  165. package/dist/ssao-shader.js +120 -0
  166. package/dist/ssao-shader.js.map +1 -0
  167. package/dist/terrain-mesh-renderer.d.ts +39 -0
  168. package/dist/terrain-mesh-renderer.d.ts.map +1 -0
  169. package/dist/terrain-mesh-renderer.js +131 -0
  170. package/dist/terrain-mesh-renderer.js.map +1 -0
  171. package/dist/terrain-pipeline.d.ts +17 -0
  172. package/dist/terrain-pipeline.d.ts.map +1 -0
  173. package/dist/terrain-pipeline.js +70 -0
  174. package/dist/terrain-pipeline.js.map +1 -0
  175. package/dist/terrain-shader.d.ts +10 -0
  176. package/dist/terrain-shader.d.ts.map +1 -0
  177. package/dist/terrain-shader.js +154 -0
  178. package/dist/terrain-shader.js.map +1 -0
  179. package/dist/texture.d.ts +20 -0
  180. package/dist/texture.d.ts.map +1 -0
  181. package/dist/texture.js +87 -0
  182. package/dist/texture.js.map +1 -0
  183. package/dist/tonemap-pass.d.ts +22 -0
  184. package/dist/tonemap-pass.d.ts.map +1 -0
  185. package/dist/tonemap-pass.js +125 -0
  186. package/dist/tonemap-pass.js.map +1 -0
  187. package/dist/unlit-pipeline.d.ts +12 -0
  188. package/dist/unlit-pipeline.d.ts.map +1 -0
  189. package/dist/unlit-pipeline.js +59 -0
  190. package/dist/unlit-pipeline.js.map +1 -0
  191. package/dist/unlit-shader.d.ts +3 -0
  192. package/dist/unlit-shader.d.ts.map +1 -0
  193. package/dist/unlit-shader.js +33 -0
  194. package/dist/unlit-shader.js.map +1 -0
  195. package/dist/webgpu-device.d.ts +13 -0
  196. package/dist/webgpu-device.d.ts.map +1 -0
  197. package/dist/webgpu-device.js +70 -0
  198. package/dist/webgpu-device.js.map +1 -0
  199. package/dist/wireframe-pipeline.d.ts +7 -0
  200. package/dist/wireframe-pipeline.d.ts.map +1 -0
  201. package/dist/wireframe-pipeline.js +72 -0
  202. package/dist/wireframe-pipeline.js.map +1 -0
  203. package/package.json +28 -0
  204. package/src/index.ts +87 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material-asset.js","sourceRoot":"","sources":["../src/material-asset.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1B,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,GAAG;KACf,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAuB;IAC5D,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;IACxD,OAAO;QACL,IAAI,EAAG,GAAG,CAAC,MAAM,CAAY,IAAI,SAAS;QAC1C,MAAM,EAAG,GAAG,CAAC,QAAQ,CAAgB,IAAI,KAAK;QAC9C,MAAM,EAAG,GAAG,CAAC,QAAQ,CAAsC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3E,QAAQ,EAAG,GAAG,CAAC,UAAU,CAAY,IAAI,CAAC;QAC1C,SAAS,EAAG,GAAG,CAAC,WAAW,CAAY,IAAI,GAAG;QAC9C,aAAa,EAAG,GAAG,CAAC,eAAe,CAAY,IAAI,SAAS;QAC5D,QAAQ,EAAG,GAAG,CAAC,UAAU,CAA8B,IAAI,SAAS;QACpE,iBAAiB,EAAG,GAAG,CAAC,mBAAmB,CAAY,IAAI,SAAS;QACpE,aAAa,EAAG,GAAG,CAAC,eAAe,CAAY,IAAI,SAAS;QAC5D,wBAAwB,EAAG,GAAG,CAAC,0BAA0B,CAAY,IAAI,SAAS;QAClF,UAAU,EAAG,GAAG,CAAC,YAAY,CAAY,IAAI,SAAS;QACtD,UAAU,EAAG,GAAG,CAAC,YAAY,CAAY,IAAI,SAAS;KACvD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { GPUTextureHandle } from './texture.js';
2
+ export interface MaterialParams {
3
+ albedo?: [number, number, number, number];
4
+ metallic?: number;
5
+ roughness?: number;
6
+ albedoTexture?: GPUTextureHandle;
7
+ emissive?: [number, number, number];
8
+ emissiveIntensity?: number;
9
+ normalTexture?: GPUTextureHandle;
10
+ metallicRoughnessTexture?: GPUTextureHandle;
11
+ splatSharpness?: number;
12
+ /** Fragments with alpha below this value are discarded. 0 = no cutoff. */
13
+ alphaCutoff?: number;
14
+ texTilingX?: number;
15
+ texTilingY?: number;
16
+ }
17
+ export interface Material {
18
+ albedo: Float32Array;
19
+ metallic: number;
20
+ roughness: number;
21
+ emissive: Float32Array;
22
+ emissiveIntensity: number;
23
+ /** Terrain splat sharpness exponent (1 = linear, higher = sharper). Default 1. */
24
+ splatSharpness: number;
25
+ /** Fragments with alpha below this value are discarded. 0 = no cutoff. */
26
+ alphaCutoff: number;
27
+ texTilingX: number;
28
+ texTilingY: number;
29
+ dirty: boolean;
30
+ uniformBuffer: GPUBuffer | null;
31
+ bindGroup: GPUBindGroup | null;
32
+ albedoTexture: GPUTextureHandle | null;
33
+ normalTexture: GPUTextureHandle | null;
34
+ metallicRoughnessTexture: GPUTextureHandle | null;
35
+ textureVersion: number;
36
+ }
37
+ /**
38
+ * Bytes: vec4 albedo(16) + f32 metallic(4) + f32 roughness(4) + 8B pad
39
+ * + vec4 emissive(16: rgb + intensity in w)
40
+ * + vec2 texTiling(8) + 8B pad = 64
41
+ */
42
+ export declare const MATERIAL_UNIFORM_SIZE = 64;
43
+ export declare function createMaterial(params?: MaterialParams): Material;
44
+ /**
45
+ * Write material uniforms into a Float32Array for GPU upload.
46
+ * Layout: [albedo(4), metallic, roughness, splatSharpness, alphaCutoff,
47
+ * emissive.rgb(3), emissiveIntensity, texTilingX, texTilingY, pad, pad]
48
+ */
49
+ export declare function writeMaterialUniforms(out: Float32Array, mat: Material): void;
50
+ //# sourceMappingURL=material.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../src/material.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,gBAAgB,CAAC;IACjC,wBAAwB,CAAC,EAAE,gBAAgB,CAAC;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kFAAkF;IAClF,cAAc,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,SAAS,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACvC,aAAa,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACvC,wBAAwB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,QAAQ,CAmBhE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAe5E"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Bytes: vec4 albedo(16) + f32 metallic(4) + f32 roughness(4) + 8B pad
3
+ * + vec4 emissive(16: rgb + intensity in w)
4
+ * + vec2 texTiling(8) + 8B pad = 64
5
+ */
6
+ export const MATERIAL_UNIFORM_SIZE = 64;
7
+ export function createMaterial(params) {
8
+ return {
9
+ albedo: new Float32Array(params?.albedo ?? [1, 1, 1, 1]),
10
+ metallic: params?.metallic ?? 0.0,
11
+ roughness: params?.roughness ?? 0.5,
12
+ emissive: new Float32Array(params?.emissive ?? [0, 0, 0]),
13
+ emissiveIntensity: params?.emissiveIntensity ?? 0,
14
+ splatSharpness: params?.splatSharpness ?? 1,
15
+ alphaCutoff: params?.alphaCutoff ?? 0,
16
+ texTilingX: params?.texTilingX ?? 1,
17
+ texTilingY: params?.texTilingY ?? 1,
18
+ dirty: true,
19
+ uniformBuffer: null,
20
+ bindGroup: null,
21
+ albedoTexture: params?.albedoTexture ?? null,
22
+ normalTexture: params?.normalTexture ?? null,
23
+ metallicRoughnessTexture: params?.metallicRoughnessTexture ?? null,
24
+ textureVersion: 0,
25
+ };
26
+ }
27
+ /**
28
+ * Write material uniforms into a Float32Array for GPU upload.
29
+ * Layout: [albedo(4), metallic, roughness, splatSharpness, alphaCutoff,
30
+ * emissive.rgb(3), emissiveIntensity, texTilingX, texTilingY, pad, pad]
31
+ */
32
+ export function writeMaterialUniforms(out, mat) {
33
+ out[0] = mat.albedo[0];
34
+ out[1] = mat.albedo[1];
35
+ out[2] = mat.albedo[2];
36
+ out[3] = mat.albedo[3];
37
+ out[4] = mat.metallic;
38
+ out[5] = mat.roughness;
39
+ out[6] = mat.splatSharpness ?? 1;
40
+ out[7] = mat.alphaCutoff;
41
+ out[8] = mat.emissive[0];
42
+ out[9] = mat.emissive[1];
43
+ out[10] = mat.emissive[2];
44
+ out[11] = mat.emissiveIntensity;
45
+ out[12] = mat.texTilingX;
46
+ out[13] = mat.texTilingY;
47
+ }
48
+ //# sourceMappingURL=material.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material.js","sourceRoot":"","sources":["../src/material.ts"],"names":[],"mappings":"AAuCA;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAExC,MAAM,UAAU,cAAc,CAAC,MAAuB;IACpD,OAAO;QACL,MAAM,EAAE,IAAI,YAAY,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACxD,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,GAAG;QACjC,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,GAAG;QACnC,QAAQ,EAAE,IAAI,YAAY,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACzD,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,IAAI,CAAC;QACjD,cAAc,EAAE,MAAM,EAAE,cAAc,IAAI,CAAC;QAC3C,WAAW,EAAE,MAAM,EAAE,WAAW,IAAI,CAAC;QACrC,UAAU,EAAE,MAAM,EAAE,UAAU,IAAI,CAAC;QACnC,UAAU,EAAE,MAAM,EAAE,UAAU,IAAI,CAAC;QACnC,KAAK,EAAE,IAAI;QACX,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,IAAI;QACf,aAAa,EAAE,MAAM,EAAE,aAAa,IAAI,IAAI;QAC5C,aAAa,EAAE,MAAM,EAAE,aAAa,IAAI,IAAI;QAC5C,wBAAwB,EAAE,MAAM,EAAE,wBAAwB,IAAI,IAAI;QAClE,cAAc,EAAE,CAAC;KAClB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAiB,EAAE,GAAa;IACpE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;IACxB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;IACxB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;IACxB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;IACxB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC;IACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC;IACvB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,cAAc,IAAI,CAAC,CAAC;IACjC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC;IACzB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC;IAC1B,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC;IAC1B,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC;IAC3B,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,iBAAiB,CAAC;IAChC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC;IACzB,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { Component } from '@certe/atmos-core';
2
+ import type { Mat4Type } from '@certe/atmos-math';
3
+ import type { Mesh } from './mesh.js';
4
+ import type { PipelineResources } from './pipeline.js';
5
+ import type { Material } from './material.js';
6
+ import type { BoundingSphere } from './bounds.js';
7
+ /** Minimal context for MeshRenderer — satisfied by RenderSystem via duck typing. */
8
+ export interface MeshRendererContext {
9
+ readonly device: GPUDevice;
10
+ readonly pipelineResources: PipelineResources;
11
+ }
12
+ export declare class MeshRenderer extends Component {
13
+ mesh: Mesh | null;
14
+ material: Material | null;
15
+ meshSource: string;
16
+ materialSource: string;
17
+ castShadow: boolean;
18
+ receiveSSAO: boolean;
19
+ uniformBuffer: GPUBuffer | null;
20
+ bindGroup: GPUBindGroup | null;
21
+ materialBindGroup: GPUBindGroup | null;
22
+ private _device;
23
+ private _pipelineResources;
24
+ private readonly _mvp;
25
+ private readonly _invModel;
26
+ private readonly _normalMat;
27
+ private readonly _matData;
28
+ private _lastTextureVersion;
29
+ private readonly _worldBoundsCenter;
30
+ private readonly _worldBounds;
31
+ init(ctx: MeshRendererContext, mesh: Mesh, material?: Material): void;
32
+ /** Lazily initialise GPU buffers if mesh+material exist but init() was never called. */
33
+ ensureGPU(ctx: MeshRendererContext): void;
34
+ /** Create material bind group lazily, once the shared scene buffer is available */
35
+ initMaterialBindGroup(sceneBuffer: GPUBuffer): void;
36
+ writeUniforms(viewProjection: Mat4Type): void;
37
+ draw(pass: GPURenderPassEncoder): void;
38
+ get worldBoundingSphere(): BoundingSphere | null;
39
+ onDestroy(): void;
40
+ /** Destroy owned GPU mesh buffers (vertex + index). */
41
+ destroyMesh(): void;
42
+ }
43
+ //# sourceMappingURL=mesh-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh-renderer.d.ts","sourceRoot":"","sources":["../src/mesh-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,oFAAoF;AACpF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;CAC/C;AAKD,qBAAa,YAAa,SAAQ,SAAS;IACzC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAQ;IACzB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;IACjC,UAAU,SAAM;IAChB,cAAc,SAAa;IAC3B,UAAU,UAAQ;IAClB,WAAW,UAAQ;IACnB,aAAa,EAAE,SAAS,GAAG,IAAI,CAAQ;IACvC,SAAS,EAAE,YAAY,GAAG,IAAI,CAAQ;IACtC,iBAAiB,EAAE,YAAY,GAAG,IAAI,CAAQ;IAE9C,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,kBAAkB,CAAkC;IAG5D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2B;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IAGtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+C;IAExE,OAAO,CAAC,mBAAmB,CAAM;IAGjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAuB;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkE;IAE/F,IAAI,CACF,GAAG,EAAE,mBAAmB,EACxB,IAAI,EAAE,IAAI,EACV,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI;IAoBP,wFAAwF;IACxF,SAAS,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI;IAezC,mFAAmF;IACnF,qBAAqB,CAAC,WAAW,EAAE,SAAS,GAAG,IAAI;IA+BnD,aAAa,CAAC,cAAc,EAAE,QAAQ,GAAG,IAAI;IA+B7C,IAAI,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI;IAUtC,IAAI,mBAAmB,IAAI,cAAc,GAAG,IAAI,CAoB/C;IAED,SAAS,IAAI,IAAI;IAOjB,uDAAuD;IACvD,WAAW,IAAI,IAAI;CAOpB"}
@@ -0,0 +1,162 @@
1
+ import { Component } from '@certe/atmos-core';
2
+ import { Mat4 } from '@certe/atmos-math';
3
+ import { writeMaterialUniforms, MATERIAL_UNIFORM_SIZE } from './material.js';
4
+ import { getWhiteFallbackTexture, getFlatNormalFallback, getDefaultMetallicRoughnessFallback } from './texture.js';
5
+ /** Per-object uniform buffer: MVP(64) + model(64) + normalMatrix(64) = 192 bytes */
6
+ const OBJECT_UNIFORM_SIZE = 192;
7
+ export class MeshRenderer extends Component {
8
+ mesh = null;
9
+ material = null;
10
+ meshSource = '';
11
+ materialSource = 'Default';
12
+ castShadow = true;
13
+ receiveSSAO = true;
14
+ uniformBuffer = null;
15
+ bindGroup = null;
16
+ materialBindGroup = null;
17
+ _device = null;
18
+ _pipelineResources = null;
19
+ // Pre-allocated scratch matrices
20
+ _mvp = Mat4.create();
21
+ _invModel = Mat4.create();
22
+ _normalMat = Mat4.create();
23
+ // Scratch buffer for material uniforms
24
+ _matData = new Float32Array(MATERIAL_UNIFORM_SIZE / 4);
25
+ _lastTextureVersion = -1;
26
+ // Pre-allocated bounding sphere result (reused by worldBoundingSphere getter)
27
+ _worldBoundsCenter = new Float32Array(3);
28
+ _worldBounds = { center: this._worldBoundsCenter, radius: 0 };
29
+ init(ctx, mesh, material) {
30
+ const { device, pipelineResources } = ctx;
31
+ this._device = device;
32
+ this._pipelineResources = pipelineResources;
33
+ this.mesh = mesh;
34
+ this.material = material ?? null;
35
+ this.uniformBuffer = device.createBuffer({
36
+ size: OBJECT_UNIFORM_SIZE,
37
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
38
+ });
39
+ this.bindGroup = device.createBindGroup({
40
+ layout: pipelineResources.objectBindGroupLayout,
41
+ entries: [
42
+ { binding: 0, resource: { buffer: this.uniformBuffer } },
43
+ ],
44
+ });
45
+ }
46
+ /** Lazily initialise GPU buffers if mesh+material exist but init() was never called. */
47
+ ensureGPU(ctx) {
48
+ if (this._device || !this.mesh)
49
+ return;
50
+ const { device, pipelineResources } = ctx;
51
+ this._device = device;
52
+ this._pipelineResources = pipelineResources;
53
+ this.uniformBuffer = device.createBuffer({
54
+ size: OBJECT_UNIFORM_SIZE,
55
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
56
+ });
57
+ this.bindGroup = device.createBindGroup({
58
+ layout: pipelineResources.objectBindGroupLayout,
59
+ entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],
60
+ });
61
+ }
62
+ /** Create material bind group lazily, once the shared scene buffer is available */
63
+ initMaterialBindGroup(sceneBuffer) {
64
+ if (!this._device || !this._pipelineResources || !this.material)
65
+ return;
66
+ if (this.materialBindGroup)
67
+ return;
68
+ // Create material uniform buffer if needed
69
+ if (!this.material.uniformBuffer) {
70
+ this.material.uniformBuffer = this._device.createBuffer({
71
+ size: MATERIAL_UNIFORM_SIZE,
72
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
73
+ });
74
+ this.material.dirty = true;
75
+ }
76
+ const tex = this.material.albedoTexture ?? getWhiteFallbackTexture(this._device);
77
+ const nrm = this.material.normalTexture ?? getFlatNormalFallback(this._device);
78
+ const mr = this.material.metallicRoughnessTexture ?? getDefaultMetallicRoughnessFallback(this._device);
79
+ this.materialBindGroup = this._device.createBindGroup({
80
+ layout: this._pipelineResources.materialBindGroupLayout,
81
+ entries: [
82
+ { binding: 0, resource: { buffer: this.material.uniformBuffer } },
83
+ { binding: 1, resource: { buffer: sceneBuffer } },
84
+ { binding: 2, resource: tex.view },
85
+ { binding: 3, resource: tex.sampler },
86
+ { binding: 4, resource: nrm.view },
87
+ { binding: 5, resource: nrm.sampler },
88
+ { binding: 6, resource: mr.view },
89
+ { binding: 7, resource: mr.sampler },
90
+ ],
91
+ });
92
+ }
93
+ writeUniforms(viewProjection) {
94
+ if (!this._device || !this.uniformBuffer)
95
+ return;
96
+ const model = this.gameObject.transform.worldMatrix;
97
+ // MVP
98
+ Mat4.multiply(this._mvp, viewProjection, model);
99
+ // Normal matrix = transpose(inverse(model))
100
+ Mat4.invert(this._invModel, model);
101
+ Mat4.transpose(this._normalMat, this._invModel);
102
+ // Write all 3 matrices to buffer
103
+ this._device.queue.writeBuffer(this.uniformBuffer, 0, this._mvp);
104
+ this._device.queue.writeBuffer(this.uniformBuffer, 64, model);
105
+ this._device.queue.writeBuffer(this.uniformBuffer, 128, this._normalMat);
106
+ // Rebuild bind group if material texture changed
107
+ if (this.material && this.material.textureVersion !== this._lastTextureVersion) {
108
+ this._lastTextureVersion = this.material.textureVersion;
109
+ this.materialBindGroup = null;
110
+ }
111
+ // Write material uniforms if dirty
112
+ if (this.material?.dirty && this.material.uniformBuffer) {
113
+ writeMaterialUniforms(this._matData, this.material);
114
+ this._device.queue.writeBuffer(this.material.uniformBuffer, 0, this._matData);
115
+ this.material.dirty = false;
116
+ }
117
+ }
118
+ draw(pass) {
119
+ if (!this.mesh || !this.bindGroup || !this._pipelineResources || !this.materialBindGroup)
120
+ return;
121
+ pass.setPipeline(this._pipelineResources.pipeline);
122
+ pass.setBindGroup(0, this.bindGroup);
123
+ pass.setBindGroup(1, this.materialBindGroup);
124
+ pass.setVertexBuffer(0, this.mesh.vertexBuffer);
125
+ pass.setIndexBuffer(this.mesh.indexBuffer, this.mesh.indexFormat);
126
+ pass.drawIndexed(this.mesh.indexCount);
127
+ }
128
+ get worldBoundingSphere() {
129
+ const bounds = this.mesh?.bounds;
130
+ if (!bounds)
131
+ return null;
132
+ const model = this.gameObject.transform.worldMatrix;
133
+ // Transform center by world matrix
134
+ const cx = bounds.center[0];
135
+ const cy = bounds.center[1];
136
+ const cz = bounds.center[2];
137
+ this._worldBoundsCenter[0] = model[0] * cx + model[4] * cy + model[8] * cz + model[12];
138
+ this._worldBoundsCenter[1] = model[1] * cx + model[5] * cy + model[9] * cz + model[13];
139
+ this._worldBoundsCenter[2] = model[2] * cx + model[6] * cy + model[10] * cz + model[14];
140
+ // Approximate world radius: max column scale
141
+ const sx = Math.sqrt(model[0] * model[0] + model[1] * model[1] + model[2] * model[2]);
142
+ const sy = Math.sqrt(model[4] * model[4] + model[5] * model[5] + model[6] * model[6]);
143
+ const sz = Math.sqrt(model[8] * model[8] + model[9] * model[9] + model[10] * model[10]);
144
+ this._worldBounds.radius = bounds.radius * Math.max(sx, sy, sz);
145
+ return this._worldBounds;
146
+ }
147
+ onDestroy() {
148
+ this.uniformBuffer?.destroy();
149
+ this.uniformBuffer = null;
150
+ this.bindGroup = null;
151
+ this.materialBindGroup = null;
152
+ }
153
+ /** Destroy owned GPU mesh buffers (vertex + index). */
154
+ destroyMesh() {
155
+ if (this.mesh) {
156
+ this.mesh.vertexBuffer.destroy();
157
+ this.mesh.indexBuffer.destroy();
158
+ this.mesh = null;
159
+ }
160
+ }
161
+ }
162
+ //# sourceMappingURL=mesh-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh-renderer.js","sourceRoot":"","sources":["../src/mesh-renderer.ts"],"names":[],"mappings":"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"}
package/dist/mesh.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import type { BoundingSphere } from './bounds.js';
2
+ export interface Mesh {
3
+ vertexBuffer: GPUBuffer;
4
+ indexBuffer: GPUBuffer;
5
+ indexCount: number;
6
+ indexFormat: GPUIndexFormat;
7
+ bounds?: BoundingSphere;
8
+ /** CPU-side vertex data for ray picking */
9
+ vertices?: Float32Array;
10
+ /** CPU-side index data for ray picking */
11
+ indices?: Uint16Array | Uint32Array;
12
+ /** Floats per vertex (e.g. 8 for pos+normal+uv) */
13
+ vertexStride?: number;
14
+ }
15
+ export declare function createMesh(device: GPUDevice, vertices: Float32Array, indices: Uint16Array | Uint32Array, vertexStride?: number): Mesh;
16
+ //# sourceMappingURL=mesh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh.d.ts","sourceRoot":"","sources":["../src/mesh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,IAAI;IACnB,YAAY,EAAE,SAAS,CAAC;IACxB,WAAW,EAAE,SAAS,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,cAAc,CAAC;IAC5B,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC;IACpC,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,WAAW,GAAG,WAAW,EAClC,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI,CAiCN"}
package/dist/mesh.js ADDED
@@ -0,0 +1,33 @@
1
+ export function createMesh(device, vertices, indices, vertexStride) {
2
+ const vertexBuffer = device.createBuffer({
3
+ size: vertices.byteLength,
4
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
5
+ });
6
+ device.queue.writeBuffer(vertexBuffer, 0, vertices);
7
+ // writeBuffer requires byte length to be a multiple of 4.
8
+ // Uint16Array with odd element count (e.g. 3 indices = 6 bytes) needs padding.
9
+ const alignedByteSize = Math.ceil(indices.byteLength / 4) * 4;
10
+ const indexBuffer = device.createBuffer({
11
+ size: alignedByteSize,
12
+ usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
13
+ });
14
+ if (indices.byteLength === alignedByteSize) {
15
+ device.queue.writeBuffer(indexBuffer, 0, indices);
16
+ }
17
+ else {
18
+ const padded = new Uint8Array(alignedByteSize);
19
+ padded.set(new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength));
20
+ device.queue.writeBuffer(indexBuffer, 0, padded);
21
+ }
22
+ const indexFormat = indices instanceof Uint32Array ? 'uint32' : 'uint16';
23
+ return {
24
+ vertexBuffer,
25
+ indexBuffer,
26
+ indexCount: indices.length,
27
+ indexFormat,
28
+ vertices,
29
+ indices,
30
+ vertexStride,
31
+ };
32
+ }
33
+ //# sourceMappingURL=mesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh.js","sourceRoot":"","sources":["../src/mesh.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,UAAU,CACxB,MAAiB,EACjB,QAAsB,EACtB,OAAkC,EAClC,YAAqB;IAErB,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QACvC,IAAI,EAAE,QAAQ,CAAC,UAAU;QACzB,KAAK,EAAE,cAAc,CAAC,MAAM,GAAG,cAAc,CAAC,QAAQ;KACvD,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,EAAE,QAAsC,CAAC,CAAC;IAElF,0DAA0D;IAC1D,+EAA+E;IAC/E,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,WAAW,GAAG,MAAM,CAAC,YAAY,CAAC;QACtC,IAAI,EAAE,eAAe;QACrB,KAAK,EAAE,cAAc,CAAC,KAAK,GAAG,cAAc,CAAC,QAAQ;KACtD,CAAC,CAAC;IACH,IAAI,OAAO,CAAC,UAAU,KAAK,eAAe,EAAE,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,EAAE,OAAqC,CAAC,CAAC;IAClF,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QACnF,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,EAAE,MAAoC,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,WAAW,GAAmB,OAAO,YAAY,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEzF,OAAO;QACL,YAAY;QACZ,WAAW;QACX,UAAU,EAAE,OAAO,CAAC,MAAM;QAC1B,WAAW;QACX,QAAQ;QACR,OAAO;QACP,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Blit-based mipmap generator for WebGPU textures.
3
+ * Creates each mip level by rendering a fullscreen triangle with linear filtering.
4
+ */
5
+ /** Generate mipmaps for a texture using blit-based downsampling. */
6
+ export declare function generateMipmaps(device: GPUDevice, texture: GPUTexture): void;
7
+ //# sourceMappingURL=mipmap-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mipmap-generator.d.ts","sourceRoot":"","sources":["../src/mipmap-generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuEH,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAmC5E"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Blit-based mipmap generator for WebGPU textures.
3
+ * Creates each mip level by rendering a fullscreen triangle with linear filtering.
4
+ */
5
+ const MIPMAP_SHADER = /* wgsl */ `
6
+ var<private> pos: array<vec2<f32>, 3> = array(
7
+ vec2(-1.0, -1.0),
8
+ vec2( 3.0, -1.0),
9
+ vec2(-1.0, 3.0),
10
+ );
11
+
12
+ struct VertexOutput {
13
+ @builtin(position) position: vec4<f32>,
14
+ @location(0) uv: vec2<f32>,
15
+ };
16
+
17
+ @vertex
18
+ fn vs(@builtin(vertex_index) i: u32) -> VertexOutput {
19
+ var out: VertexOutput;
20
+ let p = pos[i];
21
+ out.position = vec4(p, 0.0, 1.0);
22
+ out.uv = p * vec2(0.5, -0.5) + vec2(0.5);
23
+ return out;
24
+ }
25
+
26
+ @group(0) @binding(0) var srcTexture: texture_2d<f32>;
27
+ @group(0) @binding(1) var srcSampler: sampler;
28
+
29
+ @fragment
30
+ fn fs(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
31
+ return textureSample(srcTexture, srcSampler, uv);
32
+ }
33
+ `;
34
+ const _cache = new WeakMap();
35
+ function getOrCreatePipeline(device, format) {
36
+ let formatMap = _cache.get(device);
37
+ if (!formatMap) {
38
+ formatMap = new Map();
39
+ _cache.set(device, formatMap);
40
+ }
41
+ const cached = formatMap.get(format);
42
+ if (cached)
43
+ return cached;
44
+ const module = device.createShaderModule({ code: MIPMAP_SHADER });
45
+ const bindGroupLayout = device.createBindGroupLayout({
46
+ entries: [
47
+ { binding: 0, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
48
+ { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
49
+ ],
50
+ });
51
+ const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] });
52
+ const pipeline = device.createRenderPipeline({
53
+ layout: pipelineLayout,
54
+ vertex: { module, entryPoint: 'vs' },
55
+ fragment: { module, entryPoint: 'fs', targets: [{ format }] },
56
+ primitive: { topology: 'triangle-list' },
57
+ });
58
+ const sampler = device.createSampler({ minFilter: 'linear', magFilter: 'linear' });
59
+ const entry = { pipeline, sampler, bindGroupLayout };
60
+ formatMap.set(format, entry);
61
+ return entry;
62
+ }
63
+ /** Generate mipmaps for a texture using blit-based downsampling. */
64
+ export function generateMipmaps(device, texture) {
65
+ const mipCount = texture.mipLevelCount;
66
+ if (mipCount <= 1)
67
+ return;
68
+ const format = texture.format;
69
+ const { pipeline, sampler, bindGroupLayout } = getOrCreatePipeline(device, format);
70
+ const encoder = device.createCommandEncoder();
71
+ for (let level = 1; level < mipCount; level++) {
72
+ const srcView = texture.createView({ baseMipLevel: level - 1, mipLevelCount: 1 });
73
+ const dstView = texture.createView({ baseMipLevel: level, mipLevelCount: 1 });
74
+ const bindGroup = device.createBindGroup({
75
+ layout: bindGroupLayout,
76
+ entries: [
77
+ { binding: 0, resource: srcView },
78
+ { binding: 1, resource: sampler },
79
+ ],
80
+ });
81
+ const pass = encoder.beginRenderPass({
82
+ colorAttachments: [{
83
+ view: dstView,
84
+ loadOp: 'clear',
85
+ storeOp: 'store',
86
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
87
+ }],
88
+ });
89
+ pass.setPipeline(pipeline);
90
+ pass.setBindGroup(0, bindGroup);
91
+ pass.draw(3);
92
+ pass.end();
93
+ }
94
+ device.queue.submit([encoder.finish()]);
95
+ }
96
+ //# sourceMappingURL=mipmap-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mipmap-generator.js","sourceRoot":"","sources":["../src/mipmap-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared PBR WGSL functions and light loop code.
3
+ * Concatenated into both shader.ts (standard PBR) and terrain-shader.ts (splat PBR).
4
+ */
5
+ /** PBR helper functions: GGX distribution, geometry, Fresnel, computePBR, computeTBN */
6
+ export declare const PBR_FUNCTIONS_WGSL = "\n// GGX/Trowbridge-Reitz normal distribution\nfn distributionGGX(N: vec3<f32>, H: vec3<f32>, roughness: f32) -> f32 {\n let a = roughness * roughness;\n let a2 = a * a;\n let NdotH = max(dot(N, H), 0.0);\n let NdotH2 = NdotH * NdotH;\n let denom = NdotH2 * (a2 - 1.0) + 1.0;\n return a2 / (PI * denom * denom);\n}\n\n// Schlick-GGX geometry function\nfn geometrySchlickGGX(NdotV: f32, roughness: f32) -> f32 {\n let r = roughness + 1.0;\n let k = (r * r) / 8.0;\n return NdotV / (NdotV * (1.0 - k) + k);\n}\n\n// Smith's geometry function\nfn geometrySmith(N: vec3<f32>, V: vec3<f32>, L: vec3<f32>, roughness: f32) -> f32 {\n let NdotV = max(dot(N, V), 0.0);\n let NdotL = max(dot(N, L), 0.0);\n return geometrySchlickGGX(NdotV, roughness) * geometrySchlickGGX(NdotL, roughness);\n}\n\n// Fresnel-Schlick approximation\nfn fresnelSchlick(cosTheta: f32, F0: vec3<f32>) -> vec3<f32> {\n return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);\n}\n\n// Compute PBR contribution from a single light direction\nfn computePBR(\n N: vec3<f32>, V: vec3<f32>, L: vec3<f32>,\n albedo: vec3<f32>, metallic: f32, roughness: f32,\n F0: vec3<f32>, radiance: vec3<f32>,\n) -> vec3<f32> {\n let H = normalize(V + L);\n let NDF = distributionGGX(N, H, roughness);\n let G = geometrySmith(N, V, L, roughness);\n let F = fresnelSchlick(max(dot(H, V), 0.0), F0);\n\n let numerator = NDF * G * F;\n let denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;\n let specular = numerator / denominator;\n\n let kS = F;\n let kD = (vec3<f32>(1.0) - kS) * (1.0 - metallic);\n let NdotL = max(dot(N, L), 0.0);\n\n return (kD * albedo / PI + specular) * radiance * NdotL;\n}\n\n// Compute cotangent-frame TBN from screen-space derivatives\nfn computeTBN(worldPos: vec3<f32>, worldNormal: vec3<f32>, uv: vec2<f32>) -> mat3x3<f32> {\n let dp1 = dpdx(worldPos);\n let dp2 = dpdy(worldPos);\n let duv1 = dpdx(uv);\n let duv2 = dpdy(uv);\n let T = normalize(dp1 * duv2.y - dp2 * duv1.y);\n let B = normalize(dp2 * duv1.x - dp1 * duv2.x);\n let N = normalize(worldNormal);\n return mat3x3(T, B, N);\n}\n";
7
+ /** Light loop WGSL: iterates dir/point/spot lights with PBR + shadow sampling.
8
+ * Expects: N, V, albedo, metallic, roughness, F0, worldPosition in scope. Writes to Lo. */
9
+ export declare const LIGHT_LOOP_WGSL = "\n // Directional lights\n for (var i = 0u; i < scene.numDirLights; i = i + 1u) {\n let light = scene.dirLights[i];\n let L = normalize(-light.direction.xyz);\n let intensity = light.color.w;\n let radiance = light.color.rgb * intensity;\n var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);\n let dirSlot = shadow.dirLightToSlot[i];\n if (dirSlot != 0xFFFFFFFFu) {\n contribution = contribution * sampleDirShadow(dirSlot, worldPosition);\n }\n Lo = Lo + contribution;\n }\n\n // Point lights\n for (var i = 0u; i < scene.numPointLights; i = i + 1u) {\n let light = scene.pointLights[i];\n let lightPos = light.position.xyz;\n let range = light.position.w;\n let intensity = light.color.w;\n\n let toLight = lightPos - worldPosition;\n let dist = length(toLight);\n let L = toLight / max(dist, 0.0001);\n\n // Smooth distance attenuation with range cutoff\n let attenuation = max(1.0 - (dist * dist) / (range * range), 0.0);\n let radiance = light.color.rgb * intensity * attenuation * attenuation;\n\n var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);\n let pointSlot = shadow.pointLightToSlot[i];\n if (pointSlot != 0xFFFFFFFFu) {\n contribution = contribution * samplePointShadow(pointSlot, worldPosition, N);\n }\n Lo = Lo + contribution;\n }\n\n // Spot lights\n for (var i = 0u; i < scene.numSpotLights; i = i + 1u) {\n let light = scene.spotLights[i];\n let lightPos = light.position.xyz;\n let range = light.position.w;\n let spotDir = light.direction.xyz;\n let outerCos = light.direction.w;\n let innerCos = light.extra.x;\n let intensity = light.color.w;\n\n let toLight = lightPos - worldPosition;\n let dist = length(toLight);\n let L = toLight / max(dist, 0.0001);\n\n // Distance attenuation (same as point light)\n let distAtt = max(1.0 - (dist * dist) / (range * range), 0.0);\n\n // Cone attenuation: smoothstep between outer and inner cosines\n let cosAngle = dot(-L, spotDir);\n let coneAtt = smoothstep(outerCos, innerCos, cosAngle);\n\n let attenuation = distAtt * distAtt * coneAtt;\n let radiance = light.color.rgb * intensity * attenuation;\n\n var contribution = computePBR(N, V, L, albedo, metallic, roughness, F0, radiance);\n let spotSlot = shadow.spotLightToSlot[i];\n if (spotSlot != 0xFFFFFFFFu) {\n contribution = contribution * sampleSpotShadow(spotSlot, worldPosition);\n }\n Lo = Lo + contribution;\n }\n";
10
+ /** Fog calculation WGSL. Expects: scene, worldPosition, color in scope. Modifies color. */
11
+ export declare const FOG_WGSL = "\n // Distance fog\n if (scene.fogEnabled != 0u) {\n let fogDist = length(scene.cameraPos.xyz - worldPosition);\n var fogFactor: f32;\n if (scene.fogMode == 0u) {\n // Linear\n fogFactor = saturate((scene.fogEnd - fogDist) / (scene.fogEnd - scene.fogStart));\n } else {\n // Exponential\u00B2\n let d = scene.fogDensity * fogDist;\n fogFactor = exp(-(d * d));\n }\n color = mix(scene.fogColor.rgb, color, fogFactor);\n }\n";
12
+ //# sourceMappingURL=pbr-wgsl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pbr-wgsl.d.ts","sourceRoot":"","sources":["../src/pbr-wgsl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wFAAwF;AACxF,eAAO,MAAM,kBAAkB,2lEA+D9B,CAAC;AAEF;4FAC4F;AAC5F,eAAO,MAAM,eAAe,2gFAqE3B,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,QAAQ,ydAepB,CAAC"}