@driftengine/core 4.11.0 → 4.12.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 (77) hide show
  1. package/CHANGELOG.json +72 -0
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +1 -1
  5. package/dist/render/ambientOcclusionPass.d.ts +3 -2
  6. package/dist/render/ambientOcclusionPass.js +4 -2
  7. package/dist/render/backend/api.d.ts +21 -1
  8. package/dist/render/backend/webgl2/renderer.d.ts +61 -5
  9. package/dist/render/backend/webgl2/renderer.js +153 -21
  10. package/dist/render/backend/webgpu/renderer.d.ts +54 -1
  11. package/dist/render/backend/webgpu/renderer.js +246 -89
  12. package/dist/render/instances.d.ts +13 -1
  13. package/dist/render/instances.js +10 -0
  14. package/dist/render/occlusionFade.d.ts +21 -0
  15. package/dist/render/occlusionFade.js +27 -0
  16. package/dist/render/sceneTarget.d.ts +2 -0
  17. package/dist/render/sceneTarget.js +1 -1
  18. package/dist/render/shaders/ambientOcclusion.js +12 -1
  19. package/dist/render/shaders/flat/areaLight.d.ts +1 -1
  20. package/dist/render/shaders/flat/areaLight.js +1 -1
  21. package/dist/render/shaders/flat/glassTint.d.ts +1 -1
  22. package/dist/render/shaders/flat/glassTint.js +1 -0
  23. package/dist/render/shaders/flat/index.d.ts +5 -0
  24. package/dist/render/shaders/flat/index.js +10 -3
  25. package/dist/render/shaders/flat/layerLooks.d.ts +16 -0
  26. package/dist/render/shaders/flat/layerLooks.js +116 -0
  27. package/dist/render/shaders/flat/layered.d.ts +19 -9
  28. package/dist/render/shaders/flat/layered.js +169 -37
  29. package/dist/render/shaders/flat/main.d.ts +1 -1
  30. package/dist/render/shaders/flat/main.js +17 -5
  31. package/dist/render/shaders/flat/models.js +1 -1
  32. package/dist/render/shaders/flat/normalMap.d.ts +1 -1
  33. package/dist/render/shaders/flat/normalMap.js +11 -2
  34. package/dist/render/shaders/flat/preamble.js +6 -0
  35. package/dist/render/shaders/generated/ambientOcclusion.wgsl.d.ts +6 -1
  36. package/dist/render/shaders/generated/ambientOcclusion.wgsl.js +6 -1
  37. package/dist/render/shaders/generated/flat.wgsl.d.ts +176 -48
  38. package/dist/render/shaders/generated/flat.wgsl.js +215 -87
  39. package/dist/render/surfaceLayerLooks.d.ts +80 -0
  40. package/dist/render/surfaceLayerLooks.js +83 -0
  41. package/dist/render/surfaceLayers.d.ts +128 -19
  42. package/dist/render/surfaceLayers.js +73 -13
  43. package/dist/render/surfaceTexture.d.ts +13 -4
  44. package/dist/render/transmission.d.ts +21 -0
  45. package/dist/render/transmission.js +21 -0
  46. package/dist/ui/splash.d.ts +42 -2
  47. package/dist/ui/splash.js +78 -13
  48. package/package.json +6 -6
  49. package/scripts/browser.d.mts +5 -0
  50. package/scripts/browser.mjs +68 -14
  51. package/scripts/look.d.mts +81 -0
  52. package/scripts/look.mjs +380 -0
  53. package/src/index.ts +4 -0
  54. package/src/render/ambientOcclusionPass.ts +4 -1
  55. package/src/render/backend/api.ts +31 -0
  56. package/src/render/backend/webgl2/renderer.ts +170 -22
  57. package/src/render/backend/webgpu/renderer.ts +379 -139
  58. package/src/render/instances.ts +18 -1
  59. package/src/render/occlusionFade.ts +29 -0
  60. package/src/render/sceneTarget.ts +3 -0
  61. package/src/render/shaders/ambientOcclusion.ts +12 -1
  62. package/src/render/shaders/flat/areaLight.ts +1 -1
  63. package/src/render/shaders/flat/glassTint.ts +3 -1
  64. package/src/render/shaders/flat/index.ts +15 -3
  65. package/src/render/shaders/flat/layerLooks.ts +116 -0
  66. package/src/render/shaders/flat/layered.ts +170 -37
  67. package/src/render/shaders/flat/main.ts +17 -5
  68. package/src/render/shaders/flat/models.ts +1 -1
  69. package/src/render/shaders/flat/normalMap.ts +11 -2
  70. package/src/render/shaders/flat/preamble.ts +6 -0
  71. package/src/render/shaders/generated/ambientOcclusion.wgsl.ts +6 -1
  72. package/src/render/shaders/generated/flat.wgsl.ts +215 -87
  73. package/src/render/surfaceLayerLooks.ts +155 -0
  74. package/src/render/surfaceLayers.ts +187 -23
  75. package/src/render/surfaceTexture.ts +13 -4
  76. package/src/render/transmission.ts +27 -0
  77. package/src/ui/splash.ts +83 -14
