@driftengine/core 4.8.6 → 4.8.7

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 (139) hide show
  1. package/CHANGELOG.json +71 -0
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +1 -1
  5. package/dist/render/anisotropicLobe.d.ts +10 -0
  6. package/dist/render/anisotropicLobe.js +19 -0
  7. package/dist/render/areaLights.d.ts +35 -0
  8. package/dist/render/areaLights.js +35 -0
  9. package/dist/render/backend/api.d.ts +33 -3
  10. package/dist/render/backend/webgl2/renderer.d.ts +50 -14
  11. package/dist/render/backend/webgl2/renderer.js +141 -30
  12. package/dist/render/backend/webgl2/sceneCaptureTarget.d.ts +29 -0
  13. package/dist/render/backend/webgl2/sceneCaptureTarget.js +96 -0
  14. package/dist/render/backend/webgpu/particlePass.js +2 -1
  15. package/dist/render/backend/webgpu/renderer.d.ts +35 -1
  16. package/dist/render/backend/webgpu/renderer.js +155 -16
  17. package/dist/render/backend/webgpu/sceneCaptureTarget.d.ts +24 -0
  18. package/dist/render/backend/webgpu/sceneCaptureTarget.js +59 -0
  19. package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
  20. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +4 -1
  21. package/dist/render/backend/webgpu/surfaceTexturePass.js +34 -8
  22. package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
  23. package/dist/render/clusteredLights.d.ts +23 -5
  24. package/dist/render/clusteredLights.js +35 -8
  25. package/dist/render/driftLight/bake.d.ts +2 -0
  26. package/dist/render/driftLight/bake.js +1 -1
  27. package/dist/render/driftLight/falloff.d.ts +4 -2
  28. package/dist/render/driftLight/falloff.js +8 -2
  29. package/dist/render/gi/bounceLights.d.ts +3 -2
  30. package/dist/render/gi/bounceLights.js +8 -3
  31. package/dist/render/instanceCull.js +5 -0
  32. package/dist/render/instances.d.ts +19 -5
  33. package/dist/render/instances.js +9 -3
  34. package/dist/render/lightBudget.d.ts +12 -1
  35. package/dist/render/lightBudget.js +23 -3
  36. package/dist/render/lightmap.d.ts +23 -9
  37. package/dist/render/lightmap.js +40 -18
  38. package/dist/render/particlePool.d.ts +21 -0
  39. package/dist/render/particlePool.js +7 -0
  40. package/dist/render/pointLightSelection.d.ts +13 -0
  41. package/dist/render/pointLightSelection.js +3 -1
  42. package/dist/render/renderQuality.d.ts +8 -7
  43. package/dist/render/rendererHarness.js +3 -0
  44. package/dist/render/rgb9e5.d.ts +22 -0
  45. package/dist/render/rgb9e5.js +47 -0
  46. package/dist/render/sceneCapture.d.ts +29 -0
  47. package/dist/render/sceneCapture.js +36 -0
  48. package/dist/render/screenSpaceReflection.d.ts +27 -1
  49. package/dist/render/screenSpaceReflection.js +9 -0
  50. package/dist/render/shaders/bolt.d.ts +1 -1
  51. package/dist/render/shaders/bolt.js +7 -1
  52. package/dist/render/shaders/depth.js +11 -0
  53. package/dist/render/shaders/flat/anisotropic.d.ts +1 -1
  54. package/dist/render/shaders/flat/anisotropic.js +37 -3
  55. package/dist/render/shaders/flat/areaLight.d.ts +1 -1
  56. package/dist/render/shaders/flat/areaLight.js +46 -0
  57. package/dist/render/shaders/flat/glassTint.d.ts +3 -2
  58. package/dist/render/shaders/flat/glassTint.js +3 -1
  59. package/dist/render/shaders/flat/index.d.ts +5 -0
  60. package/dist/render/shaders/flat/index.js +16 -2
  61. package/dist/render/shaders/flat/lobes.d.ts +6 -0
  62. package/dist/render/shaders/flat/lobes.js +49 -43
  63. package/dist/render/shaders/flat/main.d.ts +1 -1
  64. package/dist/render/shaders/flat/main.js +57 -22
  65. package/dist/render/shaders/flat/models.d.ts +5 -2
  66. package/dist/render/shaders/flat/models.js +100 -16
  67. package/dist/render/shaders/flat/preamble.js +10 -3
  68. package/dist/render/shaders/generated/bolt.wgsl.d.ts +1 -1
  69. package/dist/render/shaders/generated/bolt.wgsl.js +1 -1
  70. package/dist/render/shaders/generated/depth.wgsl.d.ts +4 -4
  71. package/dist/render/shaders/generated/depth.wgsl.js +4 -4
  72. package/dist/render/shaders/generated/flat.wgsl.d.ts +16 -0
  73. package/dist/render/shaders/generated/flat.wgsl.js +54 -38
  74. package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +11 -6
  75. package/dist/render/shaders/generated/ssrTrace.wgsl.js +11 -6
  76. package/dist/render/shaders/generated/water.wgsl.d.ts +23 -16
  77. package/dist/render/shaders/generated/water.wgsl.js +23 -16
  78. package/dist/render/shaders/gi/probeBake.wgsl.js +9 -5
  79. package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
  80. package/dist/render/shaders/recon/motion.wgsl.js +13 -2
  81. package/dist/render/shaders/ssrTrace.js +20 -1
  82. package/dist/render/shaders/water.d.ts +1 -1
  83. package/dist/render/shaders/water.js +12 -3
  84. package/dist/render/skinScatter.d.ts +3 -1
  85. package/dist/render/skinScatter.js +3 -1
  86. package/dist/render/ssrPass.js +1 -0
  87. package/dist/render/surfaceModel.d.ts +29 -8
  88. package/dist/render/surfaceModel.js +33 -9
  89. package/dist/render/surfaceTexture.d.ts +25 -1
  90. package/dist/render/surfaceTexture.js +27 -5
  91. package/package.json +6 -6
  92. package/src/index.ts +6 -2
  93. package/src/render/anisotropicLobe.ts +29 -0
  94. package/src/render/areaLights.ts +58 -0
  95. package/src/render/backend/api.ts +49 -2
  96. package/src/render/backend/webgl2/renderer.ts +192 -38
  97. package/src/render/backend/webgl2/sceneCaptureTarget.ts +130 -0
  98. package/src/render/backend/webgpu/particlePass.ts +2 -1
  99. package/src/render/backend/webgpu/renderer.ts +194 -19
  100. package/src/render/backend/webgpu/sceneCaptureTarget.ts +63 -0
  101. package/src/render/backend/webgpu/surfaceTexturePass.ts +44 -14
  102. package/src/render/clusteredLights.ts +41 -8
  103. package/src/render/driftLight/bake.ts +3 -1
  104. package/src/render/driftLight/falloff.ts +13 -2
  105. package/src/render/gi/bounceLights.ts +12 -3
  106. package/src/render/instanceCull.ts +4 -0
  107. package/src/render/instances.ts +26 -6
  108. package/src/render/lightBudget.ts +40 -2
  109. package/src/render/lightmap.ts +64 -23
  110. package/src/render/particlePool.ts +23 -0
  111. package/src/render/pointLightSelection.ts +20 -1
  112. package/src/render/renderQuality.ts +8 -7
  113. package/src/render/rendererHarness.ts +3 -0
  114. package/src/render/rgb9e5.ts +52 -0
  115. package/src/render/sceneCapture.ts +56 -0
  116. package/src/render/screenSpaceReflection.ts +33 -1
  117. package/src/render/shaders/bolt.ts +7 -1
  118. package/src/render/shaders/depth.ts +11 -0
  119. package/src/render/shaders/flat/anisotropic.ts +37 -3
  120. package/src/render/shaders/flat/areaLight.ts +46 -0
  121. package/src/render/shaders/flat/glassTint.ts +9 -2
  122. package/src/render/shaders/flat/index.ts +21 -2
  123. package/src/render/shaders/flat/lobes.ts +50 -43
  124. package/src/render/shaders/flat/main.ts +57 -22
  125. package/src/render/shaders/flat/models.ts +100 -16
  126. package/src/render/shaders/flat/preamble.ts +10 -3
  127. package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
  128. package/src/render/shaders/generated/depth.wgsl.ts +4 -4
  129. package/src/render/shaders/generated/flat.wgsl.ts +54 -38
  130. package/src/render/shaders/generated/ssrTrace.wgsl.ts +11 -6
  131. package/src/render/shaders/generated/water.wgsl.ts +23 -16
  132. package/src/render/shaders/gi/probeBake.wgsl.ts +9 -5
  133. package/src/render/shaders/recon/motion.wgsl.ts +13 -2
  134. package/src/render/shaders/ssrTrace.ts +20 -1
  135. package/src/render/shaders/water.ts +12 -3
  136. package/src/render/skinScatter.ts +3 -1
  137. package/src/render/ssrPass.ts +1 -0
  138. package/src/render/surfaceModel.ts +47 -10
  139. package/src/render/surfaceTexture.ts +69 -9