@@ -106,9 +106,18 @@ import {
106
106
  type SurfaceOverlay,
107
107
  } from '../../surfaceOverlay.ts';
108
108
  import { PROJECTION_FLOATS, packSurfaceProjection, projects } from '../../surfaceProjection.ts';
109
+ import { resolveTransmission } from '../../transmission.ts';
110
+ import { resolveOcclusionFade } from '../../occlusionFade.ts';
109
111
  import { orthographicDepthSpan } from '../../lightMatrix.ts';
110
- import { LAYER_FLOATS, packSurfaceLayers } from '../../surfaceLayers.ts';
112
+ import {
113
+ LAYER_FLOATS,
114
+ layerMaskMap,
115
+ layeredProjection,
116
+ layersFitBeside,
117
+ packSurfaceLayers,
118
+ } from '../../surfaceLayers.ts';
111
119
  import type { SurfaceLayers } from '../../surfaceLayers.ts';
120
+ import { LOOK_FLOATS, asksLayerLooks, packLayerLooks } from '../../surfaceLayerLooks.ts';
112
121
  import type { SurfaceProjection } from '../../surfaceProjection.ts';
113
122
  import { FILM_FRAG, FILM_VERT } from '../../shaders/film.ts';
114
123
  import { SceneTarget } from '../../sceneTarget.ts';
@@ -282,7 +291,7 @@ import type { BufferSize } from '../../drawingBuffer.ts';
282
291
  import { Mesh, createMeshIncremental } from '../../mesh.ts';
283
292
  import type { IncrementalMesh } from '../../mesh.ts';
284
293
  import type { MeshData } from '../../mesh.ts';
285
- import type { MeshOptions } from '../api.ts';
294
+ import type { MeshOptions, PrepareOptions } from '../api.ts';
286
295
  import { SurfaceTexture } from '../../surfaceTexture.ts';
287
296
  import { sceneCaptureTexels } from '../../sceneCapture.ts';
288
297
  import { GlSceneCaptureTarget } from './sceneCaptureTarget.ts';