@@ -31,6 +31,7 @@ export function noLitSwitches() {
31
31
  LIGHT_FIXTURES: false,
32
32
  SURFACE_EFFECTS: false,
33
33
  DRIFT_LIGHT: false,
34
+ PHYSICAL_SPECULAR: false,
34
35
  };
35
36
  }
36
37
  /**
@@ -44,7 +45,8 @@ export function noLitSwitches() {
44
45
  * first uses them — a measured profile or a cookie, a material with an effects table, a DriftLight
45
46
  * volume — and then on for good; see `PipelineCache.enable` and the WebGL2 renderer's rebuild.
46
47
  * Measured on RADV against the lit shader with glass already out: 6,852 instructions and 120
47
- * registers, 4,641 and 96 with all four out.
48
+ * registers, 4,641 and 96 with all four out. `PHYSICAL_SPECULAR` is a sixth, declared with the
49
+ * models so that theirs keep their ids (`modelsGlsl`).
48
50
  */
49
51
  export function litSwitchesGlsl(switches) {
50
52
  return /* glsl */ `
@@ -104,6 +104,11 @@ export interface FlatShaderOptions {
104
104
  readonly surfaceEffects?: boolean;
105
105
  /** Whether it reads a DriftLight volume. True when absent. See `litSwitchesGlsl`. */
106
106
  readonly driftLight?: boolean;
107
+ /**
108
+ * Whether it carries GGX's own highlight for a material that asks (`physicalSpecular`). True
109
+ * when absent. See `modelsGlsl`.
110
+ */
111
+ readonly physicalSpecular?: boolean;
107
112
  /**
108
113
  * How many point lights this build declares room for. `MAX_POINT_LIGHTS` when absent.
109
114
  *
@@ -14,7 +14,7 @@ import { CLOTH_BINDING_GLSL } from '../clothBinding.js';
14
14
  import { SKINNING_GLSL } from '../skinning.js';
15
15
  import { SURFACE_GLSL } from './surface.js';
16
16
  import { MAIN_GLSL } from './main.js';
17
- import { MODELS_GLSL } from './models.js';
17
+ import { modelsGlsl } from './models.js';
18
18
  import { AREA_LIGHT_GLSL } from './areaLight.js';
19
19
  import { NORMAL_MAP_GLSL } from './normalMap.js';
20
20
  import { DRIFT_LIGHT_GLSL } from './driftLight.js';
@@ -244,6 +244,15 @@ void main() {
244
244
  #endif
245
245
  #if INSTANCED
246
246
  mat4 model = mat4(aInstanceModel0, aInstanceModel1, aInstanceModel2, aInstanceModel3);
247
+ /*
248
+ * **The bottom row is the instance's texture cell** (\`MeshInstances.uvRegions\`), which an
249
+ * affine placement leaves free: read, and rebuilt as the \`[0, 0, 0, 1]\` it stands for.
250
+ */
251
+ vec4 instanceCell = vec4(model[0].w, model[1].w, model[2].w, model[3].w);
252
+ model[0].w = 0.0;
253
+ model[1].w = 0.0;
254
+ model[2].w = 0.0;
255
+ model[3].w = 1.0;
247
256
  vec3 tint = aInstanceTint.rgb;
248
257
  if (LIGHTMAP_REGIONS) tint = vec3(1.0);
249
258
  #else
@@ -292,7 +301,12 @@ void main() {
292
301
  vColor = aColor * tint;
293
302
  vEmissive = aEmissive;
294
303
  vSpecular = aSpecular;
304
+ #if INSTANCED
305
+ /* The instance's cell first, then the material's scale and offset. */
306
+ vUv = vec3((aUv.xy * instanceCell.xy + instanceCell.zw) * uUvScale + uUvOffset, aUv.z);
307
+ #else
295
308
  vUv = vec3(aUv.xy * uUvScale + uUvOffset, aUv.z);
309
+ #endif
296
310
  vEmissiveColor = aEmissiveColor;
297
311
  vRoughness = aRoughness;
298
312
  vGrain = aGrain;
@@ -456,7 +470,7 @@ export function flatFrag(options) {
456
470
  DRIFT_LIGHT_GLSL,
457
471
  SURFACE_EFFECTS_GLSL,
458
472
  /* Depth zero and after the tangent frame and the lobes it calls; see models.ts. */
459
- MODELS_GLSL,
473
+ modelsGlsl(options.physicalSpecular ?? true),
460
474
  /* After the models, whose answer to a rectangle it asks for. See areaLight.ts. */
461
475
  AREA_LIGHT_GLSL,
462
476
  MAIN_GLSL,
@@ -25,4 +25,10 @@ export declare const EMISSIVE_SHADOW_SHARE = 0.55;
25
25
  * deliberately not this.
26
26
  */
27
27
  export declare const MIN_LOBE_ALPHA = 0.01;
28
+ /**
29
+ * Karis's fit to the split-sum environment BRDF, as GLSL: the lit stage's, and the screen-space
30
+ * reflection's when a surface asks for its Fresnel (`ReflectiveSurface.fresnel`). One text, so the
31
+ * two cannot drift.
32
+ */
33
+ export declare const ENV_BRDF_GLSL = "/**\n * The other half of the split-sum approximation: what fraction of an environment a surface returns.\n *\n * The convolution decides *what* a surface reflects at a given roughness; this decides *how much*.\n * Before it the amount was fresnel times one-minus-roughness, which is a curve somebody chose\n * standing in for an integral.\n *\n * Karis's analytic fit to the environment BRDF, so there is **no lookup texture and no texture\n * unit**: a few multiply-adds against roughness and the view angle. x scales the surface's own\n * reflectance at normal incidence and y is the additive grazing term, so a smooth dielectric at\n * f0 0.04 returns about 0.046 head-on and approaches 1 at the edge, which is what a dielectric\n * does. At roughness 1 it returns about 0.016 rather than the zero one-minus-roughness gave, which\n * is the substantive difference: a fully rough dielectric does reflect its surroundings.\n *\n * **It replaces the Fresnel factor as well as the thinning**, because the fit already contains the\n * angular dependence; multiplying by a separate Fresnel term would apply it twice.\n *\n * **How much this is worth was measured, and it is worth less than it looks on a dark room.**\n * On demo/dev/ibl.html?ladder=1 the whole ladder moved by at most 0.2 of 255 when the old term was\n * replaced. That is not the term failing: at high roughness the surface reads the coarsest levels\n * of the chain, and in a room of five dark walls and one bright one those levels are dark, so a\n * weight three times larger against a near-zero radiance is still near zero. It is worth much more\n * against a bright environment, which is what a loaded sky is and what no captured room here is.\n *\n * **A warning about reading that page, paid for once.** The ladder falls about five-fold from\n * mirror to rough, and that reads as energy being lost. It is not: a mirror concentrates the one\n * bright wall into a sharp image and a rough surface averages it against five dark ones, so the\n * falloff is the room's own content. The normalised falloff also happens to track one-minus-\n * roughness closely, which made the old term look like the cause \u2014 and removing that term entirely\n * changed nothing, which is what settled it. Perturb before believing a match.\n *\n * **What it costs** is a fit rather than the integral: the published error is around one per cent\n * of the tabulated term, far below what an eight-bit frame can show. **What would make it wrong**\n * is a material model this shader does not have \u2014 a clearcoat or a sheen lobe carries its own BRDF\n * and its own integral, and this fit is Trowbridge-Reitz with Smith masking and nothing else.\n */\nvec2 envBrdfApprox(float ndv, float roughness) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min(r.x * r.x, exp2(-9.28 * ndv)) * r.x + r.y;\n return vec2(-1.04, 1.04) * a004 + r.zw;\n}";
28
34
  export declare const LOBES_GLSL: string;
@@ -27,6 +27,54 @@ export const EMISSIVE_SHADOW_SHARE = 0.55;
27
27
  * deliberately not this.
28
28
  */
29
29
  export const MIN_LOBE_ALPHA = 0.01;
30
+ /**
31
+ * Karis's fit to the split-sum environment BRDF, as GLSL: the lit stage's, and the screen-space
32
+ * reflection's when a surface asks for its Fresnel (`ReflectiveSurface.fresnel`). One text, so the
33
+ * two cannot drift.
34
+ */
35
+ export const ENV_BRDF_GLSL = `/**
36
+ * The other half of the split-sum approximation: what fraction of an environment a surface returns.
37
+ *
38
+ * The convolution decides *what* a surface reflects at a given roughness; this decides *how much*.
39
+ * Before it the amount was fresnel times one-minus-roughness, which is a curve somebody chose
40
+ * standing in for an integral.
41
+ *
42
+ * Karis's analytic fit to the environment BRDF, so there is **no lookup texture and no texture
43
+ * unit**: a few multiply-adds against roughness and the view angle. x scales the surface's own
44
+ * reflectance at normal incidence and y is the additive grazing term, so a smooth dielectric at
45
+ * f0 0.04 returns about 0.046 head-on and approaches 1 at the edge, which is what a dielectric
46
+ * does. At roughness 1 it returns about 0.016 rather than the zero one-minus-roughness gave, which
47
+ * is the substantive difference: a fully rough dielectric does reflect its surroundings.
48
+ *
49
+ * **It replaces the Fresnel factor as well as the thinning**, because the fit already contains the
50
+ * angular dependence; multiplying by a separate Fresnel term would apply it twice.
51
+ *
52
+ * **How much this is worth was measured, and it is worth less than it looks on a dark room.**
53
+ * On demo/dev/ibl.html?ladder=1 the whole ladder moved by at most 0.2 of 255 when the old term was
54
+ * replaced. That is not the term failing: at high roughness the surface reads the coarsest levels
55
+ * of the chain, and in a room of five dark walls and one bright one those levels are dark, so a
56
+ * weight three times larger against a near-zero radiance is still near zero. It is worth much more
57
+ * against a bright environment, which is what a loaded sky is and what no captured room here is.
58
+ *
59
+ * **A warning about reading that page, paid for once.** The ladder falls about five-fold from
60
+ * mirror to rough, and that reads as energy being lost. It is not: a mirror concentrates the one
61
+ * bright wall into a sharp image and a rough surface averages it against five dark ones, so the
62
+ * falloff is the room's own content. The normalised falloff also happens to track one-minus-
63
+ * roughness closely, which made the old term look like the cause — and removing that term entirely
64
+ * changed nothing, which is what settled it. Perturb before believing a match.
65
+ *
66
+ * **What it costs** is a fit rather than the integral: the published error is around one per cent
67
+ * of the tabulated term, far below what an eight-bit frame can show. **What would make it wrong**
68
+ * is a material model this shader does not have — a clearcoat or a sheen lobe carries its own BRDF
69
+ * and its own integral, and this fit is Trowbridge-Reitz with Smith masking and nothing else.
70
+ */
71
+ vec2 envBrdfApprox(float ndv, float roughness) {
72
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
73
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
74
+ vec4 r = roughness * c0 + c1;
75
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndv)) * r.x + r.y;
76
+ return vec2(-1.04, 1.04) * a004 + r.zw;
77
+ }`;
30
78
  export const LOBES_GLSL = `float shadowReach(float distance, float maxDistance) {
31
79
  return 1.0 - smoothstep(
32
80
  maxDistance * ${POINT_SHADOW_FADE_START.toFixed(2)},
@@ -153,49 +201,7 @@ float sphereLobe(float ndh, float roughness, float sourceRadius, float dist) {
153
201
  return energy * (w2 * w2) / max(d * d, 1e-8);
154
202
  }
155
203
 
156
- /**
157
- * The other half of the split-sum approximation: what fraction of an environment a surface returns.
158
- *
159
- * The convolution decides *what* a surface reflects at a given roughness; this decides *how much*.
160
- * Before it the amount was fresnel times one-minus-roughness, which is a curve somebody chose
161
- * standing in for an integral.
162
- *
163
- * Karis's analytic fit to the environment BRDF, so there is **no lookup texture and no texture
164
- * unit**: a few multiply-adds against roughness and the view angle. x scales the surface's own
165
- * reflectance at normal incidence and y is the additive grazing term, so a smooth dielectric at
166
- * f0 0.04 returns about 0.046 head-on and approaches 1 at the edge, which is what a dielectric
167
- * does. At roughness 1 it returns about 0.016 rather than the zero one-minus-roughness gave, which
168
- * is the substantive difference: a fully rough dielectric does reflect its surroundings.
169
- *
170
- * **It replaces the Fresnel factor as well as the thinning**, because the fit already contains the
171
- * angular dependence; multiplying by a separate Fresnel term would apply it twice.
172
- *
173
- * **How much this is worth was measured, and it is worth less than it looks on a dark room.**
174
- * On demo/dev/ibl.html?ladder=1 the whole ladder moved by at most 0.2 of 255 when the old term was
175
- * replaced. That is not the term failing: at high roughness the surface reads the coarsest levels
176
- * of the chain, and in a room of five dark walls and one bright one those levels are dark, so a
177
- * weight three times larger against a near-zero radiance is still near zero. It is worth much more
178
- * against a bright environment, which is what a loaded sky is and what no captured room here is.
179
- *
180
- * **A warning about reading that page, paid for once.** The ladder falls about five-fold from
181
- * mirror to rough, and that reads as energy being lost. It is not: a mirror concentrates the one
182
- * bright wall into a sharp image and a rough surface averages it against five dark ones, so the
183
- * falloff is the room's own content. The normalised falloff also happens to track one-minus-
184
- * roughness closely, which made the old term look like the cause — and removing that term entirely
185
- * changed nothing, which is what settled it. Perturb before believing a match.
186
- *
187
- * **What it costs** is a fit rather than the integral: the published error is around one per cent
188
- * of the tabulated term, far below what an eight-bit frame can show. **What would make it wrong**
189
- * is a material model this shader does not have — a clearcoat or a sheen lobe carries its own BRDF
190
- * and its own integral, and this fit is Trowbridge-Reitz with Smith masking and nothing else.
191
- */
192
- vec2 envBrdfApprox(float ndv, float roughness) {
193
- const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
194
- const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
195
- vec4 r = roughness * c0 + c1;
196
- float a004 = min(r.x * r.x, exp2(-9.28 * ndv)) * r.x + r.y;
197
- return vec2(-1.04, 1.04) * a004 + r.zw;
198
- }
204
+ ${ENV_BRDF_GLSL}
199
205
 
200
206
  /**
201
207
  * How much of a prefiltered environment a surface returns, with the light that bounces more than