@@ -1599,6 +1608,8 @@ export class WebGL2Renderer implements RendererApi {
1599
1608
  private readonly aoProjScale = new Float32Array(2);
1600
1609
  /** Where this frame's jitter put the occlusion, in the composite's uv. See `uAoOffset`. */
1601
1610
  private readonly aoOffset = new Float32Array(2);
1611
+ /** Where occlusion fades out with distance, `uFade`: none until a caller sets one. */
1612
+ private readonly aoFade = new Float32Array([-1, 0]);
1602
1613
  /**
1603
1614
  * Whether this frame has already been resolved to the canvas.
1604
1615
  *
@@ -1766,14 +1777,23 @@ export class WebGL2Renderer implements RendererApi {
1766
1777
  private warnedProjectionRoom = false;
1767
1778
  /** `uWorldUv`, the current material's projection packed. See `surfaceProjection.ts`. */
1768
1779
  private readonly projection = new Float32Array(PROJECTION_FLOATS);
1769
- /** The current material's `diffuseTransmission`, `uGlassTint.w`, 0 to 1. */
1770
- private diffuseTransmission = 0;
1780
+ /**
1781
+ * `uGlassTint` as the current material leaves it: its light from behind and that light's colour,
1782
+ * which a pane overwrites for its own draw and `unbindSeeThrough` puts back. See `transmission.ts`.
1783
+ */
1784
+ private readonly transmission = new Float32Array([-1, -1, -1, 0]);
1771
1785
  /** `uLayers`, the current material's layers packed. See `surfaceLayers.ts`. */
1772
1786
  private readonly layerFloats = new Float32Array(LAYER_FLOATS);
1787
+ /** `uLayerLooks`, the current material's layer picks and looks packed. See `surfaceLayerLooks.ts`. */
1788
+ private readonly lookFloats = new Float32Array(LOOK_FLOATS);
1773
1789
  /** Whether the lit stage has room for layers' two vectors, and which refusals were said. */
1774
1790
  private layersRoom: boolean | null = null;
1775
1791
  private warnedLayersRoom = false;
1792
+ /** Whether it has room for the layers' looks beside them, and whether the refusal was said. */
1793
+ private looksRoom: boolean | null = null;
1794
+ private warnedLooksRoom = false;
1776
1795
  private warnedLayersModelMap = false;
1796
+ private warnedLayersTriplanar = false;
1777
1797
  private warnedOverlayRoom = false;
1778
1798
  private warnedOverlayBlocks = false;
1779
1799
  /** Whether a probe is being baked, so the passes that would recurse into one can tell. */
@@ -3929,6 +3949,58 @@ export class WebGL2Renderer implements RendererApi {
3929
3949
  * `uScale`/`vScale` are repeats across the mesh's own UV range: geometry authored in
3930
3950
  * metres is textured at whatever density the material wants without rebuilding it.
3931
3951
  */
3952
+ /**
3953
+ * Compile, off the frame, every program a draw of `mesh` in `material` takes that making the mesh
3954
+ * did not, so the first frame that draws it waits on none: the program of the material's shading
3955
+ * model for each vertex variant the mesh can be drawn with (its rig, with a palette; its targets,
3956
+ * with weights and without), a skin's halves under the screen-space blur, and the lit switches
3957
+ * the material turns on. `ready()` resolves once they have.
3958
+ *
3959
+ * **For `pipelineCompile: 'skip'` above all**, where a draw whose program is new is left out until
3960
+ * it lands: a figure brought on screen whole rather than without its face and hair for the frames
3961
+ * those take. Where draws wait, the programs compile here, at the call, rather than in a frame.
3962
+ * Two-sided and cut-out surfaces are draw state on this backend and need nothing; on WebGPU they
3963
+ * are pipelines of their own, prepared the same way.
3964
+ *
3965
+ * **Call it between frames**: it sets `material` to read it and leaves no material set after, as
3966
+ * `setMaterial(null)` does. `options` is the other backend's; blended draws share a program here.
3967
+ */
3968
+ prepareMesh(mesh: Mesh, material: SurfaceMaterial | null, _options: PrepareOptions = {}): void {
3969
+ if (this.contextLost) return;
3970
+ this.setMaterial(material);
3971
+ const kind = material?.model?.kind ?? null;
3972
+ if (kind !== null) {
3973
+ const eight = mesh.isSkinnedEight;
3974
+ const morphs = mesh.morph !== null;
3975
+ const plain = mesh.isSkinned ? (eight ? 'skinned8' : 'skinned') : 'plain';
3976
+ const morphed = mesh.isSkinned ? (eight ? 'both8' : 'both') : 'morphed';
3977
+ for (const variant of morphs ? [plain, morphed] : [plain]) {
3978
+ this.modelProgram(variant, kind);
3979
+ /* A skin under the screen-space blur draws three halves, each a program of its own. */
3980
+ if (kind === 'skin' && this.skinScatter !== null && this.sceneTarget !== null) {
3981
+ for (const half of SPLIT_SKIN_HALVES) this.modelProgram(variant, kind, half);
3982
+ }
3983
+ }
3984
+ }
3985
+ this.setMaterial(null);
3986
+ }
3987
+
3988
+ /** `prepareMesh` for an instanced batch: its own programs, and its model's for its variant. */
3989
+ prepareInstanced(
3990
+ batch: InstancedBatch,
3991
+ material: SurfaceMaterial | null,
3992
+ _options: PrepareOptions = {},
3993
+ ): void {
3994
+ if (this.contextLost) return;
3995
+ this.setMaterial(material);
3996
+ const animated = batch.animation !== null;
3997
+ this.ensureInstancedProgram();
3998
+ if (animated) this.ensureAnimatedProgram();
3999
+ const kind = material?.model?.kind ?? null;
4000
+ if (kind !== null) this.modelProgram(animated ? 'animated' : 'instanced', kind);
4001
+ this.setMaterial(null);
4002
+ }
4003
+
3932
4004
  /**
3933
4005
  * Choose the joint palette the following `drawMesh` calls skin by, or null for none.
3934
4006
  *
@@ -4323,15 +4395,18 @@ export class WebGL2Renderer implements RendererApi {
4323
4395
  * and read neither — one decision for every program, as `setMaterial` says.
4324
4396
  */
4325
4397
  const modelMap = material?.modelMap ?? null;
4326
- /* A layered material's mask goes where a model's map would: see `SurfaceMaterial.layers`. */
4398
+ /* A layered material's mask, where it is a map, goes where a model's would: surfaceLayers.ts. */
4327
4399
  const layers = this.layersOf(material);
4328
- const boundMap = modelMap ?? layers?.mask ?? null;
4400
+ const boundMap = modelMap ?? layerMaskMap(layers);
4329
4401
  gl.activeTexture(gl.TEXTURE0 + MODEL_MAP_TEXTURE_UNIT);
4330
4402
  gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.emptyTexture2DArray);
4331
4403
  if (boundMap !== null) boundMap.bind(gl, MODEL_MAP_TEXTURE_UNIT);
4332
4404
  packSurfaceLayers(layers, this.layerFloats);
4333
4405
  if (layers !== null) this.askLit('LAYERED');
4334
4406
  gl.uniform4fv(u['uLayers'] ?? null, this.layerFloats);
4407
+ packLayerLooks(layers, this.lookFloats);
4408
+ if (this.looksFit(layers)) this.askLit('LAYER_LOOKS');
4409
+ gl.uniform4fv(u['uLayerLooks'] ?? null, this.lookFloats);
4335
4410
  gl.uniform1i(u['uModelMap'] ?? null, MODEL_MAP_TEXTURE_UNIT);
4336
4411
  packModel(
4337
4412
  material?.model ?? null,
@@ -4345,11 +4420,12 @@ export class WebGL2Renderer implements RendererApi {
4345
4420
  /* The draw's overlay, which a program born mid-pass must wear too: see `setSurfaceOverlay`. */
4346
4421
  gl.uniform4fv(u['uOverlay'] ?? null, this.overlayFloats);
4347
4422
  gl.uniform4fv(u['uWorldUv'] ?? null, this.projection);
4348
- /* How much light from behind the surface lets through, in the glass tint's spare lane. */
4349
- this.diffuseTransmission = Math.min(Math.max(material?.diffuseTransmission ?? 0, 0), 1) || 0;
4350
- gl.uniform4f(u['uGlassTint'] ?? null, 1, 1, 1, this.diffuseTransmission);
4423
+ /* How much light from behind the surface lets through, and its colour: transmission.ts. */
4424
+ resolveTransmission(material, this.transmission);
4425
+ this.writeTransmission(u);
4351
4426
  /* Maps placed by the world, where the material asks and the lit stage has room: worldUv.ts. */
4352
- const projection = material?.projection ?? null;
4427
+ const projection = layeredProjection(material?.projection, layers);
4428
+ if (projection !== (material?.projection ?? null)) this.warnLayersTriplanar();
4353
4429
  packSurfaceProjection(this.projectionFits(projection) ? projection : null, this.projection);
4354
4430
  if ((this.projection[0] as number) > 0) this.askLit('WORLD_UVS');
4355
4431
  gl.uniform4fv(u['uWorldUv'] ?? null, this.projection);
@@ -4598,14 +4674,15 @@ export class WebGL2Renderer implements RendererApi {
4598
4674
  * no room for their two vectors each leave one layer, the last two said once each.
4599
4675
  */
4600
4676
  private layersOf(material: SurfaceMaterial | null): SurfaceLayers<SurfaceTexture> | null {
4601
- const layers = material?.layers ?? null;
4677
+ const layers = (material?.layers ?? null) as SurfaceLayers<SurfaceTexture> | null;
4602
4678
  if (layers === null || layers.repeats.length === 0) return null;
4603
- if ((material?.modelMap ?? null) !== null) {
4679
+ if (!layersFitBeside(layers, material?.modelMap)) {
4604
4680
  if (!this.warnedLayersModelMap) {
4605
4681
  this.warnedLayersModelMap = true;
4606
4682
  console.warn(
4607
- "Renderer: a material's layers are drawn as one: its mask is read where a model's map " +
4608
- 'goes, and this material carries a `modelMap` too.',
4683
+ "Renderer: a material's layers are drawn as one: its mask is a map, read where a " +
4684
+ "model's map goes, and this material carries a `modelMap` too. A mask in the ORM " +
4685
+ "array (`mask: 'orm'`) or the vertex colour (`mask: 'vertex'`) leaves the slot free.",
4609
4686
  );
4610
4687
  }
4611
4688
  return null;
@@ -4615,7 +4692,7 @@ export class WebGL2Renderer implements RendererApi {
4615
4692
  if (!this.warnedLayersRoom) {
4616
4693
  this.warnedLayersRoom = true;
4617
4694
  console.warn(
4618
- "Renderer: a material's layers are refused on this device. They take two fragment uniform " +
4695
+ "Renderer: a material's layers are refused on this device. They take four fragment uniform " +
4619
4696
  'vectors the lit shader does not have; the material is drawn as its base layer. A lower ' +
4620
4697
  '`maxLights` makes the room, or WebGPU has it.',
4621
4698
  );
@@ -4623,9 +4700,45 @@ export class WebGL2Renderer implements RendererApi {
4623
4700
  return null;
4624
4701
  }
4625
4702
 
4626
- /** Whether the lit shader with `feature` compiled in fits this GPU's fragment uniform vectors. */
4627
- private switchFits(feature: LitSwitch): boolean {
4703
+ /**
4704
+ * Whether a layered material's picks and looks are drawn: asked for, and room for their fifteen
4705
+ * vectors beside the layers' four. Refused, the layers are drawn reading layer `i` of their arrays
4706
+ * as they are, said once — which on a material sharing its arrays reads the wrong textures, so
4707
+ * the sentence names the way out.
4708
+ */
4709
+ private looksFit(layers: SurfaceLayers<SurfaceTexture> | null): boolean {
4710
+ if (!asksLayerLooks(layers)) return false;
4711
+ this.looksRoom ??= this.switchFits('LAYER_LOOKS', 'LAYERED');
4712
+ if (this.looksRoom) return true;
4713
+ if (!this.warnedLooksRoom) {
4714
+ this.warnedLooksRoom = true;
4715
+ console.warn(
4716
+ "Renderer: a layered material's picks and looks are refused on this device. They take " +
4717
+ 'fifteen fragment uniform vectors the lit shader does not have, so its layers read layer ' +
4718
+ 'i of its arrays, untinted, at one repeat each. A lower `maxLights` makes the room, or ' +
4719
+ 'WebGPU has it.',
4720
+ );
4721
+ }
4722
+ return false;
4723
+ }
4724
+
4725
+ /** Says once that a layered material's triplanar projection is laid on the horizontal plane. */
4726
+ private warnLayersTriplanar(): void {
4727
+ if (this.warnedLayersTriplanar) return;
4728
+ this.warnedLayersTriplanar = true;
4729
+ console.warn(
4730
+ "Renderer: a layered material's triplanar projection is laid on the horizontal plane: every " +
4731
+ "layer's maps on three planes would be three times the reads. See `SurfaceMaterial.layers`.",
4732
+ );
4733
+ }
4734
+
4735
+ /**
4736
+ * Whether the lit shader with `feature` compiled in, and `beside` with it where a switch means
4737
+ * nothing alone, fits this GPU's fragment uniform vectors.
4738
+ */
4739
+ private switchFits(feature: LitSwitch, beside?: LitSwitch): boolean {
4628
4740
  const asIf: Partial<Record<LitSwitch, boolean>> = { [feature]: true };
4741
+ if (beside !== undefined) asIf[beside] = true;
4629
4742
  return (
4630
4743
  countUniformVectors(this.flatFragAt(this.lightBudget, asIf)) <= this.fragmentVectorLimit()
4631
4744
  );
@@ -4786,7 +4899,8 @@ export class WebGL2Renderer implements RendererApi {
4786
4899
  *
4787
4900
  * What it gives up: a fade reads as grain while it lasts, which a temporal resolve smooths and a
4788
4901
  * plain frame does not; a blended draw that asks spends its opacity here and blends none of it;
4789
- * and a lightmapped batch carries regions where the opacities would be, so it has none to fade.
4902
+ * and a lightmapped batch's opacities ride its page regions, so they fade in steps of a
4903
+ * sixty-fourth, which is the pattern's own resolution (`MeshInstances.lightmapRegions`).
4790
4904
  */
4791
4905
  setDitherOpacity(on: boolean): void {
4792
4906
  if (this.contextLost) return;
@@ -5281,15 +5395,23 @@ export class WebGL2Renderer implements RendererApi {
5281
5395
  glass.tint[0] ?? 1,
5282
5396
  glass.tint[1] ?? 1,
5283
5397
  glass.tint[2] ?? 1,
5284
- this.diffuseTransmission,
5398
+ this.transmission[3] as number,
5285
5399
  );
5286
5400
  return true;
5287
5401
  }
5288
5402
 
5403
+ /** `uGlassTint` as the current material leaves it. See `transmission`. */
5404
+ private writeTransmission(u: Record<string, WebGLUniformLocation>): void {
5405
+ const t = this.transmission;
5406
+ this.gl.uniform4f(u['uGlassTint'] ?? null, t[0] ?? -1, t[1] ?? -1, t[2] ?? -1, t[3] ?? 0);
5407
+ }
5408
+
5289
5409
  /** Put back what `bindSeeThrough` bound: the binding outlives its frame (the 2026-08-27 rule). */
5290
5410
  private unbindSeeThrough(u: Record<string, WebGLUniformLocation>): void {
5291
5411
  const { gl } = this;
5292
5412
  gl.uniform4f(u['uSeeThrough'] ?? null, 0, 0, 0, 0);
5413
+ /* The material's light through, over the pane's tint: transmission.ts. */
5414
+ this.writeTransmission(u);
5293
5415
  gl.activeTexture(gl.TEXTURE0 + REFRACT_SCENE_TEXTURE_UNIT);
5294
5416
  /* The overlay's atlas, where one is held: it shares the unit. See `setSurfaceOverlay`. */
5295
5417
  gl.bindTexture(gl.TEXTURE_2D, this.overlayTexture ?? this.emptyTexture2D);
@@ -6873,6 +6995,7 @@ export class WebGL2Renderer implements RendererApi {
6873
6995
  worldUvs: asIf.WORLD_UVS ?? this.litOn.WORLD_UVS,
6874
6996
  movingSun: asIf.MOVING_SUN ?? this.litOn.MOVING_SUN,
6875
6997
  layered: asIf.LAYERED ?? this.litOn.LAYERED,
6998
+ layerLooks: asIf.LAYER_LOOKS ?? this.litOn.LAYER_LOOKS,
6876
6999
  maxLights: budget.maxLights,
6877
7000
  maxAreaLights: budget.maxAreaLights,
6878
7001
  });
@@ -7800,6 +7923,20 @@ export class WebGL2Renderer implements RendererApi {
7800
7923
  this.sceneTarget.setLocalExposure(strength);
7801
7924
  }
7802
7925
 
7926
+ /**
7927
+ * Where ambient occlusion fades out with distance: whole up to `distance` metres from the eye and
7928
+ * gone `radius` metres past it, so the far depth buffer's steps — a sky dome kilometres off, a
7929
+ * mountain range — are not shaded in rings, and those pixels skip the occlusion's sampling.
7930
+ *
7931
+ * A distance that is not a finite number at or above zero is no fade, which is the default, and
7932
+ * `Infinity` reads as "never fades"; a radius below zero is a cut at `distance`. Set before
7933
+ * `endFrame` and held until changed, like `setDepthOfField`. Nothing at all when
7934
+ * `ambientOcclusion` is 0. See `occlusionFade.ts` for what it gives up.
7935
+ */
7936
+ setAmbientOcclusionFade(distance: number, radius: number): void {
7937
+ resolveOcclusionFade(distance, radius, this.aoFade);
7938
+ }
7939
+
7803
7940
  /**
7804
7941
  * Where this frame's lens is focused, how deep the sharp zone is, and how much of the ceiling
7805
7942
  * to take.
@@ -8453,6 +8590,7 @@ export class WebGL2Renderer implements RendererApi {
8453
8590
  radius: number;
8454
8591
  projScale: Float32Array;
8455
8592
  invProjection: Float32Array;
8593
+ fade: Float32Array;
8456
8594
  offset: Float32Array;
8457
8595
  }
8458
8596
  | undefined;
@@ -8476,6 +8614,7 @@ export class WebGL2Renderer implements RendererApi {
8476
8614
  radius: this.quality.ambientOcclusionRadius,
8477
8615
  projScale: this.aoProjScale,
8478
8616
  invProjection: this.aoInvProjection as Float32Array,
8617
+ fade: this.aoFade,
8479
8618
  offset: this.aoOffset,
8480
8619
  };
8481
8620
  }
@@ -9010,9 +9149,10 @@ export class WebGL2Renderer implements RendererApi {
9010
9149
  /* Nor a projection: maps follow the mesh's coordinates until a material asks otherwise. */
9011
9150
  this.projection.fill(0);
9012
9151
  /* Nor light through from behind. See `SurfaceMaterial.diffuseTransmission`. */
9013
- this.diffuseTransmission = 0;
9152
+ resolveTransmission(null, this.transmission);
9014
9153
  /* Nor layers: one layer until a material asks for more. */
9015
9154
  this.layerFloats.fill(0);
9155
+ this.lookFloats.fill(0);
9016
9156
  this.overlayMaps = null;
9017
9157
  this.overlayTexture = null;
9018
9158
  /* Nor an ambient of its own: the frame's, until a draw asks. See `setAmbientSH`. */
@@ -9187,12 +9327,20 @@ export class WebGL2Renderer implements RendererApi {
9187
9327
  gl.uniform4fv(u['uOverlay'] ?? null, this.overlayFloats);
9188
9328
  gl.uniform4fv(u['uWorldUv'] ?? null, this.projection);
9189
9329
  gl.uniform4fv(u['uLayers'] ?? null, this.layerFloats);
9330
+ gl.uniform4fv(u['uLayerLooks'] ?? null, this.lookFloats);
9190
9331
  /* Neither refracting nor glass, which is every draw that does not say otherwise. See
9191
9332
  `bindSeeThrough` for the four numbers in the one vector. */
9192
9333
  gl.uniform4f(u['uSeeThrough'] ?? null, 0, 0, 0, 0);
9193
9334
  gl.uniform4f(u['uRefractTint'] ?? null, 1, 1, 1, 1);
9194
- /* White, and no light through from behind: no material at a pass's start. */
9195
- gl.uniform4f(u['uGlassTint'] ?? null, 1, 1, 1, this.diffuseTransmission);
9335
+ /* No light through from behind: no material at a pass's start. See `writeTransmission`. */
9336
+ const through = this.transmission;
9337
+ gl.uniform4f(
9338
+ u['uGlassTint'] ?? null,
9339
+ through[0] ?? -1,
9340
+ through[1] ?? -1,
9341
+ through[2] ?? -1,
9342
+ through[3] ?? 0,
9343
+ );
9196
9344
  gl.uniform3fv(u['uDirectionalDir'] ?? null, env.directionalDir);
9197
9345
  gl.uniform3fv(u['uDirectionalColor'] ?? null, env.directionalColor);
9198
9346
  gl.uniform3fv(u['uAmbient'] ?? null, env.ambient);